=== modified file '.pc/applied-patches'
--- .pc/applied-patches	2010-12-17 10:40:10 +0000
+++ .pc/applied-patches	2011-03-02 20:48:44 +0000
@@ -14,3 +14,5 @@
 security-CVE-2010-3069.patch
 fix-lpbug-393012.patch
 spnego-auth-win7.patch
+security-CVE-2011-0719.patch
+ntlm-auth-lp623342.patch

=== added directory '.pc/security-CVE-2011-0719.patch'
=== added directory '.pc/security-CVE-2011-0719.patch/lib'
=== added directory '.pc/security-CVE-2011-0719.patch/lib/tevent'
=== added file '.pc/security-CVE-2011-0719.patch/lib/tevent/tevent_select.c'
--- .pc/security-CVE-2011-0719.patch/lib/tevent/tevent_select.c	1970-01-01 00:00:00 +0000
+++ .pc/security-CVE-2011-0719.patch/lib/tevent/tevent_select.c	2011-03-02 20:48:44 +0000
@@ -0,0 +1,247 @@
+/* 
+   Unix SMB/CIFS implementation.
+   main select loop and event handling
+   Copyright (C) Andrew Tridgell	2003-2005
+   Copyright (C) Stefan Metzmacher	2005-2009
+
+     ** NOTE! The following LGPL license applies to the tevent
+     ** library. This does NOT imply that all of Samba is released
+     ** under the LGPL
+
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 3 of the License, or (at your option) any later version.
+
+   This library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "replace.h"
+#include "system/filesys.h"
+#include "system/select.h"
+#include "tevent.h"
+#include "tevent_util.h"
+#include "tevent_internal.h"
+
+struct select_event_context {
+	/* a pointer back to the generic event_context */
+	struct tevent_context *ev;
+
+	/* the maximum file descriptor number in fd_events */
+	int maxfd;
+
+	/* information for exiting from the event loop */
+	int exit_code;
+};
+
+/*
+  create a select_event_context structure.
+*/
+static int select_event_context_init(struct tevent_context *ev)
+{
+	struct select_event_context *select_ev;
+
+	select_ev = talloc_zero(ev, struct select_event_context);
+	if (!select_ev) return -1;
+	select_ev->ev = ev;
+
+	ev->additional_data = select_ev;
+	return 0;
+}
+
+/*
+  recalculate the maxfd
+*/
+static void calc_maxfd(struct select_event_context *select_ev)
+{
+	struct tevent_fd *fde;
+
+	select_ev->maxfd = 0;
+	for (fde = select_ev->ev->fd_events; fde; fde = fde->next) {
+		if (fde->fd > select_ev->maxfd) {
+			select_ev->maxfd = fde->fd;
+		}
+	}
+}
+
+
+/* to mark the ev->maxfd invalid
+ * this means we need to recalculate it
+ */
+#define EVENT_INVALID_MAXFD (-1)
+
+/*
+  destroy an fd_event
+*/
+static int select_event_fd_destructor(struct tevent_fd *fde)
+{
+	struct tevent_context *ev = fde->event_ctx;
+	struct select_event_context *select_ev = NULL;
+
+	if (ev) {
+		select_ev = talloc_get_type(ev->additional_data,
+					    struct select_event_context);
+
+		if (select_ev->maxfd == fde->fd) {
+			select_ev->maxfd = EVENT_INVALID_MAXFD;
+		}
+	}
+
+	return tevent_common_fd_destructor(fde);
+}
+
+/*
+  add a fd based event
+  return NULL on failure (memory allocation error)
+*/
+static struct tevent_fd *select_event_add_fd(struct tevent_context *ev, TALLOC_CTX *mem_ctx,
+					     int fd, uint16_t flags,
+					     tevent_fd_handler_t handler,
+					     void *private_data,
+					     const char *handler_name,
+					     const char *location)
+{
+	struct select_event_context *select_ev = talloc_get_type(ev->additional_data,
+							   struct select_event_context);
+	struct tevent_fd *fde;
+
+	fde = tevent_common_add_fd(ev, mem_ctx, fd, flags,
+				   handler, private_data,
+				   handler_name, location);
+	if (!fde) return NULL;
+
+	if (fde->fd > select_ev->maxfd) {
+		select_ev->maxfd = fde->fd;
+	}
+	talloc_set_destructor(fde, select_event_fd_destructor);
+
+	return fde;
+}
+
+/*
+  event loop handling using select()
+*/
+static int select_event_loop_select(struct select_event_context *select_ev, struct timeval *tvalp)
+{
+	fd_set r_fds, w_fds;
+	struct tevent_fd *fde;
+	int selrtn;
+
+	/* we maybe need to recalculate the maxfd */
+	if (select_ev->maxfd == EVENT_INVALID_MAXFD) {
+		calc_maxfd(select_ev);
+	}
+
+	FD_ZERO(&r_fds);
+	FD_ZERO(&w_fds);
+
+	/* setup any fd events */
+	for (fde = select_ev->ev->fd_events; fde; fde = fde->next) {
+		if (fde->flags & TEVENT_FD_READ) {
+			FD_SET(fde->fd, &r_fds);
+		}
+		if (fde->flags & TEVENT_FD_WRITE) {
+			FD_SET(fde->fd, &w_fds);
+		}
+	}
+
+	if (select_ev->ev->signal_events &&
+	    tevent_common_check_signal(select_ev->ev)) {
+		return 0;
+	}
+
+	selrtn = select(select_ev->maxfd+1, &r_fds, &w_fds, NULL, tvalp);
+
+	if (selrtn == -1 && errno == EINTR && 
+	    select_ev->ev->signal_events) {
+		tevent_common_check_signal(select_ev->ev);
+		return 0;
+	}
+
+	if (selrtn == -1 && errno == EBADF) {
+		/* the socket is dead! this should never
+		   happen as the socket should have first been
+		   made readable and that should have removed
+		   the event, so this must be a bug. This is a
+		   fatal error. */
+		tevent_debug(select_ev->ev, TEVENT_DEBUG_FATAL,
+			     "ERROR: EBADF on select_event_loop_once\n");
+		select_ev->exit_code = EBADF;
+		return -1;
+	}
+
+	if (selrtn == 0 && tvalp) {
+		/* we don't care about a possible delay here */
+		tevent_common_loop_timer_delay(select_ev->ev);
+		return 0;
+	}
+
+	if (selrtn > 0) {
+		/* at least one file descriptor is ready - check
+		   which ones and call the handler, being careful to allow
+		   the handler to remove itself when called */
+		for (fde = select_ev->ev->fd_events; fde; fde = fde->next) {
+			uint16_t flags = 0;
+
+			if (FD_ISSET(fde->fd, &r_fds)) flags |= TEVENT_FD_READ;
+			if (FD_ISSET(fde->fd, &w_fds)) flags |= TEVENT_FD_WRITE;
+			if (flags) {
+				fde->handler(select_ev->ev, fde, flags, fde->private_data);
+				break;
+			}
+		}
+	}
+
+	return 0;
+}
+
+/*
+  do a single event loop using the events defined in ev 
+*/
+static int select_event_loop_once(struct tevent_context *ev, const char *location)
+{
+	struct select_event_context *select_ev = talloc_get_type(ev->additional_data,
+		 					   struct select_event_context);
+	struct timeval tval;
+
+	if (ev->signal_events &&
+	    tevent_common_check_signal(ev)) {
+		return 0;
+	}
+
+	if (ev->immediate_events &&
+	    tevent_common_loop_immediate(ev)) {
+		return 0;
+	}
+
+	tval = tevent_common_loop_timer_delay(ev);
+	if (tevent_timeval_is_zero(&tval)) {
+		return 0;
+	}
+
+	return select_event_loop_select(select_ev, &tval);
+}
+
+static const struct tevent_ops select_event_ops = {
+	.context_init		= select_event_context_init,
+	.add_fd			= select_event_add_fd,
+	.set_fd_close_fn	= tevent_common_fd_set_close_fn,
+	.get_fd_flags		= tevent_common_fd_get_flags,
+	.set_fd_flags		= tevent_common_fd_set_flags,
+	.add_timer		= tevent_common_add_timer,
+	.schedule_immediate	= tevent_common_schedule_immediate,
+	.add_signal		= tevent_common_add_signal,
+	.loop_once		= select_event_loop_once,
+	.loop_wait		= tevent_common_loop_wait,
+};
+
+bool tevent_select_init(void)
+{
+	return tevent_register_backend("select", &select_event_ops);
+}

=== added file '.pc/security-CVE-2011-0719.patch/lib/tevent/tevent_standard.c'
--- .pc/security-CVE-2011-0719.patch/lib/tevent/tevent_standard.c	1970-01-01 00:00:00 +0000
+++ .pc/security-CVE-2011-0719.patch/lib/tevent/tevent_standard.c	2011-03-02 20:48:44 +0000
@@ -0,0 +1,569 @@
+/* 
+   Unix SMB/CIFS implementation.
+   main select loop and event handling
+   Copyright (C) Andrew Tridgell	2003-2005
+   Copyright (C) Stefan Metzmacher	2005-2009
+
+     ** NOTE! The following LGPL license applies to the tevent
+     ** library. This does NOT imply that all of Samba is released
+     ** under the LGPL
+
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 3 of the License, or (at your option) any later version.
+
+   This library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*
+  This is SAMBA's default event loop code
+
+  - we try to use epoll if configure detected support for it
+    otherwise we use select()
+  - if epoll is broken on the system or the kernel doesn't support it
+    at runtime we fallback to select()
+*/
+
+#include "replace.h"
+#include "system/filesys.h"
+#include "system/select.h"
+#include "tevent.h"
+#include "tevent_util.h"
+#include "tevent_internal.h"
+
+struct std_event_context {
+	/* a pointer back to the generic event_context */
+	struct tevent_context *ev;
+
+	/* the maximum file descriptor number in fd_events */
+	int maxfd;
+
+	/* information for exiting from the event loop */
+	int exit_code;
+
+	/* when using epoll this is the handle from epoll_create */
+	int epoll_fd;
+
+	/* our pid at the time the epoll_fd was created */
+	pid_t pid;
+};
+
+/* use epoll if it is available */
+#if HAVE_EPOLL
+/*
+  called when a epoll call fails, and we should fallback
+  to using select
+*/
+static void epoll_fallback_to_select(struct std_event_context *std_ev, const char *reason)
+{
+	tevent_debug(std_ev->ev, TEVENT_DEBUG_FATAL,
+		     "%s (%s) - falling back to select()\n",
+		     reason, strerror(errno));
+	close(std_ev->epoll_fd);
+	std_ev->epoll_fd = -1;
+	talloc_set_destructor(std_ev, NULL);
+}
+
+/*
+  map from TEVENT_FD_* to EPOLLIN/EPOLLOUT
+*/
+static uint32_t epoll_map_flags(uint16_t flags)
+{
+	uint32_t ret = 0;
+	if (flags & TEVENT_FD_READ) ret |= (EPOLLIN | EPOLLERR | EPOLLHUP);
+	if (flags & TEVENT_FD_WRITE) ret |= (EPOLLOUT | EPOLLERR | EPOLLHUP);
+	return ret;
+}
+
+/*
+ free the epoll fd
+*/
+static int epoll_ctx_destructor(struct std_event_context *std_ev)
+{
+	if (std_ev->epoll_fd != -1) {
+		close(std_ev->epoll_fd);
+	}
+	std_ev->epoll_fd = -1;
+	return 0;
+}
+
+/*
+ init the epoll fd
+*/
+static void epoll_init_ctx(struct std_event_context *std_ev)
+{
+	std_ev->epoll_fd = epoll_create(64);
+	std_ev->pid = getpid();
+	talloc_set_destructor(std_ev, epoll_ctx_destructor);
+}
+
+static void epoll_add_event(struct std_event_context *std_ev, struct tevent_fd *fde);
+
+/*
+  reopen the epoll handle when our pid changes
+  see http://junkcode.samba.org/ftp/unpacked/junkcode/epoll_fork.c for an 
+  demonstration of why this is needed
+ */
+static void epoll_check_reopen(struct std_event_context *std_ev)
+{
+	struct tevent_fd *fde;
+
+	if (std_ev->pid == getpid()) {
+		return;
+	}
+
+	close(std_ev->epoll_fd);
+	std_ev->epoll_fd = epoll_create(64);
+	if (std_ev->epoll_fd == -1) {
+		tevent_debug(std_ev->ev, TEVENT_DEBUG_FATAL,
+			     "Failed to recreate epoll handle after fork\n");
+		return;
+	}
+	std_ev->pid = getpid();
+	for (fde=std_ev->ev->fd_events;fde;fde=fde->next) {
+		epoll_add_event(std_ev, fde);
+	}
+}
+
+#define EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT	(1<<0)
+#define EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR	(1<<1)
+#define EPOLL_ADDITIONAL_FD_FLAG_GOT_ERROR	(1<<2)
+
+/*
+ add the epoll event to the given fd_event
+*/
+static void epoll_add_event(struct std_event_context *std_ev, struct tevent_fd *fde)
+{
+	struct epoll_event event;
+	if (std_ev->epoll_fd == -1) return;
+
+	fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR;
+
+	/* if we don't want events yet, don't add an epoll_event */
+	if (fde->flags == 0) return;
+
+	ZERO_STRUCT(event);
+	event.events = epoll_map_flags(fde->flags);
+	event.data.ptr = fde;
+	if (epoll_ctl(std_ev->epoll_fd, EPOLL_CTL_ADD, fde->fd, &event) != 0) {
+		epoll_fallback_to_select(std_ev, "EPOLL_CTL_ADD failed");
+	}
+	fde->additional_flags |= EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT;
+
+	/* only if we want to read we want to tell the event handler about errors */
+	if (fde->flags & TEVENT_FD_READ) {
+		fde->additional_flags |= EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR;
+	}
+}
+
+/*
+ delete the epoll event for given fd_event
+*/
+static void epoll_del_event(struct std_event_context *std_ev, struct tevent_fd *fde)
+{
+	struct epoll_event event;
+	if (std_ev->epoll_fd == -1) return;
+
+	fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR;
+
+	/* if there's no epoll_event, we don't need to delete it */
+	if (!(fde->additional_flags & EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT)) return;
+
+	ZERO_STRUCT(event);
+	event.events = epoll_map_flags(fde->flags);
+	event.data.ptr = fde;
+	epoll_ctl(std_ev->epoll_fd, EPOLL_CTL_DEL, fde->fd, &event);
+	fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT;
+}
+
+/*
+ change the epoll event to the given fd_event
+*/
+static void epoll_mod_event(struct std_event_context *std_ev, struct tevent_fd *fde)
+{
+	struct epoll_event event;
+	if (std_ev->epoll_fd == -1) return;
+
+	fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR;
+
+	ZERO_STRUCT(event);
+	event.events = epoll_map_flags(fde->flags);
+	event.data.ptr = fde;
+	if (epoll_ctl(std_ev->epoll_fd, EPOLL_CTL_MOD, fde->fd, &event) != 0) {
+		epoll_fallback_to_select(std_ev, "EPOLL_CTL_MOD failed");
+	}
+
+	/* only if we want to read we want to tell the event handler about errors */
+	if (fde->flags & TEVENT_FD_READ) {
+		fde->additional_flags |= EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR;
+	}
+}
+
+static void epoll_change_event(struct std_event_context *std_ev, struct tevent_fd *fde)
+{
+	bool got_error = (fde->additional_flags & EPOLL_ADDITIONAL_FD_FLAG_GOT_ERROR);
+	bool want_read = (fde->flags & TEVENT_FD_READ);
+	bool want_write= (fde->flags & TEVENT_FD_WRITE);
+
+	if (std_ev->epoll_fd == -1) return;
+
+	fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR;
+
+	/* there's already an event */
+	if (fde->additional_flags & EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT) {
+		if (want_read || (want_write && !got_error)) {
+			epoll_mod_event(std_ev, fde);
+			return;
+		}
+		/* 
+		 * if we want to match the select behavior, we need to remove the epoll_event
+		 * when the caller isn't interested in events.
+		 *
+		 * this is because epoll reports EPOLLERR and EPOLLHUP, even without asking for them
+		 */
+		epoll_del_event(std_ev, fde);
+		return;
+	}
+
+	/* there's no epoll_event attached to the fde */
+	if (want_read || (want_write && !got_error)) {
+		epoll_add_event(std_ev, fde);
+		return;
+	}
+}
+
+/*
+  event loop handling using epoll
+*/
+static int epoll_event_loop(struct std_event_context *std_ev, struct timeval *tvalp)
+{
+	int ret, i;
+#define MAXEVENTS 1
+	struct epoll_event events[MAXEVENTS];
+	int timeout = -1;
+
+	if (std_ev->epoll_fd == -1) return -1;
+
+	if (tvalp) {
+		/* it's better to trigger timed events a bit later than to early */
+		timeout = ((tvalp->tv_usec+999) / 1000) + (tvalp->tv_sec*1000);
+	}
+
+	if (std_ev->ev->signal_events &&
+	    tevent_common_check_signal(std_ev->ev)) {
+		return 0;
+	}
+
+	ret = epoll_wait(std_ev->epoll_fd, events, MAXEVENTS, timeout);
+
+	if (ret == -1 && errno == EINTR && std_ev->ev->signal_events) {
+		if (tevent_common_check_signal(std_ev->ev)) {
+			return 0;
+		}
+	}
+
+	if (ret == -1 && errno != EINTR) {
+		epoll_fallback_to_select(std_ev, "epoll_wait() failed");
+		return -1;
+	}
+
+	if (ret == 0 && tvalp) {
+		/* we don't care about a possible delay here */
+		tevent_common_loop_timer_delay(std_ev->ev);
+		return 0;
+	}
+
+	for (i=0;i<ret;i++) {
+		struct tevent_fd *fde = talloc_get_type(events[i].data.ptr, 
+						       struct tevent_fd);
+		uint16_t flags = 0;
+
+		if (fde == NULL) {
+			epoll_fallback_to_select(std_ev, "epoll_wait() gave bad data");
+			return -1;
+		}
+		if (events[i].events & (EPOLLHUP|EPOLLERR)) {
+			fde->additional_flags |= EPOLL_ADDITIONAL_FD_FLAG_GOT_ERROR;
+			/*
+			 * if we only wait for TEVENT_FD_WRITE, we should not tell the
+			 * event handler about it, and remove the epoll_event,
+			 * as we only report errors when waiting for read events,
+			 * to match the select() behavior
+			 */
+			if (!(fde->additional_flags & EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR)) {
+				epoll_del_event(std_ev, fde);
+				continue;
+			}
+			flags |= TEVENT_FD_READ;
+		}
+		if (events[i].events & EPOLLIN) flags |= TEVENT_FD_READ;
+		if (events[i].events & EPOLLOUT) flags |= TEVENT_FD_WRITE;
+		if (flags) {
+			fde->handler(std_ev->ev, fde, flags, fde->private_data);
+			break;
+		}
+	}
+
+	return 0;
+}
+#else
+#define epoll_init_ctx(std_ev) 
+#define epoll_add_event(std_ev,fde)
+#define epoll_del_event(std_ev,fde)
+#define epoll_change_event(std_ev,fde)
+#define epoll_event_loop(std_ev,tvalp) (-1)
+#define epoll_check_reopen(std_ev)
+#endif
+
+/*
+  create a std_event_context structure.
+*/
+static int std_event_context_init(struct tevent_context *ev)
+{
+	struct std_event_context *std_ev;
+
+	std_ev = talloc_zero(ev, struct std_event_context);
+	if (!std_ev) return -1;
+	std_ev->ev = ev;
+	std_ev->epoll_fd = -1;
+
+	epoll_init_ctx(std_ev);
+
+	ev->additional_data = std_ev;
+	return 0;
+}
+
+/*
+  recalculate the maxfd
+*/
+static void calc_maxfd(struct std_event_context *std_ev)
+{
+	struct tevent_fd *fde;
+
+	std_ev->maxfd = 0;
+	for (fde = std_ev->ev->fd_events; fde; fde = fde->next) {
+		if (fde->fd > std_ev->maxfd) {
+			std_ev->maxfd = fde->fd;
+		}
+	}
+}
+
+
+/* to mark the ev->maxfd invalid
+ * this means we need to recalculate it
+ */
+#define EVENT_INVALID_MAXFD (-1)
+
+/*
+  destroy an fd_event
+*/
+static int std_event_fd_destructor(struct tevent_fd *fde)
+{
+	struct tevent_context *ev = fde->event_ctx;
+	struct std_event_context *std_ev = NULL;
+
+	if (ev) {
+		std_ev = talloc_get_type(ev->additional_data,
+					 struct std_event_context);
+
+		epoll_check_reopen(std_ev);
+
+		if (std_ev->maxfd == fde->fd) {
+			std_ev->maxfd = EVENT_INVALID_MAXFD;
+		}
+
+		epoll_del_event(std_ev, fde);
+	}
+
+	return tevent_common_fd_destructor(fde);
+}
+
+/*
+  add a fd based event
+  return NULL on failure (memory allocation error)
+*/
+static struct tevent_fd *std_event_add_fd(struct tevent_context *ev, TALLOC_CTX *mem_ctx,
+					  int fd, uint16_t flags,
+					  tevent_fd_handler_t handler,
+					  void *private_data,
+					  const char *handler_name,
+					  const char *location)
+{
+	struct std_event_context *std_ev = talloc_get_type(ev->additional_data,
+							   struct std_event_context);
+	struct tevent_fd *fde;
+
+	epoll_check_reopen(std_ev);
+
+	fde = tevent_common_add_fd(ev, mem_ctx, fd, flags,
+				   handler, private_data,
+				   handler_name, location);
+	if (!fde) return NULL;
+
+	if ((std_ev->maxfd != EVENT_INVALID_MAXFD)
+	    && (fde->fd > std_ev->maxfd)) {
+		std_ev->maxfd = fde->fd;
+	}
+	talloc_set_destructor(fde, std_event_fd_destructor);
+
+	epoll_add_event(std_ev, fde);
+
+	return fde;
+}
+
+/*
+  set the fd event flags
+*/
+static void std_event_set_fd_flags(struct tevent_fd *fde, uint16_t flags)
+{
+	struct tevent_context *ev;
+	struct std_event_context *std_ev;
+
+	if (fde->flags == flags) return;
+
+	ev = fde->event_ctx;
+	std_ev = talloc_get_type(ev->additional_data, struct std_event_context);
+
+	fde->flags = flags;
+
+	epoll_check_reopen(std_ev);
+
+	epoll_change_event(std_ev, fde);
+}
+
+/*
+  event loop handling using select()
+*/
+static int std_event_loop_select(struct std_event_context *std_ev, struct timeval *tvalp)
+{
+	fd_set r_fds, w_fds;
+	struct tevent_fd *fde;
+	int selrtn;
+
+	/* we maybe need to recalculate the maxfd */
+	if (std_ev->maxfd == EVENT_INVALID_MAXFD) {
+		calc_maxfd(std_ev);
+	}
+
+	FD_ZERO(&r_fds);
+	FD_ZERO(&w_fds);
+
+	/* setup any fd events */
+	for (fde = std_ev->ev->fd_events; fde; fde = fde->next) {
+		if (fde->flags & TEVENT_FD_READ) {
+			FD_SET(fde->fd, &r_fds);
+		}
+		if (fde->flags & TEVENT_FD_WRITE) {
+			FD_SET(fde->fd, &w_fds);
+		}
+	}
+
+	if (std_ev->ev->signal_events &&
+	    tevent_common_check_signal(std_ev->ev)) {
+		return 0;
+	}
+
+	selrtn = select(std_ev->maxfd+1, &r_fds, &w_fds, NULL, tvalp);
+
+	if (selrtn == -1 && errno == EINTR && 
+	    std_ev->ev->signal_events) {
+		tevent_common_check_signal(std_ev->ev);
+		return 0;
+	}
+
+	if (selrtn == -1 && errno == EBADF) {
+		/* the socket is dead! this should never
+		   happen as the socket should have first been
+		   made readable and that should have removed
+		   the event, so this must be a bug. This is a
+		   fatal error. */
+		tevent_debug(std_ev->ev, TEVENT_DEBUG_FATAL,
+			     "ERROR: EBADF on std_event_loop_once\n");
+		std_ev->exit_code = EBADF;
+		return -1;
+	}
+
+	if (selrtn == 0 && tvalp) {
+		/* we don't care about a possible delay here */
+		tevent_common_loop_timer_delay(std_ev->ev);
+		return 0;
+	}
+
+	if (selrtn > 0) {
+		/* at least one file descriptor is ready - check
+		   which ones and call the handler, being careful to allow
+		   the handler to remove itself when called */
+		for (fde = std_ev->ev->fd_events; fde; fde = fde->next) {
+			uint16_t flags = 0;
+
+			if (FD_ISSET(fde->fd, &r_fds)) flags |= TEVENT_FD_READ;
+			if (FD_ISSET(fde->fd, &w_fds)) flags |= TEVENT_FD_WRITE;
+			if (flags) {
+				fde->handler(std_ev->ev, fde, flags, fde->private_data);
+				break;
+			}
+		}
+	}
+
+	return 0;
+}		
+
+/*
+  do a single event loop using the events defined in ev 
+*/
+static int std_event_loop_once(struct tevent_context *ev, const char *location)
+{
+	struct std_event_context *std_ev = talloc_get_type(ev->additional_data,
+		 					   struct std_event_context);
+	struct timeval tval;
+
+	if (ev->signal_events &&
+	    tevent_common_check_signal(ev)) {
+		return 0;
+	}
+
+	if (ev->immediate_events &&
+	    tevent_common_loop_immediate(ev)) {
+		return 0;
+	}
+
+	tval = tevent_common_loop_timer_delay(ev);
+	if (tevent_timeval_is_zero(&tval)) {
+		return 0;
+	}
+
+	epoll_check_reopen(std_ev);
+
+	if (epoll_event_loop(std_ev, &tval) == 0) {
+		return 0;
+	}
+
+	return std_event_loop_select(std_ev, &tval);
+}
+
+static const struct tevent_ops std_event_ops = {
+	.context_init		= std_event_context_init,
+	.add_fd			= std_event_add_fd,
+	.set_fd_close_fn	= tevent_common_fd_set_close_fn,
+	.get_fd_flags		= tevent_common_fd_get_flags,
+	.set_fd_flags		= std_event_set_fd_flags,
+	.add_timer		= tevent_common_add_timer,
+	.schedule_immediate	= tevent_common_schedule_immediate,
+	.add_signal		= tevent_common_add_signal,
+	.loop_once		= std_event_loop_once,
+	.loop_wait		= tevent_common_loop_wait,
+};
+
+
+bool tevent_standard_init(void)
+{
+	return tevent_register_backend("standard", &std_event_ops);
+}
+

=== added directory '.pc/security-CVE-2011-0719.patch/nsswitch'
=== added directory '.pc/security-CVE-2011-0719.patch/nsswitch/libwbclient'
=== added file '.pc/security-CVE-2011-0719.patch/nsswitch/libwbclient/wbc_async.c'
--- .pc/security-CVE-2011-0719.patch/nsswitch/libwbclient/wbc_async.c	1970-01-01 00:00:00 +0000
+++ .pc/security-CVE-2011-0719.patch/nsswitch/libwbclient/wbc_async.c	2011-03-02 20:48:44 +0000
@@ -0,0 +1,774 @@
+/*
+   Unix SMB/CIFS implementation.
+   Infrastructure for async winbind requests
+   Copyright (C) Volker Lendecke 2008
+
+     ** NOTE! The following LGPL license applies to the wbclient
+     ** library. This does NOT imply that all of Samba is released
+     ** under the LGPL
+
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 3 of the License, or (at your option) any later version.
+
+   This library 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
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "replace.h"
+#include "system/filesys.h"
+#include "system/network.h"
+#include <talloc.h>
+#include <tevent.h>
+#include "lib/async_req/async_sock.h"
+#include "nsswitch/winbind_struct_protocol.h"
+#include "nsswitch/libwbclient/wbclient.h"
+#include "nsswitch/libwbclient/wbc_async.h"
+
+wbcErr map_wbc_err_from_errno(int error)
+{
+	switch(error) {
+	case EPERM:
+	case EACCES:
+		return WBC_ERR_AUTH_ERROR;
+	case ENOMEM:
+		return WBC_ERR_NO_MEMORY;
+	case EIO:
+	default:
+		return WBC_ERR_UNKNOWN_FAILURE;
+	}
+}
+
+bool tevent_req_is_wbcerr(struct tevent_req *req, wbcErr *pwbc_err)
+{
+	enum tevent_req_state state;
+	uint64_t error;
+	if (!tevent_req_is_error(req, &state, &error)) {
+		*pwbc_err = WBC_ERR_SUCCESS;
+		return false;
+	}
+
+	switch (state) {
+	case TEVENT_REQ_USER_ERROR:
+		*pwbc_err = error;
+		break;
+	case TEVENT_REQ_TIMED_OUT:
+		*pwbc_err = WBC_ERR_UNKNOWN_FAILURE;
+		break;
+	case TEVENT_REQ_NO_MEMORY:
+		*pwbc_err = WBC_ERR_NO_MEMORY;
+		break;
+	default:
+		*pwbc_err = WBC_ERR_UNKNOWN_FAILURE;
+		break;
+	}
+	return true;
+}
+
+wbcErr tevent_req_simple_recv_wbcerr(struct tevent_req *req)
+{
+	wbcErr wbc_err;
+
+	if (tevent_req_is_wbcerr(req, &wbc_err)) {
+		return wbc_err;
+	}
+
+	return WBC_ERR_SUCCESS;
+}
+
+struct wbc_debug_ops {
+	void (*debug)(void *context, enum wbcDebugLevel level,
+		      const char *fmt, va_list ap) PRINTF_ATTRIBUTE(3,0);
+	void *context;
+};
+
+struct wb_context {
+	struct tevent_queue *queue;
+	int fd;
+	bool is_priv;
+	const char *dir;
+	struct wbc_debug_ops debug_ops;
+};
+
+static int make_nonstd_fd(int fd)
+{
+	int i;
+	int sys_errno = 0;
+	int fds[3];
+	int num_fds = 0;
+
+	if (fd == -1) {
+		return -1;
+	}
+	while (fd < 3) {
+		fds[num_fds++] = fd;
+		fd = dup(fd);
+		if (fd == -1) {
+			sys_errno = errno;
+			break;
+		}
+	}
+	for (i=0; i<num_fds; i++) {
+		close(fds[i]);
+	}
+	if (fd == -1) {
+		errno = sys_errno;
+	}
+	return fd;
+}
+
+/****************************************************************************
+ Set a fd into blocking/nonblocking mode. Uses POSIX O_NONBLOCK if available,
+ else
+ if SYSV use O_NDELAY
+ if BSD use FNDELAY
+ Set close on exec also.
+****************************************************************************/
+
+static int make_safe_fd(int fd)
+{
+	int result, flags;
+	int new_fd = make_nonstd_fd(fd);
+
+	if (new_fd == -1) {
+		goto fail;
+	}
+
+	/* Socket should be nonblocking. */
+
+#ifdef O_NONBLOCK
+#define FLAG_TO_SET O_NONBLOCK
+#else
+#ifdef SYSV
+#define FLAG_TO_SET O_NDELAY
+#else /* BSD */
+#define FLAG_TO_SET FNDELAY
+#endif
+#endif
+
+	if ((flags = fcntl(new_fd, F_GETFL)) == -1) {
+		goto fail;
+	}
+
+	flags |= FLAG_TO_SET;
+	if (fcntl(new_fd, F_SETFL, flags) == -1) {
+		goto fail;
+	}
+
+#undef FLAG_TO_SET
+
+	/* Socket should be closed on exec() */
+#ifdef FD_CLOEXEC
+	result = flags = fcntl(new_fd, F_GETFD, 0);
+	if (flags >= 0) {
+		flags |= FD_CLOEXEC;
+		result = fcntl( new_fd, F_SETFD, flags );
+	}
+	if (result < 0) {
+		goto fail;
+	}
+#endif
+	return new_fd;
+
+ fail:
+	if (new_fd != -1) {
+		int sys_errno = errno;
+		close(new_fd);
+		errno = sys_errno;
+	}
+	return -1;
+}
+
+/* Just put a prototype to avoid moving the whole function around */
+static const char *winbindd_socket_dir(void);
+
+struct wb_context *wb_context_init(TALLOC_CTX *mem_ctx, const char* dir)
+{
+	struct wb_context *result;
+
+	result = talloc(mem_ctx, struct wb_context);
+	if (result == NULL) {
+		return NULL;
+	}
+	result->queue = tevent_queue_create(result, "wb_trans");
+	if (result->queue == NULL) {
+		TALLOC_FREE(result);
+		return NULL;
+	}
+	result->fd = -1;
+	result->is_priv = false;
+
+	if (dir != NULL) {
+		result->dir = talloc_strdup(result, dir);
+	} else {
+		result->dir = winbindd_socket_dir();
+	}
+	if (result->dir == NULL) {
+		TALLOC_FREE(result);
+		return NULL;
+	}
+	return result;
+}
+
+struct wb_connect_state {
+	int dummy;
+};
+
+static void wbc_connect_connected(struct tevent_req *subreq);
+
+static struct tevent_req *wb_connect_send(TALLOC_CTX *mem_ctx,
+					  struct tevent_context *ev,
+					  struct wb_context *wb_ctx,
+					  const char *dir)
+{
+	struct tevent_req *result, *subreq;
+	struct wb_connect_state *state;
+	struct sockaddr_un sunaddr;
+	struct stat st;
+	char *path = NULL;
+	wbcErr wbc_err;
+
+	result = tevent_req_create(mem_ctx, &state, struct wb_connect_state);
+	if (result == NULL) {
+		return NULL;
+	}
+
+	if (wb_ctx->fd != -1) {
+		close(wb_ctx->fd);
+		wb_ctx->fd = -1;
+	}
+
+	/* Check permissions on unix socket directory */
+
+	if (lstat(dir, &st) == -1) {
+		wbc_err = WBC_ERR_WINBIND_NOT_AVAILABLE;
+		goto post_status;
+	}
+
+	if (!S_ISDIR(st.st_mode) ||
+	    (st.st_uid != 0 && st.st_uid != geteuid())) {
+		wbc_err = WBC_ERR_WINBIND_NOT_AVAILABLE;
+		goto post_status;
+	}
+
+	/* Connect to socket */
+
+	path = talloc_asprintf(mem_ctx, "%s/%s", dir,
+			       WINBINDD_SOCKET_NAME);
+	if (path == NULL) {
+		goto nomem;
+	}
+
+	sunaddr.sun_family = AF_UNIX;
+	strlcpy(sunaddr.sun_path, path, sizeof(sunaddr.sun_path));
+	TALLOC_FREE(path);
+
+	/* If socket file doesn't exist, don't bother trying to connect
+	   with retry.  This is an attempt to make the system usable when
+	   the winbindd daemon is not running. */
+
+	if ((lstat(sunaddr.sun_path, &st) == -1)
+	    || !S_ISSOCK(st.st_mode)
+	    || (st.st_uid != 0 && st.st_uid != geteuid())) {
+		wbc_err = WBC_ERR_WINBIND_NOT_AVAILABLE;
+		goto post_status;
+	}
+
+	wb_ctx->fd = make_safe_fd(socket(AF_UNIX, SOCK_STREAM, 0));
+	if (wb_ctx->fd == -1) {
+		wbc_err = map_wbc_err_from_errno(errno);
+		goto post_status;
+	}
+
+	subreq = async_connect_send(mem_ctx, ev, wb_ctx->fd,
+				    (struct sockaddr *)(void *)&sunaddr,
+				    sizeof(sunaddr));
+	if (subreq == NULL) {
+		goto nomem;
+	}
+	tevent_req_set_callback(subreq, wbc_connect_connected, result);
+	return result;
+
+ post_status:
+	tevent_req_error(result, wbc_err);
+	return tevent_req_post(result, ev);
+ nomem:
+	TALLOC_FREE(result);
+	return NULL;
+}
+
+static void wbc_connect_connected(struct tevent_req *subreq)
+{
+	struct tevent_req *req = tevent_req_callback_data(
+		subreq, struct tevent_req);
+	int res, err;
+
+	res = async_connect_recv(subreq, &err);
+	TALLOC_FREE(subreq);
+	if (res == -1) {
+		tevent_req_error(req, map_wbc_err_from_errno(err));
+		return;
+	}
+	tevent_req_done(req);
+}
+
+static wbcErr wb_connect_recv(struct tevent_req *req)
+{
+	return tevent_req_simple_recv_wbcerr(req);
+}
+
+static const char *winbindd_socket_dir(void)
+{
+#ifdef SOCKET_WRAPPER
+	const char *env_dir;
+
+	env_dir = getenv(WINBINDD_SOCKET_DIR_ENVVAR);
+	if (env_dir) {
+		return env_dir;
+	}
+#endif
+
+	return WINBINDD_SOCKET_DIR;
+}
+
+struct wb_open_pipe_state {
+	struct wb_context *wb_ctx;
+	struct tevent_context *ev;
+	bool need_priv;
+	struct winbindd_request wb_req;
+};
+
+static void wb_open_pipe_connect_nonpriv_done(struct tevent_req *subreq);
+static void wb_open_pipe_ping_done(struct tevent_req *subreq);
+static void wb_open_pipe_getpriv_done(struct tevent_req *subreq);
+static void wb_open_pipe_connect_priv_done(struct tevent_req *subreq);
+
+static struct tevent_req *wb_open_pipe_send(TALLOC_CTX *mem_ctx,
+					    struct tevent_context *ev,
+					    struct wb_context *wb_ctx,
+					    bool need_priv)
+{
+	struct tevent_req *result, *subreq;
+	struct wb_open_pipe_state *state;
+
+	result = tevent_req_create(mem_ctx, &state, struct wb_open_pipe_state);
+	if (result == NULL) {
+		return NULL;
+	}
+	state->wb_ctx = wb_ctx;
+	state->ev = ev;
+	state->need_priv = need_priv;
+
+	if (wb_ctx->fd != -1) {
+		close(wb_ctx->fd);
+		wb_ctx->fd = -1;
+	}
+
+	subreq = wb_connect_send(state, ev, wb_ctx, wb_ctx->dir);
+	if (subreq == NULL) {
+		goto fail;
+	}
+	tevent_req_set_callback(subreq, wb_open_pipe_connect_nonpriv_done,
+				result);
+	return result;
+
+ fail:
+	TALLOC_FREE(result);
+	return NULL;
+}
+
+static void wb_open_pipe_connect_nonpriv_done(struct tevent_req *subreq)
+{
+	struct tevent_req *req = tevent_req_callback_data(
+		subreq, struct tevent_req);
+	struct wb_open_pipe_state *state = tevent_req_data(
+		req, struct wb_open_pipe_state);
+	wbcErr wbc_err;
+
+	wbc_err = wb_connect_recv(subreq);
+	TALLOC_FREE(subreq);
+	if (!WBC_ERROR_IS_OK(wbc_err)) {
+		state->wb_ctx->is_priv = true;
+		tevent_req_error(req, wbc_err);
+		return;
+	}
+
+	ZERO_STRUCT(state->wb_req);
+	state->wb_req.cmd = WINBINDD_INTERFACE_VERSION;
+	state->wb_req.pid = getpid();
+
+	subreq = wb_simple_trans_send(state, state->ev, NULL,
+				      state->wb_ctx->fd, &state->wb_req);
+	if (tevent_req_nomem(subreq, req)) {
+		return;
+	}
+	tevent_req_set_callback(subreq, wb_open_pipe_ping_done, req);
+}
+
+static void wb_open_pipe_ping_done(struct tevent_req *subreq)
+{
+	struct tevent_req *req = tevent_req_callback_data(
+		subreq, struct tevent_req);
+	struct wb_open_pipe_state *state = tevent_req_data(
+		req, struct wb_open_pipe_state);
+	struct winbindd_response *wb_resp;
+	int ret, err;
+
+	ret = wb_simple_trans_recv(subreq, state, &wb_resp, &err);
+	TALLOC_FREE(subreq);
+	if (ret == -1) {
+		tevent_req_error(req, map_wbc_err_from_errno(err));
+		return;
+	}
+
+	if (!state->need_priv) {
+		tevent_req_done(req);
+		return;
+	}
+
+	state->wb_req.cmd = WINBINDD_PRIV_PIPE_DIR;
+	state->wb_req.pid = getpid();
+
+	subreq = wb_simple_trans_send(state, state->ev, NULL,
+				      state->wb_ctx->fd, &state->wb_req);
+	if (tevent_req_nomem(subreq, req)) {
+		return;
+	}
+	tevent_req_set_callback(subreq, wb_open_pipe_getpriv_done, req);
+}
+
+static void wb_open_pipe_getpriv_done(struct tevent_req *subreq)
+{
+	struct tevent_req *req = tevent_req_callback_data(
+		subreq, struct tevent_req);
+	struct wb_open_pipe_state *state = tevent_req_data(
+		req, struct wb_open_pipe_state);
+	struct winbindd_response *wb_resp = NULL;
+	int ret, err;
+
+	ret = wb_simple_trans_recv(subreq, state, &wb_resp, &err);
+	TALLOC_FREE(subreq);
+	if (ret == -1) {
+		tevent_req_error(req, map_wbc_err_from_errno(err));
+		return;
+	}
+
+	close(state->wb_ctx->fd);
+	state->wb_ctx->fd = -1;
+
+	subreq = wb_connect_send(state, state->ev, state->wb_ctx,
+				  (char *)wb_resp->extra_data.data);
+	TALLOC_FREE(wb_resp);
+	if (tevent_req_nomem(subreq, req)) {
+		return;
+	}
+	tevent_req_set_callback(subreq, wb_open_pipe_connect_priv_done, req);
+}
+
+static void wb_open_pipe_connect_priv_done(struct tevent_req *subreq)
+{
+	struct tevent_req *req = tevent_req_callback_data(
+		subreq, struct tevent_req);
+	struct wb_open_pipe_state *state = tevent_req_data(
+		req, struct wb_open_pipe_state);
+	wbcErr wbc_err;
+
+	wbc_err = wb_connect_recv(subreq);
+	TALLOC_FREE(subreq);
+	if (!WBC_ERROR_IS_OK(wbc_err)) {
+		tevent_req_error(req, wbc_err);
+		return;
+	}
+	state->wb_ctx->is_priv = true;
+	tevent_req_done(req);
+}
+
+static wbcErr wb_open_pipe_recv(struct tevent_req *req)
+{
+	return tevent_req_simple_recv_wbcerr(req);
+}
+
+struct wb_trans_state {
+	struct wb_trans_state *prev, *next;
+	struct wb_context *wb_ctx;
+	struct tevent_context *ev;
+	struct winbindd_request *wb_req;
+	struct winbindd_response *wb_resp;
+	bool need_priv;
+};
+
+static bool closed_fd(int fd)
+{
+	struct timeval tv;
+	fd_set r_fds;
+	int selret;
+
+	if (fd == -1) {
+		return true;
+	}
+
+	FD_ZERO(&r_fds);
+	FD_SET(fd, &r_fds);
+	ZERO_STRUCT(tv);
+
+	selret = select(fd+1, &r_fds, NULL, NULL, &tv);
+	if (selret == -1) {
+		return true;
+	}
+	if (selret == 0) {
+		return false;
+	}
+	return (FD_ISSET(fd, &r_fds));
+}
+
+static void wb_trans_trigger(struct tevent_req *req, void *private_data);
+static void wb_trans_connect_done(struct tevent_req *subreq);
+static void wb_trans_done(struct tevent_req *subreq);
+static void wb_trans_retry_wait_done(struct tevent_req *subreq);
+
+struct tevent_req *wb_trans_send(TALLOC_CTX *mem_ctx,
+				 struct tevent_context *ev,
+				 struct wb_context *wb_ctx, bool need_priv,
+				 struct winbindd_request *wb_req)
+{
+	struct tevent_req *req;
+	struct wb_trans_state *state;
+
+	req = tevent_req_create(mem_ctx, &state, struct wb_trans_state);
+	if (req == NULL) {
+		return NULL;
+	}
+	state->wb_ctx = wb_ctx;
+	state->ev = ev;
+	state->wb_req = wb_req;
+	state->need_priv = need_priv;
+
+	if (!tevent_queue_add(wb_ctx->queue, ev, req, wb_trans_trigger,
+			      NULL)) {
+		tevent_req_nomem(NULL, req);
+		return tevent_req_post(req, ev);
+	}
+	return req;
+}
+
+static void wb_trans_trigger(struct tevent_req *req, void *private_data)
+{
+	struct wb_trans_state *state = tevent_req_data(
+		req, struct wb_trans_state);
+	struct tevent_req *subreq;
+
+	if ((state->wb_ctx->fd != -1) && closed_fd(state->wb_ctx->fd)) {
+		close(state->wb_ctx->fd);
+		state->wb_ctx->fd = -1;
+	}
+
+	if ((state->wb_ctx->fd == -1)
+	    || (state->need_priv && !state->wb_ctx->is_priv)) {
+		subreq = wb_open_pipe_send(state, state->ev, state->wb_ctx,
+					   state->need_priv);
+		if (tevent_req_nomem(subreq, req)) {
+			return;
+		}
+		tevent_req_set_callback(subreq, wb_trans_connect_done, req);
+		return;
+	}
+
+	state->wb_req->pid = getpid();
+
+	subreq = wb_simple_trans_send(state, state->ev, NULL,
+				      state->wb_ctx->fd, state->wb_req);
+	if (tevent_req_nomem(subreq, req)) {
+		return;
+	}
+	tevent_req_set_callback(subreq, wb_trans_done, req);
+}
+
+static bool wb_trans_retry(struct tevent_req *req,
+			   struct wb_trans_state *state,
+			   wbcErr wbc_err)
+{
+	struct tevent_req *subreq;
+
+	if (WBC_ERROR_IS_OK(wbc_err)) {
+		return false;
+	}
+
+	if (wbc_err == WBC_ERR_WINBIND_NOT_AVAILABLE) {
+		/*
+		 * Winbind not around or we can't connect to the pipe. Fail
+		 * immediately.
+		 */
+		tevent_req_error(req, wbc_err);
+		return true;
+	}
+
+	/*
+	 * The transfer as such failed, retry after one second
+	 */
+
+	if (state->wb_ctx->fd != -1) {
+		close(state->wb_ctx->fd);
+		state->wb_ctx->fd = -1;
+	}
+
+	subreq = tevent_wakeup_send(state, state->ev,
+				    tevent_timeval_current_ofs(1, 0));
+	if (tevent_req_nomem(subreq, req)) {
+		return true;
+	}
+	tevent_req_set_callback(subreq, wb_trans_retry_wait_done, req);
+	return true;
+}
+
+static void wb_trans_retry_wait_done(struct tevent_req *subreq)
+{
+	struct tevent_req *req = tevent_req_callback_data(
+		subreq, struct tevent_req);
+	struct wb_trans_state *state = tevent_req_data(
+		req, struct wb_trans_state);
+	bool ret;
+
+	ret = tevent_wakeup_recv(subreq);
+	TALLOC_FREE(subreq);
+	if (!ret) {
+		tevent_req_error(req, WBC_ERR_UNKNOWN_FAILURE);
+		return;
+	}
+
+	subreq = wb_open_pipe_send(state, state->ev, state->wb_ctx,
+				   state->need_priv);
+	if (tevent_req_nomem(subreq, req)) {
+		return;
+	}
+	tevent_req_set_callback(subreq, wb_trans_connect_done, req);
+}
+
+static void wb_trans_connect_done(struct tevent_req *subreq)
+{
+	struct tevent_req *req = tevent_req_callback_data(
+		subreq, struct tevent_req);
+	struct wb_trans_state *state = tevent_req_data(
+		req, struct wb_trans_state);
+	wbcErr wbc_err;
+
+	wbc_err = wb_open_pipe_recv(subreq);
+	TALLOC_FREE(subreq);
+
+	if (wb_trans_retry(req, state, wbc_err)) {
+		return;
+	}
+
+	subreq = wb_simple_trans_send(state, state->ev, NULL,
+				      state->wb_ctx->fd, state->wb_req);
+	if (tevent_req_nomem(subreq, req)) {
+		return;
+	}
+	tevent_req_set_callback(subreq, wb_trans_done, req);
+}
+
+static void wb_trans_done(struct tevent_req *subreq)
+{
+	struct tevent_req *req = tevent_req_callback_data(
+		subreq, struct tevent_req);
+	struct wb_trans_state *state = tevent_req_data(
+		req, struct wb_trans_state);
+	int ret, err;
+
+	ret = wb_simple_trans_recv(subreq, state, &state->wb_resp, &err);
+	TALLOC_FREE(subreq);
+	if ((ret == -1)
+	    && wb_trans_retry(req, state, map_wbc_err_from_errno(err))) {
+		return;
+	}
+
+	tevent_req_done(req);
+}
+
+wbcErr wb_trans_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
+		     struct winbindd_response **presponse)
+{
+	struct wb_trans_state *state = tevent_req_data(
+		req, struct wb_trans_state);
+	wbcErr wbc_err;
+
+	if (tevent_req_is_wbcerr(req, &wbc_err)) {
+		return wbc_err;
+	}
+
+	*presponse = talloc_move(mem_ctx, &state->wb_resp);
+	return WBC_ERR_SUCCESS;
+}
+
+/********************************************************************
+ * Debug wrapper functions, modeled (with lot's of code copied as is)
+ * after the tevent debug wrapper functions
+ ********************************************************************/
+
+/*
+  this allows the user to choose their own debug function
+*/
+int wbcSetDebug(struct wb_context *wb_ctx,
+		void (*debug)(void *context,
+			      enum wbcDebugLevel level,
+			      const char *fmt,
+			      va_list ap) PRINTF_ATTRIBUTE(3,0),
+		void *context)
+{
+	wb_ctx->debug_ops.debug = debug;
+	wb_ctx->debug_ops.context = context;
+	return 0;
+}
+
+/*
+  debug function for wbcSetDebugStderr
+*/
+static void wbcDebugStderr(void *private_data,
+			   enum wbcDebugLevel level,
+			   const char *fmt,
+			   va_list ap) PRINTF_ATTRIBUTE(3,0);
+static void wbcDebugStderr(void *private_data,
+			   enum wbcDebugLevel level,
+			   const char *fmt, va_list ap)
+{
+	if (level <= WBC_DEBUG_WARNING) {
+		vfprintf(stderr, fmt, ap);
+	}
+}
+
+/*
+  convenience function to setup debug messages on stderr
+  messages of level WBC_DEBUG_WARNING and higher are printed
+*/
+int wbcSetDebugStderr(struct wb_context *wb_ctx)
+{
+	return wbcSetDebug(wb_ctx, wbcDebugStderr, wb_ctx);
+}
+
+/*
+ * log a message
+ *
+ * The default debug action is to ignore debugging messages.
+ * This is the most appropriate action for a library.
+ * Applications using the library must decide where to
+ * redirect debugging messages
+*/
+void wbcDebug(struct wb_context *wb_ctx, enum wbcDebugLevel level,
+	      const char *fmt, ...)
+{
+	va_list ap;
+	if (!wb_ctx) {
+		return;
+	}
+	if (wb_ctx->debug_ops.debug == NULL) {
+		return;
+	}
+	va_start(ap, fmt);
+	wb_ctx->debug_ops.debug(wb_ctx->debug_ops.context, level, fmt, ap);
+	va_end(ap);
+}

=== added file '.pc/security-CVE-2011-0719.patch/nsswitch/wb_common.c'
--- .pc/security-CVE-2011-0719.patch/nsswitch/wb_common.c	1970-01-01 00:00:00 +0000
+++ .pc/security-CVE-2011-0719.patch/nsswitch/wb_common.c	2011-03-02 20:48:44 +0000
@@ -0,0 +1,690 @@
+/*
+   Unix SMB/CIFS implementation.
+
+   winbind client common code
+
+   Copyright (C) Tim Potter 2000
+   Copyright (C) Andrew Tridgell 2000
+   Copyright (C) Andrew Bartlett 2002
+
+
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 3 of the License, or (at your option) any later version.
+
+   This library 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
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "winbind_client.h"
+
+/* Global variables.  These are effectively the client state information */
+
+int winbindd_fd = -1;           /* fd for winbindd socket */
+static int is_privileged = 0;
+
+/* Free a response structure */
+
+void winbindd_free_response(struct winbindd_response *response)
+{
+	/* Free any allocated extra_data */
+
+	if (response)
+		SAFE_FREE(response->extra_data.data);
+}
+
+/* Initialise a request structure */
+
+void winbindd_init_request(struct winbindd_request *request, int request_type)
+{
+	request->length = sizeof(struct winbindd_request);
+
+	request->cmd = (enum winbindd_cmd)request_type;
+	request->pid = getpid();
+
+}
+
+/* Initialise a response structure */
+
+static void init_response(struct winbindd_response *response)
+{
+	/* Initialise return value */
+
+	response->result = WINBINDD_ERROR;
+}
+
+/* Close established socket */
+
+void winbind_close_sock(void)
+{
+	if (winbindd_fd != -1) {
+		close(winbindd_fd);
+		winbindd_fd = -1;
+	}
+}
+
+#define CONNECT_TIMEOUT 30
+
+/* Make sure socket handle isn't stdin, stdout or stderr */
+#define RECURSION_LIMIT 3
+
+static int make_nonstd_fd_internals(int fd, int limit /* Recursion limiter */)
+{
+	int new_fd;
+	if (fd >= 0 && fd <= 2) {
+#ifdef F_DUPFD
+		if ((new_fd = fcntl(fd, F_DUPFD, 3)) == -1) {
+			return -1;
+		}
+		/* Paranoia */
+		if (new_fd < 3) {
+			close(new_fd);
+			return -1;
+		}
+		close(fd);
+		return new_fd;
+#else
+		if (limit <= 0)
+			return -1;
+
+		new_fd = dup(fd);
+		if (new_fd == -1)
+			return -1;
+
+		/* use the program stack to hold our list of FDs to close */
+		new_fd = make_nonstd_fd_internals(new_fd, limit - 1);
+		close(fd);
+		return new_fd;
+#endif
+	}
+	return fd;
+}
+
+/****************************************************************************
+ Set a fd into blocking/nonblocking mode. Uses POSIX O_NONBLOCK if available,
+ else
+ if SYSV use O_NDELAY
+ if BSD use FNDELAY
+ Set close on exec also.
+****************************************************************************/
+
+static int make_safe_fd(int fd)
+{
+	int result, flags;
+	int new_fd = make_nonstd_fd_internals(fd, RECURSION_LIMIT);
+	if (new_fd == -1) {
+		close(fd);
+		return -1;
+	}
+
+	/* Socket should be nonblocking. */
+#ifdef O_NONBLOCK
+#define FLAG_TO_SET O_NONBLOCK
+#else
+#ifdef SYSV
+#define FLAG_TO_SET O_NDELAY
+#else /* BSD */
+#define FLAG_TO_SET FNDELAY
+#endif
+#endif
+
+	if ((flags = fcntl(new_fd, F_GETFL)) == -1) {
+		close(new_fd);
+		return -1;
+	}
+
+	flags |= FLAG_TO_SET;
+	if (fcntl(new_fd, F_SETFL, flags) == -1) {
+		close(new_fd);
+		return -1;
+	}
+
+#undef FLAG_TO_SET
+
+	/* Socket should be closed on exec() */
+#ifdef FD_CLOEXEC
+	result = flags = fcntl(new_fd, F_GETFD, 0);
+	if (flags >= 0) {
+		flags |= FD_CLOEXEC;
+		result = fcntl( new_fd, F_SETFD, flags );
+	}
+	if (result < 0) {
+		close(new_fd);
+		return -1;
+	}
+#endif
+	return new_fd;
+}
+
+/* Connect to winbindd socket */
+
+static int winbind_named_pipe_sock(const char *dir)
+{
+	struct sockaddr_un sunaddr;
+	struct stat st;
+	char *path = NULL;
+	int fd;
+	int wait_time;
+	int slept;
+
+	/* Check permissions on unix socket directory */
+
+	if (lstat(dir, &st) == -1) {
+		errno = ENOENT;
+		return -1;
+	}
+
+	if (!S_ISDIR(st.st_mode) ||
+	    (st.st_uid != 0 && st.st_uid != geteuid())) {
+		errno = ENOENT;
+		return -1;
+	}
+
+	/* Connect to socket */
+
+	if (asprintf(&path, "%s/%s", dir, WINBINDD_SOCKET_NAME) < 0) {
+		return -1;
+	}
+
+	ZERO_STRUCT(sunaddr);
+	sunaddr.sun_family = AF_UNIX;
+	strncpy(sunaddr.sun_path, path, sizeof(sunaddr.sun_path) - 1);
+
+	/* If socket file doesn't exist, don't bother trying to connect
+	   with retry.  This is an attempt to make the system usable when
+	   the winbindd daemon is not running. */
+
+	if (lstat(path, &st) == -1) {
+		errno = ENOENT;
+		SAFE_FREE(path);
+		return -1;
+	}
+
+	SAFE_FREE(path);
+	/* Check permissions on unix socket file */
+
+	if (!S_ISSOCK(st.st_mode) ||
+	    (st.st_uid != 0 && st.st_uid != geteuid())) {
+		errno = ENOENT;
+		return -1;
+	}
+
+	/* Connect to socket */
+
+	if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
+		return -1;
+	}
+
+	/* Set socket non-blocking and close on exec. */
+
+	if ((fd = make_safe_fd( fd)) == -1) {
+		return fd;
+	}
+
+	for (wait_time = 0; connect(fd, (struct sockaddr *)&sunaddr, sizeof(sunaddr)) == -1;
+			wait_time += slept) {
+		struct timeval tv;
+		fd_set w_fds;
+		int ret;
+		int connect_errno = 0;
+		socklen_t errnosize;
+
+		if (wait_time >= CONNECT_TIMEOUT)
+			goto error_out;
+
+		switch (errno) {
+			case EINPROGRESS:
+				FD_ZERO(&w_fds);
+				FD_SET(fd, &w_fds);
+				tv.tv_sec = CONNECT_TIMEOUT - wait_time;
+				tv.tv_usec = 0;
+
+				ret = select(fd + 1, NULL, &w_fds, NULL, &tv);
+
+				if (ret > 0) {
+					errnosize = sizeof(connect_errno);
+
+					ret = getsockopt(fd, SOL_SOCKET,
+							SO_ERROR, &connect_errno, &errnosize);
+
+					if (ret >= 0 && connect_errno == 0) {
+						/* Connect succeed */
+						goto out;
+					}
+				}
+
+				slept = CONNECT_TIMEOUT;
+				break;
+			case EAGAIN:
+				slept = rand() % 3 + 1;
+				sleep(slept);
+				break;
+			default:
+				goto error_out;
+		}
+
+	}
+
+  out:
+
+	return fd;
+
+  error_out:
+
+	close(fd);
+	return -1;
+}
+
+static const char *winbindd_socket_dir(void)
+{
+#ifdef SOCKET_WRAPPER
+	const char *env_dir;
+
+	env_dir = getenv(WINBINDD_SOCKET_DIR_ENVVAR);
+	if (env_dir) {
+		return env_dir;
+	}
+#endif
+
+	return WINBINDD_SOCKET_DIR;
+}
+
+/* Connect to winbindd socket */
+
+static int winbind_open_pipe_sock(int recursing, int need_priv)
+{
+#ifdef HAVE_UNIXSOCKET
+	static pid_t our_pid;
+	struct winbindd_request request;
+	struct winbindd_response response;
+	ZERO_STRUCT(request);
+	ZERO_STRUCT(response);
+
+	if (our_pid != getpid()) {
+		winbind_close_sock();
+		our_pid = getpid();
+	}
+
+	if ((need_priv != 0) && (is_privileged == 0)) {
+		winbind_close_sock();
+	}
+
+	if (winbindd_fd != -1) {
+		return winbindd_fd;
+	}
+
+	if (recursing) {
+		return -1;
+	}
+
+	if ((winbindd_fd = winbind_named_pipe_sock(winbindd_socket_dir())) == -1) {
+		return -1;
+	}
+
+	is_privileged = 0;
+
+	/* version-check the socket */
+
+	request.wb_flags = WBFLAG_RECURSE;
+	if ((winbindd_request_response(WINBINDD_INTERFACE_VERSION, &request, &response) != NSS_STATUS_SUCCESS) || (response.data.interface_version != WINBIND_INTERFACE_VERSION)) {
+		winbind_close_sock();
+		return -1;
+	}
+
+	/* try and get priv pipe */
+
+	request.wb_flags = WBFLAG_RECURSE;
+	if (winbindd_request_response(WINBINDD_PRIV_PIPE_DIR, &request, &response) == NSS_STATUS_SUCCESS) {
+		int fd;
+		if ((fd = winbind_named_pipe_sock((char *)response.extra_data.data)) != -1) {
+			close(winbindd_fd);
+			winbindd_fd = fd;
+			is_privileged = 1;
+		}
+	}
+
+	if ((need_priv != 0) && (is_privileged == 0)) {
+		return -1;
+	}
+
+	SAFE_FREE(response.extra_data.data);
+
+	return winbindd_fd;
+#else
+	return -1;
+#endif /* HAVE_UNIXSOCKET */
+}
+
+/* Write data to winbindd socket */
+
+int winbind_write_sock(void *buffer, int count, int recursing, int need_priv)
+{
+	int result, nwritten;
+
+	/* Open connection to winbind daemon */
+
+ restart:
+
+	if (winbind_open_pipe_sock(recursing, need_priv) == -1) {
+		errno = ENOENT;
+		return -1;
+	}
+
+	/* Write data to socket */
+
+	nwritten = 0;
+
+	while(nwritten < count) {
+		struct timeval tv;
+		fd_set r_fds;
+
+		/* Catch pipe close on other end by checking if a read()
+		   call would not block by calling select(). */
+
+		FD_ZERO(&r_fds);
+		FD_SET(winbindd_fd, &r_fds);
+		ZERO_STRUCT(tv);
+
+		if (select(winbindd_fd + 1, &r_fds, NULL, NULL, &tv) == -1) {
+			winbind_close_sock();
+			return -1;                   /* Select error */
+		}
+
+		/* Write should be OK if fd not available for reading */
+
+		if (!FD_ISSET(winbindd_fd, &r_fds)) {
+
+			/* Do the write */
+
+			result = write(winbindd_fd,
+				       (char *)buffer + nwritten,
+				       count - nwritten);
+
+			if ((result == -1) || (result == 0)) {
+
+				/* Write failed */
+
+				winbind_close_sock();
+				return -1;
+			}
+
+			nwritten += result;
+
+		} else {
+
+			/* Pipe has closed on remote end */
+
+			winbind_close_sock();
+			goto restart;
+		}
+	}
+
+	return nwritten;
+}
+
+/* Read data from winbindd socket */
+
+int winbind_read_sock(void *buffer, int count)
+{
+	int nread = 0;
+	int total_time = 0, selret;
+
+	if (winbindd_fd == -1) {
+		return -1;
+	}
+
+	/* Read data from socket */
+	while(nread < count) {
+		struct timeval tv;
+		fd_set r_fds;
+
+		/* Catch pipe close on other end by checking if a read()
+		   call would not block by calling select(). */
+
+		FD_ZERO(&r_fds);
+		FD_SET(winbindd_fd, &r_fds);
+		ZERO_STRUCT(tv);
+		/* Wait for 5 seconds for a reply. May need to parameterise this... */
+		tv.tv_sec = 5;
+
+		if ((selret = select(winbindd_fd + 1, &r_fds, NULL, NULL, &tv)) == -1) {
+			winbind_close_sock();
+			return -1;                   /* Select error */
+		}
+
+		if (selret == 0) {
+			/* Not ready for read yet... */
+			if (total_time >= 30) {
+				/* Timeout */
+				winbind_close_sock();
+				return -1;
+			}
+			total_time += 5;
+			continue;
+		}
+
+		if (FD_ISSET(winbindd_fd, &r_fds)) {
+
+			/* Do the Read */
+
+			int result = read(winbindd_fd, (char *)buffer + nread,
+			      count - nread);
+
+			if ((result == -1) || (result == 0)) {
+
+				/* Read failed.  I think the only useful thing we
+				   can do here is just return -1 and fail since the
+				   transaction has failed half way through. */
+
+				winbind_close_sock();
+				return -1;
+			}
+
+			nread += result;
+
+		}
+	}
+
+	return nread;
+}
+
+/* Read reply */
+
+int winbindd_read_reply(struct winbindd_response *response)
+{
+	int result1, result2 = 0;
+
+	if (!response) {
+		return -1;
+	}
+
+	/* Read fixed length response */
+
+	result1 = winbind_read_sock(response,
+				    sizeof(struct winbindd_response));
+	if (result1 == -1) {
+		return -1;
+	}
+
+	/* We actually send the pointer value of the extra_data field from
+	   the server.  This has no meaning in the client's address space
+	   so we clear it out. */
+
+	response->extra_data.data = NULL;
+
+	/* Read variable length response */
+
+	if (response->length > sizeof(struct winbindd_response)) {
+		int extra_data_len = response->length -
+			sizeof(struct winbindd_response);
+
+		/* Mallocate memory for extra data */
+
+		if (!(response->extra_data.data = malloc(extra_data_len))) {
+			return -1;
+		}
+
+		result2 = winbind_read_sock(response->extra_data.data,
+					    extra_data_len);
+		if (result2 == -1) {
+			winbindd_free_response(response);
+			return -1;
+		}
+	}
+
+	/* Return total amount of data read */
+
+	return result1 + result2;
+}
+
+/*
+ * send simple types of requests
+ */
+
+NSS_STATUS winbindd_send_request(int req_type, int need_priv,
+				 struct winbindd_request *request)
+{
+	struct winbindd_request lrequest;
+
+	/* Check for our tricky environment variable */
+
+	if (winbind_env_set()) {
+		return NSS_STATUS_NOTFOUND;
+	}
+
+	if (!request) {
+		ZERO_STRUCT(lrequest);
+		request = &lrequest;
+	}
+
+	/* Fill in request and send down pipe */
+
+	winbindd_init_request(request, req_type);
+
+	if (winbind_write_sock(request, sizeof(*request),
+			       request->wb_flags & WBFLAG_RECURSE,
+			       need_priv) == -1)
+	{
+		/* Set ENOENT for consistency.  Required by some apps */
+		errno = ENOENT;
+
+		return NSS_STATUS_UNAVAIL;
+	}
+
+	if ((request->extra_len != 0) &&
+	    (winbind_write_sock(request->extra_data.data,
+				request->extra_len,
+				request->wb_flags & WBFLAG_RECURSE,
+				need_priv) == -1))
+	{
+		/* Set ENOENT for consistency.  Required by some apps */
+		errno = ENOENT;
+
+		return NSS_STATUS_UNAVAIL;
+	}
+
+	return NSS_STATUS_SUCCESS;
+}
+
+/*
+ * Get results from winbindd request
+ */
+
+NSS_STATUS winbindd_get_response(struct winbindd_response *response)
+{
+	struct winbindd_response lresponse;
+
+	if (!response) {
+		ZERO_STRUCT(lresponse);
+		response = &lresponse;
+	}
+
+	init_response(response);
+
+	/* Wait for reply */
+	if (winbindd_read_reply(response) == -1) {
+		/* Set ENOENT for consistency.  Required by some apps */
+		errno = ENOENT;
+
+		return NSS_STATUS_UNAVAIL;
+	}
+
+	/* Throw away extra data if client didn't request it */
+	if (response == &lresponse) {
+		winbindd_free_response(response);
+	}
+
+	/* Copy reply data from socket */
+	if (response->result != WINBINDD_OK) {
+		return NSS_STATUS_NOTFOUND;
+	}
+
+	return NSS_STATUS_SUCCESS;
+}
+
+/* Handle simple types of requests */
+
+NSS_STATUS winbindd_request_response(int req_type,
+			    struct winbindd_request *request,
+			    struct winbindd_response *response)
+{
+	NSS_STATUS status = NSS_STATUS_UNAVAIL;
+	int count = 0;
+
+	while ((status == NSS_STATUS_UNAVAIL) && (count < 10)) {
+		status = winbindd_send_request(req_type, 0, request);
+		if (status != NSS_STATUS_SUCCESS)
+			return(status);
+		status = winbindd_get_response(response);
+		count += 1;
+	}
+
+	return status;
+}
+
+NSS_STATUS winbindd_priv_request_response(int req_type,
+					  struct winbindd_request *request,
+					  struct winbindd_response *response)
+{
+	NSS_STATUS status = NSS_STATUS_UNAVAIL;
+	int count = 0;
+
+	while ((status == NSS_STATUS_UNAVAIL) && (count < 10)) {
+		status = winbindd_send_request(req_type, 1, request);
+		if (status != NSS_STATUS_SUCCESS)
+			return(status);
+		status = winbindd_get_response(response);
+		count += 1;
+	}
+
+	return status;
+}
+
+/*************************************************************************
+ ************************************************************************/
+
+const char *nss_err_str(NSS_STATUS ret)
+{
+	switch (ret) {
+		case NSS_STATUS_TRYAGAIN:
+			return "NSS_STATUS_TRYAGAIN";
+		case NSS_STATUS_SUCCESS:
+			return "NSS_STATUS_SUCCESS";
+		case NSS_STATUS_NOTFOUND:
+			return "NSS_STATUS_NOTFOUND";
+		case NSS_STATUS_UNAVAIL:
+			return "NSS_STATUS_UNAVAIL";
+#ifdef NSS_STATUS_RETURN
+		case NSS_STATUS_RETURN:
+			return "NSS_STATUS_RETURN";
+#endif
+		default:
+			return "UNKNOWN RETURN CODE!!!!!!!";
+	}
+}

=== added directory '.pc/security-CVE-2011-0719.patch/source3'
=== added directory '.pc/security-CVE-2011-0719.patch/source3/client'
=== added file '.pc/security-CVE-2011-0719.patch/source3/client/client.c'
--- .pc/security-CVE-2011-0719.patch/source3/client/client.c	1970-01-01 00:00:00 +0000
+++ .pc/security-CVE-2011-0719.patch/source3/client/client.c	2011-03-02 20:48:44 +0000
@@ -0,0 +1,5041 @@
+/*
+   Unix SMB/CIFS implementation.
+   SMB client
+   Copyright (C) Andrew Tridgell          1994-1998
+   Copyright (C) Simo Sorce               2001-2002
+   Copyright (C) Jelmer Vernooij          2003
+   Copyright (C) Gerald (Jerry) Carter    2004
+   Copyright (C) Jeremy Allison           1994-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 3 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, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "client/client_proto.h"
+#include "../librpc/gen_ndr/cli_srvsvc.h"
+
+#ifndef REGISTER
+#define REGISTER 0
+#endif
+
+extern int do_smb_browse(void); /* mDNS browsing */
+
+extern bool AllowDebugChange;
+extern bool override_logfile;
+extern char tar_type;
+
+static int port = 0;
+static char *service;
+static char *desthost;
+static char *calling_name;
+static bool grepable = false;
+static char *cmdstr = NULL;
+const char *cmd_ptr = NULL;
+
+static int io_bufsize = 524288;
+
+static int name_type = 0x20;
+static int max_protocol = PROTOCOL_NT1;
+
+static int process_tok(char *tok);
+static int cmd_help(void);
+
+#define CREATE_ACCESS_READ READ_CONTROL_ACCESS
+
+/* 30 second timeout on most commands */
+#define CLIENT_TIMEOUT (30*1000)
+#define SHORT_TIMEOUT (5*1000)
+
+/* value for unused fid field in trans2 secondary request */
+#define FID_UNUSED (0xFFFF)
+
+time_t newer_than = 0;
+static int archive_level = 0;
+
+static bool translation = false;
+static bool have_ip;
+
+/* clitar bits insert */
+extern int blocksize;
+extern bool tar_inc;
+extern bool tar_reset;
+/* clitar bits end */
+
+static bool prompt = true;
+
+static bool recurse = false;
+static bool showacls = false;
+bool lowercase = false;
+
+static struct sockaddr_storage dest_ss;
+static char dest_ss_str[INET6_ADDRSTRLEN];
+
+#define SEPARATORS " \t\n\r"
+
+static bool abort_mget = true;
+
+/* timing globals */
+uint64_t get_total_size = 0;
+unsigned int get_total_time_ms = 0;
+static uint64_t put_total_size = 0;
+static unsigned int put_total_time_ms = 0;
+
+/* totals globals */
+static double dir_total;
+
+/* encrypted state. */
+static bool smb_encrypt;
+
+/* root cli_state connection */
+
+struct cli_state *cli;
+
+static char CLI_DIRSEP_CHAR = '\\';
+static char CLI_DIRSEP_STR[] = { '\\', '\0' };
+
+/* Authentication for client connections. */
+struct user_auth_info *auth_info;
+
+/* Accessor functions for directory paths. */
+static char *fileselection;
+static const char *client_get_fileselection(void)
+{
+	if (fileselection) {
+		return fileselection;
+	}
+	return "";
+}
+
+static const char *client_set_fileselection(const char *new_fs)
+{
+	SAFE_FREE(fileselection);
+	if (new_fs) {
+		fileselection = SMB_STRDUP(new_fs);
+	}
+	return client_get_fileselection();
+}
+
+static char *cwd;
+static const char *client_get_cwd(void)
+{
+	if (cwd) {
+		return cwd;
+	}
+	return CLI_DIRSEP_STR;
+}
+
+static const char *client_set_cwd(const char *new_cwd)
+{
+	SAFE_FREE(cwd);
+	if (new_cwd) {
+		cwd = SMB_STRDUP(new_cwd);
+	}
+	return client_get_cwd();
+}
+
+static char *cur_dir;
+const char *client_get_cur_dir(void)
+{
+	if (cur_dir) {
+		return cur_dir;
+	}
+	return CLI_DIRSEP_STR;
+}
+
+const char *client_set_cur_dir(const char *newdir)
+{
+	SAFE_FREE(cur_dir);
+	if (newdir) {
+		cur_dir = SMB_STRDUP(newdir);
+	}
+	return client_get_cur_dir();
+}
+
+/****************************************************************************
+ Write to a local file with CR/LF->LF translation if appropriate. Return the
+ number taken from the buffer. This may not equal the number written.
+****************************************************************************/
+
+static int writefile(int f, char *b, int n)
+{
+	int i;
+
+	if (!translation) {
+		return write(f,b,n);
+	}
+
+	i = 0;
+	while (i < n) {
+		if (*b == '\r' && (i<(n-1)) && *(b+1) == '\n') {
+			b++;i++;
+		}
+		if (write(f, b, 1) != 1) {
+			break;
+		}
+		b++;
+		i++;
+	}
+
+	return(i);
+}
+
+/****************************************************************************
+ Read from a file with LF->CR/LF translation if appropriate. Return the
+ number read. read approx n bytes.
+****************************************************************************/
+
+static int readfile(uint8_t *b, int n, XFILE *f)
+{
+	int i;
+	int c;
+
+	if (!translation)
+		return x_fread(b,1,n,f);
+
+	i = 0;
+	while (i < (n - 1) && (i < BUFFER_SIZE)) {
+		if ((c = x_getc(f)) == EOF) {
+			break;
+		}
+
+		if (c == '\n') { /* change all LFs to CR/LF */
+			b[i++] = '\r';
+		}
+
+		b[i++] = c;
+	}
+
+	return(i);
+}
+
+struct push_state {
+	XFILE *f;
+	SMB_OFF_T nread;
+};
+
+static size_t push_source(uint8_t *buf, size_t n, void *priv)
+{
+	struct push_state *state = (struct push_state *)priv;
+	int result;
+
+	if (x_feof(state->f)) {
+		return 0;
+	}
+
+	result = readfile(buf, n, state->f);
+	state->nread += result;
+	return result;
+}
+
+/****************************************************************************
+ Send a message.
+****************************************************************************/
+
+static void send_message(const char *username)
+{
+	char buf[1600];
+	NTSTATUS status;
+	int i;
+
+	d_printf("Type your message, ending it with a Control-D\n");
+
+	i = 0;
+	while (i<sizeof(buf)-2) {
+		int c = fgetc(stdin);
+		if (c == EOF) {
+			break;
+		}
+		if (c == '\n') {
+			buf[i++] = '\r';
+		}
+		buf[i++] = c;
+	}
+	buf[i] = '\0';
+
+	status = cli_message(cli, desthost, username, buf);
+	if (!NT_STATUS_IS_OK(status)) {
+		d_fprintf(stderr, "cli_message returned %s\n",
+			  nt_errstr(status));
+	}
+}
+
+/****************************************************************************
+ Check the space on a device.
+****************************************************************************/
+
+static int do_dskattr(void)
+{
+	int total, bsize, avail;
+	struct cli_state *targetcli = NULL;
+	char *targetpath = NULL;
+	TALLOC_CTX *ctx = talloc_tos();
+
+	if ( !cli_resolve_path(ctx, "", auth_info, cli, client_get_cur_dir(), &targetcli, &targetpath)) {
+		d_printf("Error in dskattr: %s\n", cli_errstr(cli));
+		return 1;
+	}
+
+	if (!NT_STATUS_IS_OK(cli_dskattr(targetcli, &bsize, &total, &avail))) {
+		d_printf("Error in dskattr: %s\n",cli_errstr(targetcli));
+		return 1;
+	}
+
+	d_printf("\n\t\t%d blocks of size %d. %d blocks available\n",
+		 total, bsize, avail);
+
+	return 0;
+}
+
+/****************************************************************************
+ Show cd/pwd.
+****************************************************************************/
+
+static int cmd_pwd(void)
+{
+	d_printf("Current directory is %s",service);
+	d_printf("%s\n",client_get_cur_dir());
+	return 0;
+}
+
+/****************************************************************************
+ Ensure name has correct directory separators.
+****************************************************************************/
+
+static void normalize_name(char *newdir)
+{
+	if (!(cli->posix_capabilities & CIFS_UNIX_POSIX_PATHNAMES_CAP)) {
+		string_replace(newdir,'/','\\');
+	}
+}
+
+/****************************************************************************
+ Change directory - inner section.
+****************************************************************************/
+
+static int do_cd(const char *new_dir)
+{
+	char *newdir = NULL;
+	char *saved_dir = NULL;
+	char *new_cd = NULL;
+	char *targetpath = NULL;
+	struct cli_state *targetcli = NULL;
+	SMB_STRUCT_STAT sbuf;
+	uint32 attributes;
+	int ret = 1;
+	TALLOC_CTX *ctx = talloc_stackframe();
+
+	newdir = talloc_strdup(ctx, new_dir);
+	if (!newdir) {
+		TALLOC_FREE(ctx);
+		return 1;
+	}
+
+	normalize_name(newdir);
+
+	/* Save the current directory in case the new directory is invalid */
+
+	saved_dir = talloc_strdup(ctx, client_get_cur_dir());
+	if (!saved_dir) {
+		TALLOC_FREE(ctx);
+		return 1;
+	}
+
+	if (*newdir == CLI_DIRSEP_CHAR) {
+		client_set_cur_dir(newdir);
+		new_cd = newdir;
+	} else {
+		new_cd = talloc_asprintf(ctx, "%s%s",
+				client_get_cur_dir(),
+				newdir);
+		if (!new_cd) {
+			goto out;
+		}
+	}
+
+	/* Ensure cur_dir ends in a DIRSEP */
+	if ((new_cd[0] != '\0') && (*(new_cd+strlen(new_cd)-1) != CLI_DIRSEP_CHAR)) {
+		new_cd = talloc_asprintf_append(new_cd, "%s", CLI_DIRSEP_STR);
+		if (!new_cd) {
+			goto out;
+		}
+	}
+	client_set_cur_dir(new_cd);
+
+	new_cd = clean_name(ctx, new_cd);
+	client_set_cur_dir(new_cd);
+
+	if ( !cli_resolve_path(ctx, "", auth_info, cli, new_cd, &targetcli, &targetpath)) {
+		d_printf("cd %s: %s\n", new_cd, cli_errstr(cli));
+		client_set_cur_dir(saved_dir);
+		goto out;
+	}
+
+	if (strequal(targetpath,CLI_DIRSEP_STR )) {
+		TALLOC_FREE(ctx);
+		return 0;
+	}
+
+	/* Use a trans2_qpathinfo to test directories for modern servers.
+	   Except Win9x doesn't support the qpathinfo_basic() call..... */
+
+	if (targetcli->protocol > PROTOCOL_LANMAN2 && !targetcli->win95) {
+		if (!cli_qpathinfo_basic( targetcli, targetpath, &sbuf, &attributes ) ) {
+			d_printf("cd %s: %s\n", new_cd, cli_errstr(targetcli));
+			client_set_cur_dir(saved_dir);
+			goto out;
+		}
+
+		if (!(attributes & FILE_ATTRIBUTE_DIRECTORY)) {
+			d_printf("cd %s: not a directory\n", new_cd);
+			client_set_cur_dir(saved_dir);
+			goto out;
+		}
+	} else {
+		targetpath = talloc_asprintf(ctx,
+				"%s%s",
+				targetpath,
+				CLI_DIRSEP_STR );
+		if (!targetpath) {
+			client_set_cur_dir(saved_dir);
+			goto out;
+		}
+		targetpath = clean_name(ctx, targetpath);
+		if (!targetpath) {
+			client_set_cur_dir(saved_dir);
+			goto out;
+		}
+
+		if (!NT_STATUS_IS_OK(cli_chkpath(targetcli, targetpath))) {
+			d_printf("cd %s: %s\n", new_cd, cli_errstr(targetcli));
+			client_set_cur_dir(saved_dir);
+			goto out;
+		}
+	}
+
+	ret = 0;
+
+out:
+
+	TALLOC_FREE(ctx);
+	return ret;
+}
+
+/****************************************************************************
+ Change directory.
+****************************************************************************/
+
+static int cmd_cd(void)
+{
+	char *buf = NULL;
+	int rc = 0;
+
+	if (next_token_talloc(talloc_tos(), &cmd_ptr, &buf,NULL)) {
+		rc = do_cd(buf);
+	} else {
+		d_printf("Current directory is %s\n",client_get_cur_dir());
+	}
+
+	return rc;
+}
+
+/****************************************************************************
+ Change directory.
+****************************************************************************/
+
+static int cmd_cd_oneup(void)
+{
+	return do_cd("..");
+}
+
+/*******************************************************************
+ Decide if a file should be operated on.
+********************************************************************/
+
+static bool do_this_one(file_info *finfo)
+{
+	if (!finfo->name) {
+		return false;
+	}
+
+	if (finfo->mode & aDIR) {
+		return true;
+	}
+
+	if (*client_get_fileselection() &&
+	    !mask_match(finfo->name,client_get_fileselection(),false)) {
+		DEBUG(3,("mask_match %s failed\n", finfo->name));
+		return false;
+	}
+
+	if (newer_than && finfo->mtime_ts.tv_sec < newer_than) {
+		DEBUG(3,("newer_than %s failed\n", finfo->name));
+		return false;
+	}
+
+	if ((archive_level==1 || archive_level==2) && !(finfo->mode & aARCH)) {
+		DEBUG(3,("archive %s failed\n", finfo->name));
+		return false;
+	}
+
+	return true;
+}
+
+/****************************************************************************
+ Display info about a file.
+****************************************************************************/
+
+static void display_finfo(file_info *finfo, const char *dir)
+{
+	time_t t;
+	TALLOC_CTX *ctx = talloc_tos();
+
+	if (!do_this_one(finfo)) {
+		return;
+	}
+
+	t = finfo->mtime_ts.tv_sec; /* the time is assumed to be passed as GMT */
+	if (!showacls) {
+		d_printf("  %-30s%7.7s %8.0f  %s",
+			 finfo->name,
+			 attrib_string(finfo->mode),
+		 	(double)finfo->size,
+			time_to_asc(t));
+		dir_total += finfo->size;
+	} else {
+		char *afname = NULL;
+		uint16_t fnum;
+
+		/* skip if this is . or .. */
+		if ( strequal(finfo->name,"..") || strequal(finfo->name,".") )
+			return;
+		/* create absolute filename for cli_ntcreate() FIXME */
+		afname = talloc_asprintf(ctx,
+					"%s%s%s",
+					dir,
+					CLI_DIRSEP_STR,
+					finfo->name);
+		if (!afname) {
+			return;
+		}
+		/* print file meta date header */
+		d_printf( "FILENAME:%s\n", finfo->name);
+		d_printf( "MODE:%s\n", attrib_string(finfo->mode));
+		d_printf( "SIZE:%.0f\n", (double)finfo->size);
+		d_printf( "MTIME:%s", time_to_asc(t));
+		if (!NT_STATUS_IS_OK(cli_ntcreate(finfo->cli, afname, 0,
+				CREATE_ACCESS_READ, 0, FILE_SHARE_READ|FILE_SHARE_WRITE,
+				FILE_OPEN, 0x0, 0x0, &fnum))) {
+			DEBUG( 0, ("display_finfo() Failed to open %s: %s\n",
+				afname,
+				cli_errstr( finfo->cli)));
+		} else {
+			SEC_DESC *sd = NULL;
+			sd = cli_query_secdesc(finfo->cli, fnum, ctx);
+			if (!sd) {
+				DEBUG( 0, ("display_finfo() failed to "
+					"get security descriptor: %s",
+					cli_errstr( finfo->cli)));
+			} else {
+				display_sec_desc(sd);
+			}
+			TALLOC_FREE(sd);
+		}
+		TALLOC_FREE(afname);
+	}
+}
+
+/****************************************************************************
+ Accumulate size of a file.
+****************************************************************************/
+
+static void do_du(file_info *finfo, const char *dir)
+{
+	if (do_this_one(finfo)) {
+		dir_total += finfo->size;
+	}
+}
+
+static bool do_list_recurse;
+static bool do_list_dirs;
+static char *do_list_queue = 0;
+static long do_list_queue_size = 0;
+static long do_list_queue_start = 0;
+static long do_list_queue_end = 0;
+static void (*do_list_fn)(file_info *, const char *dir);
+
+/****************************************************************************
+ Functions for do_list_queue.
+****************************************************************************/
+
+/*
+ * The do_list_queue is a NUL-separated list of strings stored in a
+ * char*.  Since this is a FIFO, we keep track of the beginning and
+ * ending locations of the data in the queue.  When we overflow, we
+ * double the size of the char*.  When the start of the data passes
+ * the midpoint, we move everything back.  This is logically more
+ * complex than a linked list, but easier from a memory management
+ * angle.  In any memory error condition, do_list_queue is reset.
+ * Functions check to ensure that do_list_queue is non-NULL before
+ * accessing it.
+ */
+
+static void reset_do_list_queue(void)
+{
+	SAFE_FREE(do_list_queue);
+	do_list_queue_size = 0;
+	do_list_queue_start = 0;
+	do_list_queue_end = 0;
+}
+
+static void init_do_list_queue(void)
+{
+	reset_do_list_queue();
+	do_list_queue_size = 1024;
+	do_list_queue = (char *)SMB_MALLOC(do_list_queue_size);
+	if (do_list_queue == 0) {
+		d_printf("malloc fail for size %d\n",
+			 (int)do_list_queue_size);
+		reset_do_list_queue();
+	} else {
+		memset(do_list_queue, 0, do_list_queue_size);
+	}
+}
+
+static void adjust_do_list_queue(void)
+{
+	/*
+	 * If the starting point of the queue is more than half way through,
+	 * move everything toward the beginning.
+	 */
+
+	if (do_list_queue == NULL) {
+		DEBUG(4,("do_list_queue is empty\n"));
+		do_list_queue_start = do_list_queue_end = 0;
+		return;
+	}
+
+	if (do_list_queue_start == do_list_queue_end) {
+		DEBUG(4,("do_list_queue is empty\n"));
+		do_list_queue_start = do_list_queue_end = 0;
+		*do_list_queue = '\0';
+	} else if (do_list_queue_start > (do_list_queue_size / 2)) {
+		DEBUG(4,("sliding do_list_queue backward\n"));
+		memmove(do_list_queue,
+			do_list_queue + do_list_queue_start,
+			do_list_queue_end - do_list_queue_start);
+		do_list_queue_end -= do_list_queue_start;
+		do_list_queue_start = 0;
+	}
+}
+
+static void add_to_do_list_queue(const char *entry)
+{
+	long new_end = do_list_queue_end + ((long)strlen(entry)) + 1;
+	while (new_end > do_list_queue_size) {
+		do_list_queue_size *= 2;
+		DEBUG(4,("enlarging do_list_queue to %d\n",
+			 (int)do_list_queue_size));
+		do_list_queue = (char *)SMB_REALLOC(do_list_queue, do_list_queue_size);
+		if (! do_list_queue) {
+			d_printf("failure enlarging do_list_queue to %d bytes\n",
+				 (int)do_list_queue_size);
+			reset_do_list_queue();
+		} else {
+			memset(do_list_queue + do_list_queue_size / 2,
+			       0, do_list_queue_size / 2);
+		}
+	}
+	if (do_list_queue) {
+		safe_strcpy_base(do_list_queue + do_list_queue_end,
+				 entry, do_list_queue, do_list_queue_size);
+		do_list_queue_end = new_end;
+		DEBUG(4,("added %s to do_list_queue (start=%d, end=%d)\n",
+			 entry, (int)do_list_queue_start, (int)do_list_queue_end));
+	}
+}
+
+static char *do_list_queue_head(void)
+{
+	return do_list_queue + do_list_queue_start;
+}
+
+static void remove_do_list_queue_head(void)
+{
+	if (do_list_queue_end > do_list_queue_start) {
+		do_list_queue_start += strlen(do_list_queue_head()) + 1;
+		adjust_do_list_queue();
+		DEBUG(4,("removed head of do_list_queue (start=%d, end=%d)\n",
+			 (int)do_list_queue_start, (int)do_list_queue_end));
+	}
+}
+
+static int do_list_queue_empty(void)
+{
+	return (! (do_list_queue && *do_list_queue));
+}
+
+/****************************************************************************
+ A helper for do_list.
+****************************************************************************/
+
+static void do_list_helper(const char *mntpoint, file_info *f, const char *mask, void *state)
+{
+	TALLOC_CTX *ctx = talloc_tos();
+	char *dir = NULL;
+	char *dir_end = NULL;
+
+	/* Work out the directory. */
+	dir = talloc_strdup(ctx, mask);
+	if (!dir) {
+		return;
+	}
+	if ((dir_end = strrchr(dir, CLI_DIRSEP_CHAR)) != NULL) {
+		*dir_end = '\0';
+	}
+
+	if (f->mode & aDIR) {
+		if (do_list_dirs && do_this_one(f)) {
+			do_list_fn(f, dir);
+		}
+		if (do_list_recurse &&
+		    f->name &&
+		    !strequal(f->name,".") &&
+		    !strequal(f->name,"..")) {
+			char *mask2 = NULL;
+			char *p = NULL;
+
+			if (!f->name[0]) {
+				d_printf("Empty dir name returned. Possible server misconfiguration.\n");
+				TALLOC_FREE(dir);
+				return;
+			}
+
+			mask2 = talloc_asprintf(ctx,
+					"%s%s",
+					mntpoint,
+					mask);
+			if (!mask2) {
+				TALLOC_FREE(dir);
+				return;
+			}
+			p = strrchr_m(mask2,CLI_DIRSEP_CHAR);
+			if (p) {
+				p[1] = 0;
+			} else {
+				mask2[0] = '\0';
+			}
+			mask2 = talloc_asprintf_append(mask2,
+					"%s%s*",
+					f->name,
+					CLI_DIRSEP_STR);
+			if (!mask2) {
+				TALLOC_FREE(dir);
+				return;
+			}
+			add_to_do_list_queue(mask2);
+			TALLOC_FREE(mask2);
+		}
+		TALLOC_FREE(dir);
+		return;
+	}
+
+	if (do_this_one(f)) {
+		do_list_fn(f,dir);
+	}
+	TALLOC_FREE(dir);
+}
+
+/****************************************************************************
+ A wrapper around cli_list that adds recursion.
+****************************************************************************/
+
+void do_list(const char *mask,
+			uint16 attribute,
+			void (*fn)(file_info *, const char *dir),
+			bool rec,
+			bool dirs)
+{
+	static int in_do_list = 0;
+	TALLOC_CTX *ctx = talloc_tos();
+	struct cli_state *targetcli = NULL;
+	char *targetpath = NULL;
+
+	if (in_do_list && rec) {
+		fprintf(stderr, "INTERNAL ERROR: do_list called recursively when the recursive flag is true\n");
+		exit(1);
+	}
+
+	in_do_list = 1;
+
+	do_list_recurse = rec;
+	do_list_dirs = dirs;
+	do_list_fn = fn;
+
+	if (rec) {
+		init_do_list_queue();
+		add_to_do_list_queue(mask);
+
+		while (!do_list_queue_empty()) {
+			/*
+			 * Need to copy head so that it doesn't become
+			 * invalid inside the call to cli_list.  This
+			 * would happen if the list were expanded
+			 * during the call.
+			 * Fix from E. Jay Berkenbilt (ejb@ql.org)
+			 */
+			char *head = talloc_strdup(ctx, do_list_queue_head());
+
+			if (!head) {
+				return;
+			}
+
+			/* check for dfs */
+
+			if ( !cli_resolve_path(ctx, "", auth_info, cli, head, &targetcli, &targetpath ) ) {
+				d_printf("do_list: [%s] %s\n", head, cli_errstr(cli));
+				remove_do_list_queue_head();
+				continue;
+			}
+
+			cli_list(targetcli, targetpath, attribute, do_list_helper, NULL);
+			remove_do_list_queue_head();
+			if ((! do_list_queue_empty()) && (fn == display_finfo)) {
+				char *next_file = do_list_queue_head();
+				char *save_ch = 0;
+				if ((strlen(next_file) >= 2) &&
+				    (next_file[strlen(next_file) - 1] == '*') &&
+				    (next_file[strlen(next_file) - 2] == CLI_DIRSEP_CHAR)) {
+					save_ch = next_file +
+						strlen(next_file) - 2;
+					*save_ch = '\0';
+					if (showacls) {
+						/* cwd is only used if showacls is on */
+						client_set_cwd(next_file);
+					}
+				}
+				if (!showacls) /* don't disturbe the showacls output */
+					d_printf("\n%s\n",next_file);
+				if (save_ch) {
+					*save_ch = CLI_DIRSEP_CHAR;
+				}
+			}
+			TALLOC_FREE(head);
+			TALLOC_FREE(targetpath);
+		}
+	} else {
+		/* check for dfs */
+		if (cli_resolve_path(ctx, "", auth_info, cli, mask, &targetcli, &targetpath)) {
+			if (cli_list(targetcli, targetpath, attribute, do_list_helper, NULL) == -1) {
+				d_printf("%s listing %s\n",
+					cli_errstr(targetcli), targetpath);
+			}
+			TALLOC_FREE(targetpath);
+		} else {
+			d_printf("do_list: [%s] %s\n", mask, cli_errstr(cli));
+		}
+	}
+
+	in_do_list = 0;
+	reset_do_list_queue();
+}
+
+/****************************************************************************
+ Get a directory listing.
+****************************************************************************/
+
+static int cmd_dir(void)
+{
+	TALLOC_CTX *ctx = talloc_tos();
+	uint16 attribute = aDIR | aSYSTEM | aHIDDEN;
+	char *mask = NULL;
+	char *buf = NULL;
+	int rc = 1;
+
+	dir_total = 0;
+	mask = talloc_strdup(ctx, client_get_cur_dir());
+	if (!mask) {
+		return 1;
+	}
+
+	if (next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
+		normalize_name(buf);
+		if (*buf == CLI_DIRSEP_CHAR) {
+			mask = talloc_strdup(ctx, buf);
+		} else {
+			mask = talloc_asprintf_append(mask, "%s", buf);
+		}
+	} else {
+		mask = talloc_asprintf_append(mask, "*");
+	}
+	if (!mask) {
+		return 1;
+	}
+
+	if (showacls) {
+		/* cwd is only used if showacls is on */
+		client_set_cwd(client_get_cur_dir());
+	}
+
+	do_list(mask, attribute, display_finfo, recurse, true);
+
+	rc = do_dskattr();
+
+	DEBUG(3, ("Total bytes listed: %.0f\n", dir_total));
+
+	return rc;
+}
+
+/****************************************************************************
+ Get a directory listing.
+****************************************************************************/
+
+static int cmd_du(void)
+{
+	TALLOC_CTX *ctx = talloc_tos();
+	uint16 attribute = aDIR | aSYSTEM | aHIDDEN;
+	char *mask = NULL;
+	char *buf = NULL;
+	int rc = 1;
+
+	dir_total = 0;
+	mask = talloc_strdup(ctx, client_get_cur_dir());
+	if (!mask) {
+		return 1;
+	}
+	if ((mask[0] != '\0') && (mask[strlen(mask)-1]!=CLI_DIRSEP_CHAR)) {
+		mask = talloc_asprintf_append(mask, "%s", CLI_DIRSEP_STR);
+		if (!mask) {
+			return 1;
+		}
+	}
+
+	if (next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
+		normalize_name(buf);
+		if (*buf == CLI_DIRSEP_CHAR) {
+			mask = talloc_strdup(ctx, buf);
+		} else {
+			mask = talloc_asprintf_append(mask, "%s", buf);
+		}
+	} else {
+		mask = talloc_strdup(ctx, "*");
+	}
+
+	do_list(mask, attribute, do_du, recurse, true);
+
+	rc = do_dskattr();
+
+	d_printf("Total number of bytes: %.0f\n", dir_total);
+
+	return rc;
+}
+
+static int cmd_echo(void)
+{
+	TALLOC_CTX *ctx = talloc_tos();
+	char *num;
+	char *data;
+	NTSTATUS status;
+
+	if (!next_token_talloc(ctx, &cmd_ptr, &num, NULL)
+	    || !next_token_talloc(ctx, &cmd_ptr, &data, NULL)) {
+		d_printf("echo <num> <data>\n");
+		return 1;
+	}
+
+	status = cli_echo(cli, atoi(num), data_blob_const(data, strlen(data)));
+
+	if (!NT_STATUS_IS_OK(status)) {
+		d_printf("echo failed: %s\n", nt_errstr(status));
+		return 1;
+	}
+
+	return 0;
+}
+
+/****************************************************************************
+ Get a file from rname to lname
+****************************************************************************/
+
+static NTSTATUS writefile_sink(char *buf, size_t n, void *priv)
+{
+	int *pfd = (int *)priv;
+	if (writefile(*pfd, buf, n) == -1) {
+		return map_nt_error_from_unix(errno);
+	}
+	return NT_STATUS_OK;
+}
+
+static int do_get(const char *rname, const char *lname_in, bool reget)
+{
+	TALLOC_CTX *ctx = talloc_tos();
+	int handle = 0;
+	uint16_t fnum;
+	bool newhandle = false;
+	struct timeval tp_start;
+	uint16 attr;
+	SMB_OFF_T size;
+	off_t start = 0;
+	SMB_OFF_T nread = 0;
+	int rc = 0;
+	struct cli_state *targetcli = NULL;
+	char *targetname = NULL;
+	char *lname = NULL;
+	NTSTATUS status;
+
+	lname = talloc_strdup(ctx, lname_in);
+	if (!lname) {
+		return 1;
+	}
+
+	if (lowercase) {
+		strlower_m(lname);
+	}
+
+	if (!cli_resolve_path(ctx, "", auth_info, cli, rname, &targetcli, &targetname ) ) {
+		d_printf("Failed to open %s: %s\n", rname, cli_errstr(cli));
+		return 1;
+	}
+
+	GetTimeOfDay(&tp_start);
+
+	if (!NT_STATUS_IS_OK(cli_open(targetcli, targetname, O_RDONLY, DENY_NONE, &fnum))) {
+		d_printf("%s opening remote file %s\n",cli_errstr(cli),rname);
+		return 1;
+	}
+
+	if(!strcmp(lname,"-")) {
+		handle = fileno(stdout);
+	} else {
+		if (reget) {
+			handle = sys_open(lname, O_WRONLY|O_CREAT, 0644);
+			if (handle >= 0) {
+				start = sys_lseek(handle, 0, SEEK_END);
+				if (start == -1) {
+					d_printf("Error seeking local file\n");
+					return 1;
+				}
+			}
+		} else {
+			handle = sys_open(lname, O_WRONLY|O_CREAT|O_TRUNC, 0644);
+		}
+		newhandle = true;
+	}
+	if (handle < 0) {
+		d_printf("Error opening local file %s\n",lname);
+		return 1;
+	}
+
+
+	if (!cli_qfileinfo(targetcli, fnum,
+			   &attr, &size, NULL, NULL, NULL, NULL, NULL) &&
+	    !NT_STATUS_IS_OK(cli_getattrE(targetcli, fnum,
+			  &attr, &size, NULL, NULL, NULL))) {
+		d_printf("getattrib: %s\n",cli_errstr(targetcli));
+		return 1;
+	}
+
+	DEBUG(1,("getting file %s of size %.0f as %s ",
+		 rname, (double)size, lname));
+
+	status = cli_pull(targetcli, fnum, start, size, io_bufsize,
+			  writefile_sink, (void *)&handle, &nread);
+	if (!NT_STATUS_IS_OK(status)) {
+		d_fprintf(stderr, "parallel_read returned %s\n",
+			  nt_errstr(status));
+		cli_close(targetcli, fnum);
+		return 1;
+	}
+
+	if (!NT_STATUS_IS_OK(cli_close(targetcli, fnum))) {
+		d_printf("Error %s closing remote file\n",cli_errstr(cli));
+		rc = 1;
+	}
+
+	if (newhandle) {
+		close(handle);
+	}
+
+	if (archive_level >= 2 && (attr & aARCH)) {
+		cli_setatr(cli, rname, attr & ~(uint16)aARCH, 0);
+	}
+
+	{
+		struct timeval tp_end;
+		int this_time;
+
+		GetTimeOfDay(&tp_end);
+		this_time =
+			(tp_end.tv_sec - tp_start.tv_sec)*1000 +
+			(tp_end.tv_usec - tp_start.tv_usec)/1000;
+		get_total_time_ms += this_time;
+		get_total_size += nread;
+
+		DEBUG(1,("(%3.1f KiloBytes/sec) (average %3.1f KiloBytes/sec)\n",
+			 nread / (1.024*this_time + 1.0e-4),
+			 get_total_size / (1.024*get_total_time_ms)));
+	}
+
+	TALLOC_FREE(targetname);
+	return rc;
+}
+
+/****************************************************************************
+ Get a file.
+****************************************************************************/
+
+static int cmd_get(void)
+{
+	TALLOC_CTX *ctx = talloc_tos();
+	char *lname = NULL;
+	char *rname = NULL;
+	char *fname = NULL;
+
+	rname = talloc_strdup(ctx, client_get_cur_dir());
+	if (!rname) {
+		return 1;
+	}
+
+	if (!next_token_talloc(ctx, &cmd_ptr,&fname,NULL)) {
+		d_printf("get <filename> [localname]\n");
+		return 1;
+	}
+	rname = talloc_asprintf_append(rname, "%s", fname);
+	if (!rname) {
+		return 1;
+	}
+	rname = clean_name(ctx, rname);
+	if (!rname) {
+		return 1;
+	}
+
+	next_token_talloc(ctx, &cmd_ptr,&lname,NULL);
+	if (!lname) {
+		lname = fname;
+	}
+
+	return do_get(rname, lname, false);
+}
+
+/****************************************************************************
+ Do an mget operation on one file.
+****************************************************************************/
+
+static void do_mget(file_info *finfo, const char *dir)
+{
+	TALLOC_CTX *ctx = talloc_tos();
+	char *rname = NULL;
+	char *quest = NULL;
+	char *saved_curdir = NULL;
+	char *mget_mask = NULL;
+	char *new_cd = NULL;
+
+	if (!finfo->name) {
+		return;
+	}
+
+	if (strequal(finfo->name,".") || strequal(finfo->name,".."))
+		return;
+
+	if (abort_mget)	{
+		d_printf("mget aborted\n");
+		return;
+	}
+
+	if (finfo->mode & aDIR) {
+		if (asprintf(&quest,
+			 "Get directory %s? ",finfo->name) < 0) {
+			return;
+		}
+	} else {
+		if (asprintf(&quest,
+			 "Get file %s? ",finfo->name) < 0) {
+			return;
+		}
+	}
+
+	if (prompt && !yesno(quest)) {
+		SAFE_FREE(quest);
+		return;
+	}
+	SAFE_FREE(quest);
+
+	if (!(finfo->mode & aDIR)) {
+		rname = talloc_asprintf(ctx,
+				"%s%s",
+				client_get_cur_dir(),
+				finfo->name);
+		if (!rname) {
+			return;
+		}
+		do_get(rname, finfo->name, false);
+		TALLOC_FREE(rname);
+		return;
+	}
+
+	/* handle directories */
+	saved_curdir = talloc_strdup(ctx, client_get_cur_dir());
+	if (!saved_curdir) {
+		return;
+	}
+
+	new_cd = talloc_asprintf(ctx,
+				"%s%s%s",
+				client_get_cur_dir(),
+				finfo->name,
+				CLI_DIRSEP_STR);
+	if (!new_cd) {
+		return;
+	}
+	client_set_cur_dir(new_cd);
+
+	string_replace(finfo->name,'\\','/');
+	if (lowercase) {
+		strlower_m(finfo->name);
+	}
+
+	if (!directory_exist(finfo->name) &&
+	    mkdir(finfo->name,0777) != 0) {
+		d_printf("failed to create directory %s\n",finfo->name);
+		client_set_cur_dir(saved_curdir);
+		return;
+	}
+
+	if (chdir(finfo->name) != 0) {
+		d_printf("failed to chdir to directory %s\n",finfo->name);
+		client_set_cur_dir(saved_curdir);
+		return;
+	}
+
+	mget_mask = talloc_asprintf(ctx,
+			"%s*",
+			client_get_cur_dir());
+
+	if (!mget_mask) {
+		return;
+	}
+
+	do_list(mget_mask, aSYSTEM | aHIDDEN | aDIR,do_mget,false, true);
+	if (chdir("..") == -1) {
+		d_printf("do_mget: failed to chdir to .. (error %s)\n",
+			strerror(errno) );
+	}
+	client_set_cur_dir(saved_curdir);
+	TALLOC_FREE(mget_mask);
+	TALLOC_FREE(saved_curdir);
+	TALLOC_FREE(new_cd);
+}
+
+/****************************************************************************
+ View the file using the pager.
+****************************************************************************/
+
+static int cmd_more(void)
+{
+	TALLOC_CTX *ctx = talloc_tos();
+	char *rname = NULL;
+	char *fname = NULL;
+	char *lname = NULL;
+	char *pager_cmd = NULL;
+	const char *pager;
+	int fd;
+	int rc = 0;
+
+	rname = talloc_strdup(ctx, client_get_cur_dir());
+	if (!rname) {
+		return 1;
+	}
+
+	lname = talloc_asprintf(ctx, "%s/smbmore.XXXXXX",tmpdir());
+	if (!lname) {
+		return 1;
+	}
+	fd = mkstemp(lname);
+	if (fd == -1) {
+		d_printf("failed to create temporary file for more\n");
+		return 1;
+	}
+	close(fd);
+
+	if (!next_token_talloc(ctx, &cmd_ptr,&fname,NULL)) {
+		d_printf("more <filename>\n");
+		unlink(lname);
+		return 1;
+	}
+	rname = talloc_asprintf_append(rname, "%s", fname);
+	if (!rname) {
+		return 1;
+	}
+	rname = clean_name(ctx,rname);
+	if (!rname) {
+		return 1;
+	}
+
+	rc = do_get(rname, lname, false);
+
+	pager=getenv("PAGER");
+
+	pager_cmd = talloc_asprintf(ctx,
+				"%s %s",
+				(pager? pager:PAGER),
+				lname);
+	if (!pager_cmd) {
+		return 1;
+	}
+	if (system(pager_cmd) == -1) {
+		d_printf("system command '%s' returned -1\n",
+			pager_cmd);
+	}
+	unlink(lname);
+
+	return rc;
+}
+
+/****************************************************************************
+ Do a mget command.
+****************************************************************************/
+
+static int cmd_mget(void)
+{
+	TALLOC_CTX *ctx = talloc_tos();
+	uint16 attribute = aSYSTEM | aHIDDEN;
+	char *mget_mask = NULL;
+	char *buf = NULL;
+
+	if (recurse) {
+		attribute |= aDIR;
+	}
+
+	abort_mget = false;
+
+	while (next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
+		mget_mask = talloc_strdup(ctx, client_get_cur_dir());
+		if (!mget_mask) {
+			return 1;
+		}
+		if (*buf == CLI_DIRSEP_CHAR) {
+			mget_mask = talloc_strdup(ctx, buf);
+		} else {
+			mget_mask = talloc_asprintf_append(mget_mask,
+							"%s", buf);
+		}
+		if (!mget_mask) {
+			return 1;
+		}
+		do_list(mget_mask, attribute, do_mget, false, true);
+	}
+
+	if (mget_mask == NULL) {
+		d_printf("nothing to mget\n");
+		return 0;
+	}
+
+	if (!*mget_mask) {
+		mget_mask = talloc_asprintf(ctx,
+					"%s*",
+					client_get_cur_dir());
+		if (!mget_mask) {
+			return 1;
+		}
+		do_list(mget_mask, attribute, do_mget, false, true);
+	}
+
+	return 0;
+}
+
+/****************************************************************************
+ Make a directory of name "name".
+****************************************************************************/
+
+static bool do_mkdir(const char *name)
+{
+	TALLOC_CTX *ctx = talloc_tos();
+	struct cli_state *targetcli;
+	char *targetname = NULL;
+
+	if (!cli_resolve_path(ctx, "", auth_info, cli, name, &targetcli, &targetname)) {
+		d_printf("mkdir %s: %s\n", name, cli_errstr(cli));
+		return false;
+	}
+
+	if (!NT_STATUS_IS_OK(cli_mkdir(targetcli, targetname))) {
+		d_printf("%s making remote directory %s\n",
+			 cli_errstr(targetcli),name);
+		return false;
+	}
+
+	return true;
+}
+
+/****************************************************************************
+ Show 8.3 name of a file.
+****************************************************************************/
+
+static bool do_altname(const char *name)
+{
+	fstring altname;
+
+	if (!NT_STATUS_IS_OK(cli_qpathinfo_alt_name(cli, name, altname))) {
+		d_printf("%s getting alt name for %s\n",
+			 cli_errstr(cli),name);
+		return false;
+	}
+	d_printf("%s\n", altname);
+
+	return true;
+}
+
+/****************************************************************************
+ Exit client.
+****************************************************************************/
+
+static int cmd_quit(void)
+{
+	cli_shutdown(cli);
+	exit(0);
+	/* NOTREACHED */
+	return 0;
+}
+
+/****************************************************************************
+ Make a directory.
+****************************************************************************/
+
+static int cmd_mkdir(void)
+{
+	TALLOC_CTX *ctx = talloc_tos();
+	char *mask = NULL;
+	char *buf = NULL;
+
+	mask = talloc_strdup(ctx, client_get_cur_dir());
+	if (!mask) {
+		return 1;
+	}
+
+	if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
+		if (!recurse) {
+			d_printf("mkdir <dirname>\n");
+		}
+		return 1;
+	}
+	mask = talloc_asprintf_append(mask, "%s", buf);
+	if (!mask) {
+		return 1;
+	}
+
+	if (recurse) {
+		char *ddir = NULL;
+		char *ddir2 = NULL;
+		struct cli_state *targetcli;
+		char *targetname = NULL;
+		char *p = NULL;
+		char *saveptr;
+
+		ddir2 = talloc_strdup(ctx, "");
+		if (!ddir2) {
+			return 1;
+		}
+
+		if (!cli_resolve_path(ctx, "", auth_info, cli, mask, &targetcli, &targetname)) {
+			return 1;
+		}
+
+		ddir = talloc_strdup(ctx, targetname);
+		if (!ddir) {
+			return 1;
+		}
+		trim_char(ddir,'.','\0');
+		p = strtok_r(ddir, "/\\", &saveptr);
+		while (p) {
+			ddir2 = talloc_asprintf_append(ddir2, "%s", p);
+			if (!ddir2) {
+				return 1;
+			}
+			if (!NT_STATUS_IS_OK(cli_chkpath(targetcli, ddir2))) {
+				do_mkdir(ddir2);
+			}
+			ddir2 = talloc_asprintf_append(ddir2, "%s", CLI_DIRSEP_STR);
+			if (!ddir2) {
+				return 1;
+			}
+			p = strtok_r(NULL, "/\\", &saveptr);
+		}
+	} else {
+		do_mkdir(mask);
+	}
+
+	return 0;
+}
+
+/****************************************************************************
+ Show alt name.
+****************************************************************************/
+
+static int cmd_altname(void)
+{
+	TALLOC_CTX *ctx = talloc_tos();
+	char *name;
+	char *buf;
+
+	name = talloc_strdup(ctx, client_get_cur_dir());
+	if (!name) {
+		return 1;
+	}
+
+	if (!next_token_talloc(ctx, &cmd_ptr, &buf, NULL)) {
+		d_printf("altname <file>\n");
+		return 1;
+	}
+	name = talloc_asprintf_append(name, "%s", buf);
+	if (!name) {
+		return 1;
+	}
+	do_altname(name);
+	return 0;
+}
+
+/****************************************************************************
+ Show all info we can get
+****************************************************************************/
+
+static int do_allinfo(const char *name)
+{
+	fstring altname;
+	struct timespec b_time, a_time, m_time, c_time;
+	SMB_OFF_T size;
+	uint16_t mode;
+	SMB_INO_T ino;
+	NTTIME tmp;
+	unsigned int num_streams;
+	struct stream_struct *streams;
+	unsigned int i;
+
+	if (!NT_STATUS_IS_OK(cli_qpathinfo_alt_name(cli, name, altname))) {
+		d_printf("%s getting alt name for %s\n",
+			 cli_errstr(cli),name);
+		return false;
+	}
+	d_printf("altname: %s\n", altname);
+
+	if (!cli_qpathinfo2(cli, name, &b_time, &a_time, &m_time, &c_time,
+			    &size, &mode, &ino)) {
+		d_printf("%s getting pathinfo for %s\n",
+			 cli_errstr(cli),name);
+		return false;
+	}
+
+	unix_timespec_to_nt_time(&tmp, b_time);
+	d_printf("create_time:    %s\n", nt_time_string(talloc_tos(), tmp));
+
+	unix_timespec_to_nt_time(&tmp, a_time);
+	d_printf("access_time:    %s\n", nt_time_string(talloc_tos(), tmp));
+
+	unix_timespec_to_nt_time(&tmp, m_time);
+	d_printf("write_time:     %s\n", nt_time_string(talloc_tos(), tmp));
+
+	unix_timespec_to_nt_time(&tmp, c_time);
+	d_printf("change_time:    %s\n", nt_time_string(talloc_tos(), tmp));
+
+	if (!cli_qpathinfo_streams(cli, name, talloc_tos(), &num_streams,
+				   &streams)) {
+		d_printf("%s getting streams for %s\n",
+			 cli_errstr(cli),name);
+		return false;
+	}
+
+	for (i=0; i<num_streams; i++) {
+		d_printf("stream: [%s], %lld bytes\n", streams[i].name,
+			 (unsigned long long)streams[i].size);
+	}
+
+	return 0;
+}
+
+/****************************************************************************
+ Show all info we can get
+****************************************************************************/
+
+static int cmd_allinfo(void)
+{
+	TALLOC_CTX *ctx = talloc_tos();
+	char *name;
+	char *buf;
+
+	name = talloc_strdup(ctx, client_get_cur_dir());
+	if (!name) {
+		return 1;
+	}
+
+	if (!next_token_talloc(ctx, &cmd_ptr, &buf, NULL)) {
+		d_printf("allinfo <file>\n");
+		return 1;
+	}
+	name = talloc_asprintf_append(name, "%s", buf);
+	if (!name) {
+		return 1;
+	}
+
+	do_allinfo(name);
+
+	return 0;
+}
+
+/****************************************************************************
+ Put a single file.
+****************************************************************************/
+
+static int do_put(const char *rname, const char *lname, bool reput)
+{
+	TALLOC_CTX *ctx = talloc_tos();
+	uint16_t fnum;
+	XFILE *f;
+	SMB_OFF_T start = 0;
+	int rc = 0;
+	struct timeval tp_start;
+	struct cli_state *targetcli;
+	char *targetname = NULL;
+	struct push_state state;
+	NTSTATUS status;
+
+	if (!cli_resolve_path(ctx, "", auth_info, cli, rname, &targetcli, &targetname)) {
+		d_printf("Failed to open %s: %s\n", rname, cli_errstr(cli));
+		return 1;
+	}
+
+	GetTimeOfDay(&tp_start);
+
+	if (reput) {
+		status = cli_open(targetcli, targetname, O_RDWR|O_CREAT, DENY_NONE, &fnum);
+		if (NT_STATUS_IS_OK(status)) {
+			if (!cli_qfileinfo(targetcli, fnum, NULL, &start, NULL, NULL, NULL, NULL, NULL) &&
+			    !NT_STATUS_IS_OK(cli_getattrE(targetcli, fnum, NULL, &start, NULL, NULL, NULL))) {
+				d_printf("getattrib: %s\n",cli_errstr(cli));
+				return 1;
+			}
+		}
+	} else {
+		status = cli_open(targetcli, targetname, O_RDWR|O_CREAT|O_TRUNC, DENY_NONE, &fnum);
+	}
+
+	if (!NT_STATUS_IS_OK(status)) {
+		d_printf("%s opening remote file %s\n",cli_errstr(targetcli),rname);
+		return 1;
+	}
+
+	/* allow files to be piped into smbclient
+	   jdblair 24.jun.98
+
+	   Note that in this case this function will exit(0) rather
+	   than returning. */
+	if (!strcmp(lname, "-")) {
+		f = x_stdin;
+		/* size of file is not known */
+	} else {
+		f = x_fopen(lname,O_RDONLY, 0);
+		if (f && reput) {
+			if (x_tseek(f, start, SEEK_SET) == -1) {
+				d_printf("Error seeking local file\n");
+				x_fclose(f);
+				return 1;
+			}
+		}
+	}
+
+	if (!f) {
+		d_printf("Error opening local file %s\n",lname);
+		return 1;
+	}
+
+	DEBUG(1,("putting file %s as %s ",lname,
+		 rname));
+
+	x_setvbuf(f, NULL, X_IOFBF, io_bufsize);
+
+	state.f = f;
+	state.nread = 0;
+
+	status = cli_push(targetcli, fnum, 0, 0, io_bufsize, push_source,
+			  &state);
+	if (!NT_STATUS_IS_OK(status)) {
+		d_fprintf(stderr, "cli_push returned %s\n", nt_errstr(status));
+	}
+
+	if (!NT_STATUS_IS_OK(cli_close(targetcli, fnum))) {
+		d_printf("%s closing remote file %s\n",cli_errstr(cli),rname);
+		if (f != x_stdin) {
+			x_fclose(f);
+		}
+		return 1;
+	}
+
+	if (f != x_stdin) {
+		x_fclose(f);
+	}
+
+	{
+		struct timeval tp_end;
+		int this_time;
+
+		GetTimeOfDay(&tp_end);
+		this_time =
+			(tp_end.tv_sec - tp_start.tv_sec)*1000 +
+			(tp_end.tv_usec - tp_start.tv_usec)/1000;
+		put_total_time_ms += this_time;
+		put_total_size += state.nread;
+
+		DEBUG(1,("(%3.1f kb/s) (average %3.1f kb/s)\n",
+			 state.nread / (1.024*this_time + 1.0e-4),
+			 put_total_size / (1.024*put_total_time_ms)));
+	}
+
+	if (f == x_stdin) {
+		cli_shutdown(cli);
+		exit(0);
+	}
+
+	return rc;
+}
+
+/****************************************************************************
+ Put a file.
+****************************************************************************/
+
+static int cmd_put(void)
+{
+	TALLOC_CTX *ctx = talloc_tos();
+	char *lname;
+	char *rname;
+	char *buf;
+
+	rname = talloc_strdup(ctx, client_get_cur_dir());
+	if (!rname) {
+		return 1;
+	}
+
+	if (!next_token_talloc(ctx, &cmd_ptr,&lname,NULL)) {
+		d_printf("put <filename>\n");
+		return 1;
+	}
+
+	if (next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
+		rname = talloc_asprintf_append(rname, "%s", buf);
+	} else {
+		rname = talloc_asprintf_append(rname, "%s", lname);
+	}
+	if (!rname) {
+		return 1;
+	}
+
+	rname = clean_name(ctx, rname);
+	if (!rname) {
+		return 1;
+	}
+
+	{
+		SMB_STRUCT_STAT st;
+		/* allow '-' to represent stdin
+		   jdblair, 24.jun.98 */
+		if (!file_exist_stat(lname, &st, false) &&
+		    (strcmp(lname,"-"))) {
+			d_printf("%s does not exist\n",lname);
+			return 1;
+		}
+	}
+
+	return do_put(rname, lname, false);
+}
+
+/*************************************
+ File list structure.
+*************************************/
+
+static struct file_list {
+	struct file_list *prev, *next;
+	char *file_path;
+	bool isdir;
+} *file_list;
+
+/****************************************************************************
+ Free a file_list structure.
+****************************************************************************/
+
+static void free_file_list (struct file_list *l_head)
+{
+	struct file_list *list, *next;
+
+	for (list = l_head; list; list = next) {
+		next = list->next;
+		DLIST_REMOVE(l_head, list);
+		SAFE_FREE(list->file_path);
+		SAFE_FREE(list);
+	}
+}
+
+/****************************************************************************
+ Seek in a directory/file list until you get something that doesn't start with
+ the specified name.
+****************************************************************************/
+
+static bool seek_list(struct file_list *list, char *name)
+{
+	while (list) {
+		trim_string(list->file_path,"./","\n");
+		if (strncmp(list->file_path, name, strlen(name)) != 0) {
+			return true;
+		}
+		list = list->next;
+	}
+
+	return false;
+}
+
+/****************************************************************************
+ Set the file selection mask.
+****************************************************************************/
+
+static int cmd_select(void)
+{
+	TALLOC_CTX *ctx = talloc_tos();
+	char *new_fs = NULL;
+	next_token_talloc(ctx, &cmd_ptr,&new_fs,NULL)
+		;
+	if (new_fs) {
+		client_set_fileselection(new_fs);
+	} else {
+		client_set_fileselection("");
+	}
+	return 0;
+}
+
+/****************************************************************************
+  Recursive file matching function act as find
+  match must be always set to true when calling this function
+****************************************************************************/
+
+static int file_find(struct file_list **list, const char *directory,
+		      const char *expression, bool match)
+{
+	SMB_STRUCT_DIR *dir;
+	struct file_list *entry;
+        struct stat statbuf;
+        int ret;
+        char *path;
+	bool isdir;
+	const char *dname;
+
+        dir = sys_opendir(directory);
+	if (!dir)
+		return -1;
+
+        while ((dname = readdirname(dir))) {
+		if (!strcmp("..", dname))
+			continue;
+		if (!strcmp(".", dname))
+			continue;
+
+		if (asprintf(&path, "%s/%s", directory, dname) <= 0) {
+			continue;
+		}
+
+		isdir = false;
+		if (!match || !gen_fnmatch(expression, dname)) {
+			if (recurse) {
+				ret = stat(path, &statbuf);
+				if (ret == 0) {
+					if (S_ISDIR(statbuf.st_mode)) {
+						isdir = true;
+						ret = file_find(list, path, expression, false);
+					}
+				} else {
+					d_printf("file_find: cannot stat file %s\n", path);
+				}
+
+				if (ret == -1) {
+					SAFE_FREE(path);
+					sys_closedir(dir);
+					return -1;
+				}
+			}
+			entry = SMB_MALLOC_P(struct file_list);
+			if (!entry) {
+				d_printf("Out of memory in file_find\n");
+				sys_closedir(dir);
+				return -1;
+			}
+			entry->file_path = path;
+			entry->isdir = isdir;
+                        DLIST_ADD(*list, entry);
+		} else {
+			SAFE_FREE(path);
+		}
+        }
+
+	sys_closedir(dir);
+	return 0;
+}
+
+/****************************************************************************
+ mput some files.
+****************************************************************************/
+
+static int cmd_mput(void)
+{
+	TALLOC_CTX *ctx = talloc_tos();
+	char *p = NULL;
+
+	while (next_token_talloc(ctx, &cmd_ptr,&p,NULL)) {
+		int ret;
+		struct file_list *temp_list;
+		char *quest, *lname, *rname;
+
+		file_list = NULL;
+
+		ret = file_find(&file_list, ".", p, true);
+		if (ret) {
+			free_file_list(file_list);
+			continue;
+		}
+
+		quest = NULL;
+		lname = NULL;
+		rname = NULL;
+
+		for (temp_list = file_list; temp_list;
+		     temp_list = temp_list->next) {
+
+			SAFE_FREE(lname);
+			if (asprintf(&lname, "%s/", temp_list->file_path) <= 0) {
+				continue;
+			}
+			trim_string(lname, "./", "/");
+
+			/* check if it's a directory */
+			if (temp_list->isdir) {
+				/* if (!recurse) continue; */
+
+				SAFE_FREE(quest);
+				if (asprintf(&quest, "Put directory %s? ", lname) < 0) {
+					break;
+				}
+				if (prompt && !yesno(quest)) { /* No */
+					/* Skip the directory */
+					lname[strlen(lname)-1] = '/';
+					if (!seek_list(temp_list, lname))
+						break;
+				} else { /* Yes */
+	      				SAFE_FREE(rname);
+					if(asprintf(&rname, "%s%s", client_get_cur_dir(), lname) < 0) {
+						break;
+					}
+					normalize_name(rname);
+					if (!NT_STATUS_IS_OK(cli_chkpath(cli, rname)) &&
+					    !do_mkdir(rname)) {
+						DEBUG (0, ("Unable to make dir, skipping..."));
+						/* Skip the directory */
+						lname[strlen(lname)-1] = '/';
+						if (!seek_list(temp_list, lname)) {
+							break;
+						}
+					}
+				}
+				continue;
+			} else {
+				SAFE_FREE(quest);
+				if (asprintf(&quest,"Put file %s? ", lname) < 0) {
+					break;
+				}
+				if (prompt && !yesno(quest)) {
+					/* No */
+					continue;
+				}
+
+				/* Yes */
+				SAFE_FREE(rname);
+				if (asprintf(&rname, "%s%s", client_get_cur_dir(), lname) < 0) {
+					break;
+				}
+			}
+
+			normalize_name(rname);
+
+			do_put(rname, lname, false);
+		}
+		free_file_list(file_list);
+		SAFE_FREE(quest);
+		SAFE_FREE(lname);
+		SAFE_FREE(rname);
+	}
+
+	return 0;
+}
+
+/****************************************************************************
+ Cancel a print job.
+****************************************************************************/
+
+static int do_cancel(int job)
+{
+	if (cli_printjob_del(cli, job)) {
+		d_printf("Job %d cancelled\n",job);
+		return 0;
+	} else {
+		d_printf("Error cancelling job %d : %s\n",job,cli_errstr(cli));
+		return 1;
+	}
+}
+
+/****************************************************************************
+ Cancel a print job.
+****************************************************************************/
+
+static int cmd_cancel(void)
+{
+	TALLOC_CTX *ctx = talloc_tos();
+	char *buf = NULL;
+	int job;
+
+	if (!next_token_talloc(ctx, &cmd_ptr, &buf,NULL)) {
+		d_printf("cancel <jobid> ...\n");
+		return 1;
+	}
+	do {
+		job = atoi(buf);
+		do_cancel(job);
+	} while (next_token_talloc(ctx, &cmd_ptr,&buf,NULL));
+
+	return 0;
+}
+
+/****************************************************************************
+ Print a file.
+****************************************************************************/
+
+static int cmd_print(void)
+{
+	TALLOC_CTX *ctx = talloc_tos();
+	char *lname = NULL;
+	char *rname = NULL;
+	char *p = NULL;
+
+	if (!next_token_talloc(ctx, &cmd_ptr, &lname,NULL)) {
+		d_printf("print <filename>\n");
+		return 1;
+	}
+
+	rname = talloc_strdup(ctx, lname);
+	if (!rname) {
+		return 1;
+	}
+	p = strrchr_m(rname,'/');
+	if (p) {
+		rname = talloc_asprintf(ctx,
+					"%s-%d",
+					p+1,
+					(int)sys_getpid());
+	}
+	if (strequal(lname,"-")) {
+		rname = talloc_asprintf(ctx,
+				"stdin-%d",
+				(int)sys_getpid());
+	}
+	if (!rname) {
+		return 1;
+	}
+
+	return do_put(rname, lname, false);
+}
+
+/****************************************************************************
+ Show a print queue entry.
+****************************************************************************/
+
+static void queue_fn(struct print_job_info *p)
+{
+	d_printf("%-6d   %-9d    %s\n", (int)p->id, (int)p->size, p->name);
+}
+
+/****************************************************************************
+ Show a print queue.
+****************************************************************************/
+
+static int cmd_queue(void)
+{
+	cli_print_queue(cli, queue_fn);
+	return 0;
+}
+
+/****************************************************************************
+ Delete some files.
+****************************************************************************/
+
+static void do_del(file_info *finfo, const char *dir)
+{
+	TALLOC_CTX *ctx = talloc_tos();
+	char *mask = NULL;
+
+	mask = talloc_asprintf(ctx,
+				"%s%c%s",
+				dir,
+				CLI_DIRSEP_CHAR,
+				finfo->name);
+	if (!mask) {
+		return;
+	}
+
+	if (finfo->mode & aDIR) {
+		TALLOC_FREE(mask);
+		return;
+	}
+
+	if (!NT_STATUS_IS_OK(cli_unlink(finfo->cli, mask, aSYSTEM | aHIDDEN))) {
+		d_printf("%s deleting remote file %s\n",
+				cli_errstr(finfo->cli),mask);
+	}
+	TALLOC_FREE(mask);
+}
+
+/****************************************************************************
+ Delete some files.
+****************************************************************************/
+
+static int cmd_del(void)
+{
+	TALLOC_CTX *ctx = talloc_tos();
+	char *mask = NULL;
+	char *buf = NULL;
+	uint16 attribute = aSYSTEM | aHIDDEN;
+
+	if (recurse) {
+		attribute |= aDIR;
+	}
+
+	mask = talloc_strdup(ctx, client_get_cur_dir());
+	if (!mask) {
+		return 1;
+	}
+	if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
+		d_printf("del <filename>\n");
+		return 1;
+	}
+	mask = talloc_asprintf_append(mask, "%s", buf);
+	if (!mask) {
+		return 1;
+	}
+
+	do_list(mask,attribute,do_del,false,false);
+	return 0;
+}
+
+/****************************************************************************
+ Wildcard delete some files.
+****************************************************************************/
+
+static int cmd_wdel(void)
+{
+	TALLOC_CTX *ctx = talloc_tos();
+	char *mask = NULL;
+	char *buf = NULL;
+	uint16 attribute;
+	struct cli_state *targetcli;
+	char *targetname = NULL;
+
+	if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
+		d_printf("wdel 0x<attrib> <wcard>\n");
+		return 1;
+	}
+
+	attribute = (uint16)strtol(buf, (char **)NULL, 16);
+
+	if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
+		d_printf("wdel 0x<attrib> <wcard>\n");
+		return 1;
+	}
+
+	mask = talloc_asprintf(ctx, "%s%s",
+			client_get_cur_dir(),
+			buf);
+	if (!mask) {
+		return 1;
+	}
+
+	if (!cli_resolve_path(ctx, "", auth_info, cli, mask, &targetcli, &targetname)) {
+		d_printf("cmd_wdel %s: %s\n", mask, cli_errstr(cli));
+		return 1;
+	}
+
+	if (!NT_STATUS_IS_OK(cli_unlink(targetcli, targetname, attribute))) {
+		d_printf("%s deleting remote files %s\n",cli_errstr(targetcli),targetname);
+	}
+	return 0;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+static int cmd_open(void)
+{
+	TALLOC_CTX *ctx = talloc_tos();
+	char *mask = NULL;
+	char *buf = NULL;
+	char *targetname = NULL;
+	struct cli_state *targetcli;
+	uint16_t fnum = (uint16_t)-1;
+
+	if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
+		d_printf("open <filename>\n");
+		return 1;
+	}
+	mask = talloc_asprintf(ctx,
+			"%s%s",
+			client_get_cur_dir(),
+			buf);
+	if (!mask) {
+		return 1;
+	}
+
+	if (!cli_resolve_path(ctx, "", auth_info, cli, mask, &targetcli, &targetname)) {
+		d_printf("open %s: %s\n", mask, cli_errstr(cli));
+		return 1;
+	}
+
+	if (!NT_STATUS_IS_OK(cli_ntcreate(targetcli, targetname, 0,
+			FILE_READ_DATA|FILE_WRITE_DATA, 0,
+			FILE_SHARE_READ|FILE_SHARE_WRITE, FILE_OPEN, 0x0, 0x0, &fnum))) {
+		if (NT_STATUS_IS_OK(cli_ntcreate(targetcli, targetname, 0,
+				FILE_READ_DATA, 0,
+				FILE_SHARE_READ|FILE_SHARE_WRITE, FILE_OPEN, 0x0, 0x0, &fnum))) {
+			d_printf("open file %s: for read/write fnum %d\n", targetname, fnum);
+		} else {
+			d_printf("Failed to open file %s. %s\n", targetname, cli_errstr(cli));
+		}
+	} else {
+		d_printf("open file %s: for read/write fnum %d\n", targetname, fnum);
+	}
+	return 0;
+}
+
+static int cmd_posix_encrypt(void)
+{
+	TALLOC_CTX *ctx = talloc_tos();
+	NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
+
+	if (cli->use_kerberos) {
+		status = cli_gss_smb_encryption_start(cli);
+	} else {
+		char *domain = NULL;
+		char *user = NULL;
+		char *password = NULL;
+
+		if (!next_token_talloc(ctx, &cmd_ptr,&domain,NULL)) {
+			d_printf("posix_encrypt domain user password\n");
+			return 1;
+		}
+
+		if (!next_token_talloc(ctx, &cmd_ptr,&user,NULL)) {
+			d_printf("posix_encrypt domain user password\n");
+			return 1;
+		}
+
+		if (!next_token_talloc(ctx, &cmd_ptr,&password,NULL)) {
+			d_printf("posix_encrypt domain user password\n");
+			return 1;
+		}
+
+		status = cli_raw_ntlm_smb_encryption_start(cli,
+							user,
+							password,
+							domain);
+	}
+
+	if (!NT_STATUS_IS_OK(status)) {
+		d_printf("posix_encrypt failed with error %s\n", nt_errstr(status));
+	} else {
+		d_printf("encryption on\n");
+		smb_encrypt = true;
+	}
+
+	return 0;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+static int cmd_posix_open(void)
+{
+	TALLOC_CTX *ctx = talloc_tos();
+	char *mask = NULL;
+	char *buf = NULL;
+	char *targetname = NULL;
+	struct cli_state *targetcli;
+	mode_t mode;
+	uint16_t fnum;
+
+	if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
+		d_printf("posix_open <filename> 0<mode>\n");
+		return 1;
+	}
+	mask = talloc_asprintf(ctx,
+			"%s%s",
+			client_get_cur_dir(),
+			buf);
+	if (!mask) {
+		return 1;
+	}
+
+	if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
+		d_printf("posix_open <filename> 0<mode>\n");
+		return 1;
+	}
+	mode = (mode_t)strtol(buf, (char **)NULL, 8);
+
+	if (!cli_resolve_path(ctx, "", auth_info, cli, mask, &targetcli, &targetname)) {
+		d_printf("posix_open %s: %s\n", mask, cli_errstr(cli));
+		return 1;
+	}
+
+	if (!NT_STATUS_IS_OK(cli_posix_open(targetcli, targetname, O_CREAT|O_RDWR, mode, &fnum))) {
+		if (!NT_STATUS_IS_OK(cli_posix_open(targetcli, targetname, O_CREAT|O_RDONLY, mode, &fnum))) {
+			d_printf("posix_open file %s: for read/write fnum %d\n", targetname, fnum);
+		} else {
+			d_printf("Failed to open file %s. %s\n", targetname, cli_errstr(cli));
+		}
+	} else {
+		d_printf("posix_open file %s: for read/write fnum %d\n", targetname, fnum);
+	}
+
+	return 0;
+}
+
+static int cmd_posix_mkdir(void)
+{
+	TALLOC_CTX *ctx = talloc_tos();
+	char *mask = NULL;
+	char *buf = NULL;
+	char *targetname = NULL;
+	struct cli_state *targetcli;
+	mode_t mode;
+
+	if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
+		d_printf("posix_mkdir <filename> 0<mode>\n");
+		return 1;
+	}
+	mask = talloc_asprintf(ctx,
+			"%s%s",
+			client_get_cur_dir(),
+			buf);
+	if (!mask) {
+		return 1;
+	}
+
+	if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
+		d_printf("posix_mkdir <filename> 0<mode>\n");
+		return 1;
+	}
+	mode = (mode_t)strtol(buf, (char **)NULL, 8);
+
+	if (!cli_resolve_path(ctx, "", auth_info, cli, mask, &targetcli, &targetname)) {
+		d_printf("posix_mkdir %s: %s\n", mask, cli_errstr(cli));
+		return 1;
+	}
+
+	if (!NT_STATUS_IS_OK(cli_posix_mkdir(targetcli, targetname, mode))) {
+		d_printf("Failed to open file %s. %s\n", targetname, cli_errstr(cli));
+	} else {
+		d_printf("posix_mkdir created directory %s\n", targetname);
+	}
+	return 0;
+}
+
+static int cmd_posix_unlink(void)
+{
+	TALLOC_CTX *ctx = talloc_tos();
+	char *mask = NULL;
+	char *buf = NULL;
+	char *targetname = NULL;
+	struct cli_state *targetcli;
+
+	if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
+		d_printf("posix_unlink <filename>\n");
+		return 1;
+	}
+	mask = talloc_asprintf(ctx,
+			"%s%s",
+			client_get_cur_dir(),
+			buf);
+	if (!mask) {
+		return 1;
+	}
+
+	if (!cli_resolve_path(ctx, "", auth_info, cli, mask, &targetcli, &targetname)) {
+		d_printf("posix_unlink %s: %s\n", mask, cli_errstr(cli));
+		return 1;
+	}
+
+	if (!NT_STATUS_IS_OK(cli_posix_unlink(targetcli, targetname))) {
+		d_printf("Failed to unlink file %s. %s\n", targetname, cli_errstr(cli));
+	} else {
+		d_printf("posix_unlink deleted file %s\n", targetname);
+	}
+
+	return 0;
+}
+
+static int cmd_posix_rmdir(void)
+{
+	TALLOC_CTX *ctx = talloc_tos();
+	char *mask = NULL;
+	char *buf = NULL;
+	char *targetname = NULL;
+	struct cli_state *targetcli;
+
+	if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
+		d_printf("posix_rmdir <filename>\n");
+		return 1;
+	}
+	mask = talloc_asprintf(ctx,
+			"%s%s",
+			client_get_cur_dir(),
+			buf);
+	if (!mask) {
+		return 1;
+	}
+
+	if (!cli_resolve_path(ctx, "", auth_info, cli, mask, &targetcli, &targetname)) {
+		d_printf("posix_rmdir %s: %s\n", mask, cli_errstr(cli));
+		return 1;
+	}
+
+	if (!NT_STATUS_IS_OK(cli_posix_rmdir(targetcli, targetname))) {
+		d_printf("Failed to unlink directory %s. %s\n", targetname, cli_errstr(cli));
+	} else {
+		d_printf("posix_rmdir deleted directory %s\n", targetname);
+	}
+
+	return 0;
+}
+
+static int cmd_close(void)
+{
+	TALLOC_CTX *ctx = talloc_tos();
+	char *buf = NULL;
+	int fnum;
+
+	if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
+		d_printf("close <fnum>\n");
+		return 1;
+	}
+
+	fnum = atoi(buf);
+	/* We really should use the targetcli here.... */
+	if (!NT_STATUS_IS_OK(cli_close(cli, fnum))) {
+		d_printf("close %d: %s\n", fnum, cli_errstr(cli));
+		return 1;
+	}
+	return 0;
+}
+
+static int cmd_posix(void)
+{
+	TALLOC_CTX *ctx = talloc_tos();
+	uint16 major, minor;
+	uint32 caplow, caphigh;
+	char *caps;
+	NTSTATUS status;
+
+	if (!SERVER_HAS_UNIX_CIFS(cli)) {
+		d_printf("Server doesn't support UNIX CIFS extensions.\n");
+		return 1;
+	}
+
+	status = cli_unix_extensions_version(cli, &major, &minor, &caplow,
+					     &caphigh);
+	if (!NT_STATUS_IS_OK(status)) {
+		d_printf("Can't get UNIX CIFS extensions version from "
+			 "server: %s\n", nt_errstr(status));
+		return 1;
+	}
+
+	d_printf("Server supports CIFS extensions %u.%u\n", (unsigned int)major, (unsigned int)minor);
+
+	caps = talloc_strdup(ctx, "");
+	if (!caps) {
+		return 1;
+	}
+        if (caplow & CIFS_UNIX_FCNTL_LOCKS_CAP) {
+		caps = talloc_asprintf_append(caps, "locks ");
+		if (!caps) {
+			return 1;
+		}
+	}
+        if (caplow & CIFS_UNIX_POSIX_ACLS_CAP) {
+		caps = talloc_asprintf_append(caps, "acls ");
+		if (!caps) {
+			return 1;
+		}
+	}
+        if (caplow & CIFS_UNIX_XATTTR_CAP) {
+		caps = talloc_asprintf_append(caps, "eas ");
+		if (!caps) {
+			return 1;
+		}
+	}
+        if (caplow & CIFS_UNIX_POSIX_PATHNAMES_CAP) {
+		caps = talloc_asprintf_append(caps, "pathnames ");
+		if (!caps) {
+			return 1;
+		}
+	}
+        if (caplow & CIFS_UNIX_POSIX_PATH_OPERATIONS_CAP) {
+		caps = talloc_asprintf_append(caps, "posix_path_operations ");
+		if (!caps) {
+			return 1;
+		}
+	}
+        if (caplow & CIFS_UNIX_LARGE_READ_CAP) {
+		caps = talloc_asprintf_append(caps, "large_read ");
+		if (!caps) {
+			return 1;
+		}
+	}
+        if (caplow & CIFS_UNIX_LARGE_WRITE_CAP) {
+		caps = talloc_asprintf_append(caps, "large_write ");
+		if (!caps) {
+			return 1;
+		}
+	}
+	if (caplow & CIFS_UNIX_TRANSPORT_ENCRYPTION_CAP) {
+		caps = talloc_asprintf_append(caps, "posix_encrypt ");
+		if (!caps) {
+			return 1;
+		}
+	}
+	if (caplow & CIFS_UNIX_TRANSPORT_ENCRYPTION_MANDATORY_CAP) {
+		caps = talloc_asprintf_append(caps, "mandatory_posix_encrypt ");
+		if (!caps) {
+			return 1;
+		}
+	}
+
+	if (*caps && caps[strlen(caps)-1] == ' ') {
+		caps[strlen(caps)-1] = '\0';
+	}
+
+	d_printf("Server supports CIFS capabilities %s\n", caps);
+
+	if (!cli_set_unix_extensions_capabilities(cli, major, minor, caplow, caphigh)) {
+		d_printf("Can't set UNIX CIFS extensions capabilities. %s.\n", cli_errstr(cli));
+		return 1;
+	}
+
+	if (caplow & CIFS_UNIX_POSIX_PATHNAMES_CAP) {
+		CLI_DIRSEP_CHAR = '/';
+		*CLI_DIRSEP_STR = '/';
+		client_set_cur_dir(CLI_DIRSEP_STR);
+	}
+
+	return 0;
+}
+
+static int cmd_lock(void)
+{
+	TALLOC_CTX *ctx = talloc_tos();
+	char *buf = NULL;
+	uint64_t start, len;
+	enum brl_type lock_type;
+	int fnum;
+
+	if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
+		d_printf("lock <fnum> [r|w] <hex-start> <hex-len>\n");
+		return 1;
+	}
+	fnum = atoi(buf);
+
+	if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
+		d_printf("lock <fnum> [r|w] <hex-start> <hex-len>\n");
+		return 1;
+	}
+
+	if (*buf == 'r' || *buf == 'R') {
+		lock_type = READ_LOCK;
+	} else if (*buf == 'w' || *buf == 'W') {
+		lock_type = WRITE_LOCK;
+	} else {
+		d_printf("lock <fnum> [r|w] <hex-start> <hex-len>\n");
+		return 1;
+	}
+
+	if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
+		d_printf("lock <fnum> [r|w] <hex-start> <hex-len>\n");
+		return 1;
+	}
+
+	start = (uint64_t)strtol(buf, (char **)NULL, 16);
+
+	if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
+		d_printf("lock <fnum> [r|w] <hex-start> <hex-len>\n");
+		return 1;
+	}
+
+	len = (uint64_t)strtol(buf, (char **)NULL, 16);
+
+	if (!NT_STATUS_IS_OK(cli_posix_lock(cli, fnum, start, len, true, lock_type))) {
+		d_printf("lock failed %d: %s\n", fnum, cli_errstr(cli));
+	}
+
+	return 0;
+}
+
+static int cmd_unlock(void)
+{
+	TALLOC_CTX *ctx = talloc_tos();
+	char *buf = NULL;
+	uint64_t start, len;
+	int fnum;
+
+	if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
+		d_printf("unlock <fnum> <hex-start> <hex-len>\n");
+		return 1;
+	}
+	fnum = atoi(buf);
+
+	if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
+		d_printf("unlock <fnum> <hex-start> <hex-len>\n");
+		return 1;
+	}
+
+	start = (uint64_t)strtol(buf, (char **)NULL, 16);
+
+	if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
+		d_printf("unlock <fnum> <hex-start> <hex-len>\n");
+		return 1;
+	}
+
+	len = (uint64_t)strtol(buf, (char **)NULL, 16);
+
+	if (!NT_STATUS_IS_OK(cli_posix_unlock(cli, fnum, start, len))) {
+		d_printf("unlock failed %d: %s\n", fnum, cli_errstr(cli));
+	}
+
+	return 0;
+}
+
+
+/****************************************************************************
+ Remove a directory.
+****************************************************************************/
+
+static int cmd_rmdir(void)
+{
+	TALLOC_CTX *ctx = talloc_tos();
+	char *mask = NULL;
+	char *buf = NULL;
+	char *targetname = NULL;
+	struct cli_state *targetcli;
+
+	if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
+		d_printf("rmdir <dirname>\n");
+		return 1;
+	}
+	mask = talloc_asprintf(ctx,
+			"%s%s",
+			client_get_cur_dir(),
+			buf);
+	if (!mask) {
+		return 1;
+	}
+
+	if (!cli_resolve_path(ctx, "", auth_info, cli, mask, &targetcli, &targetname)) {
+		d_printf("rmdir %s: %s\n", mask, cli_errstr(cli));
+		return 1;
+	}
+
+	if (!NT_STATUS_IS_OK(cli_rmdir(targetcli, targetname))) {
+		d_printf("%s removing remote directory file %s\n",
+			 cli_errstr(targetcli),mask);
+	}
+
+	return 0;
+}
+
+/****************************************************************************
+ UNIX hardlink.
+****************************************************************************/
+
+static int cmd_link(void)
+{
+	TALLOC_CTX *ctx = talloc_tos();
+	char *oldname = NULL;
+	char *newname = NULL;
+	char *buf = NULL;
+	char *buf2 = NULL;
+	char *targetname = NULL;
+	struct cli_state *targetcli;
+
+	if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL) ||
+	    !next_token_talloc(ctx, &cmd_ptr,&buf2,NULL)) {
+		d_printf("link <oldname> <newname>\n");
+		return 1;
+	}
+	oldname = talloc_asprintf(ctx,
+			"%s%s",
+			client_get_cur_dir(),
+			buf);
+	if (!oldname) {
+		return 1;
+	}
+	newname = talloc_asprintf(ctx,
+			"%s%s",
+			client_get_cur_dir(),
+			buf2);
+	if (!newname) {
+		return 1;
+	}
+
+	if (!cli_resolve_path(ctx, "", auth_info, cli, oldname, &targetcli, &targetname)) {
+		d_printf("link %s: %s\n", oldname, cli_errstr(cli));
+		return 1;
+	}
+
+	if (!SERVER_HAS_UNIX_CIFS(targetcli)) {
+		d_printf("Server doesn't support UNIX CIFS calls.\n");
+		return 1;
+	}
+
+	if (!NT_STATUS_IS_OK(cli_posix_hardlink(targetcli, targetname, newname))) {
+		d_printf("%s linking files (%s -> %s)\n", cli_errstr(targetcli), newname, oldname);
+		return 1;
+	}
+	return 0;
+}
+
+/****************************************************************************
+ UNIX readlink.
+****************************************************************************/
+
+static int cmd_readlink(void)
+{
+	TALLOC_CTX *ctx = talloc_tos();
+	char *name= NULL;
+	char *buf = NULL;
+	char *targetname = NULL;
+	char linkname[PATH_MAX+1];
+	struct cli_state *targetcli;
+
+	if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
+		d_printf("readlink <name>\n");
+		return 1;
+	}
+	name = talloc_asprintf(ctx,
+			"%s%s",
+			client_get_cur_dir(),
+			buf);
+	if (!name) {
+		return 1;
+	}
+
+	if (!cli_resolve_path(ctx, "", auth_info, cli, name, &targetcli, &targetname)) {
+		d_printf("readlink %s: %s\n", name, cli_errstr(cli));
+		return 1;
+	}
+
+	if (!SERVER_HAS_UNIX_CIFS(targetcli)) {
+		d_printf("Server doesn't support UNIX CIFS calls.\n");
+		return 1;
+	}
+
+	if (!NT_STATUS_IS_OK(cli_posix_readlink(targetcli, name,
+			linkname, PATH_MAX+1))) {
+		d_printf("%s readlink on file %s\n",
+			cli_errstr(targetcli), name);
+		return 1;
+	}
+
+	d_printf("%s -> %s\n", name, linkname);
+
+	return 0;
+}
+
+
+/****************************************************************************
+ UNIX symlink.
+****************************************************************************/
+
+static int cmd_symlink(void)
+{
+	TALLOC_CTX *ctx = talloc_tos();
+	char *oldname = NULL;
+	char *newname = NULL;
+	char *buf = NULL;
+	char *buf2 = NULL;
+	char *targetname = NULL;
+	struct cli_state *targetcli;
+
+	if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL) ||
+	    !next_token_talloc(ctx, &cmd_ptr,&buf2,NULL)) {
+		d_printf("symlink <oldname> <newname>\n");
+		return 1;
+	}
+	oldname = talloc_asprintf(ctx,
+			"%s%s",
+			client_get_cur_dir(),
+			buf);
+	if (!oldname) {
+		return 1;
+	}
+	newname = talloc_asprintf(ctx,
+			"%s%s",
+			client_get_cur_dir(),
+			buf2);
+	if (!newname) {
+		return 1;
+	}
+
+	if (!cli_resolve_path(ctx, "", auth_info, cli, oldname, &targetcli, &targetname)) {
+		d_printf("link %s: %s\n", oldname, cli_errstr(cli));
+		return 1;
+	}
+
+	if (!SERVER_HAS_UNIX_CIFS(targetcli)) {
+		d_printf("Server doesn't support UNIX CIFS calls.\n");
+		return 1;
+	}
+
+	if (!NT_STATUS_IS_OK(cli_posix_symlink(targetcli, targetname, newname))) {
+		d_printf("%s symlinking files (%s -> %s)\n",
+			cli_errstr(targetcli), newname, targetname);
+		return 1;
+	}
+
+	return 0;
+}
+
+/****************************************************************************
+ UNIX chmod.
+****************************************************************************/
+
+static int cmd_chmod(void)
+{
+	TALLOC_CTX *ctx = talloc_tos();
+	char *src = NULL;
+	char *buf = NULL;
+	char *buf2 = NULL;
+	char *targetname = NULL;
+	struct cli_state *targetcli;
+	mode_t mode;
+
+	if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL) ||
+	    !next_token_talloc(ctx, &cmd_ptr,&buf2,NULL)) {
+		d_printf("chmod mode file\n");
+		return 1;
+	}
+	src = talloc_asprintf(ctx,
+			"%s%s",
+			client_get_cur_dir(),
+			buf2);
+	if (!src) {
+		return 1;
+	}
+
+	mode = (mode_t)strtol(buf, NULL, 8);
+
+	if (!cli_resolve_path(ctx, "", auth_info, cli, src, &targetcli, &targetname)) {
+		d_printf("chmod %s: %s\n", src, cli_errstr(cli));
+		return 1;
+	}
+
+	if (!SERVER_HAS_UNIX_CIFS(targetcli)) {
+		d_printf("Server doesn't support UNIX CIFS calls.\n");
+		return 1;
+	}
+
+	if (!NT_STATUS_IS_OK(cli_posix_chmod(targetcli, targetname, mode))) {
+		d_printf("%s chmod file %s 0%o\n",
+			cli_errstr(targetcli), src, (unsigned int)mode);
+		return 1;
+	}
+
+	return 0;
+}
+
+static const char *filetype_to_str(mode_t mode)
+{
+	if (S_ISREG(mode)) {
+		return "regular file";
+	} else if (S_ISDIR(mode)) {
+		return "directory";
+	} else
+#ifdef S_ISCHR
+	if (S_ISCHR(mode)) {
+		return "character device";
+	} else
+#endif
+#ifdef S_ISBLK
+	if (S_ISBLK(mode)) {
+		return "block device";
+	} else
+#endif
+#ifdef S_ISFIFO
+	if (S_ISFIFO(mode)) {
+		return "fifo";
+	} else
+#endif
+#ifdef S_ISLNK
+	if (S_ISLNK(mode)) {
+		return "symbolic link";
+	} else
+#endif
+#ifdef S_ISSOCK
+	if (S_ISSOCK(mode)) {
+		return "socket";
+	} else
+#endif
+	return "";
+}
+
+static char rwx_to_str(mode_t m, mode_t bt, char ret)
+{
+	if (m & bt) {
+		return ret;
+	} else {
+		return '-';
+	}
+}
+
+static char *unix_mode_to_str(char *s, mode_t m)
+{
+	char *p = s;
+	const char *str = filetype_to_str(m);
+
+	switch(str[0]) {
+		case 'd':
+			*p++ = 'd';
+			break;
+		case 'c':
+			*p++ = 'c';
+			break;
+		case 'b':
+			*p++ = 'b';
+			break;
+		case 'f':
+			*p++ = 'p';
+			break;
+		case 's':
+			*p++ = str[1] == 'y' ? 'l' : 's';
+			break;
+		case 'r':
+		default:
+			*p++ = '-';
+			break;
+	}
+	*p++ = rwx_to_str(m, S_IRUSR, 'r');
+	*p++ = rwx_to_str(m, S_IWUSR, 'w');
+	*p++ = rwx_to_str(m, S_IXUSR, 'x');
+	*p++ = rwx_to_str(m, S_IRGRP, 'r');
+	*p++ = rwx_to_str(m, S_IWGRP, 'w');
+	*p++ = rwx_to_str(m, S_IXGRP, 'x');
+	*p++ = rwx_to_str(m, S_IROTH, 'r');
+	*p++ = rwx_to_str(m, S_IWOTH, 'w');
+	*p++ = rwx_to_str(m, S_IXOTH, 'x');
+	*p++ = '\0';
+	return s;
+}
+
+/****************************************************************************
+ Utility function for UNIX getfacl.
+****************************************************************************/
+
+static char *perms_to_string(fstring permstr, unsigned char perms)
+{
+	fstrcpy(permstr, "---");
+	if (perms & SMB_POSIX_ACL_READ) {
+		permstr[0] = 'r';
+	}
+	if (perms & SMB_POSIX_ACL_WRITE) {
+		permstr[1] = 'w';
+	}
+	if (perms & SMB_POSIX_ACL_EXECUTE) {
+		permstr[2] = 'x';
+	}
+	return permstr;
+}
+
+/****************************************************************************
+ UNIX getfacl.
+****************************************************************************/
+
+static int cmd_getfacl(void)
+{
+	TALLOC_CTX *ctx = talloc_tos();
+	char *src = NULL;
+	char *name = NULL;
+	char *targetname = NULL;
+	struct cli_state *targetcli;
+	uint16 major, minor;
+	uint32 caplow, caphigh;
+	char *retbuf = NULL;
+	size_t rb_size = 0;
+	SMB_STRUCT_STAT sbuf;
+	uint16 num_file_acls = 0;
+	uint16 num_dir_acls = 0;
+	uint16 i;
+	NTSTATUS status;
+
+	if (!next_token_talloc(ctx, &cmd_ptr,&name,NULL)) {
+		d_printf("getfacl filename\n");
+		return 1;
+	}
+	src = talloc_asprintf(ctx,
+			"%s%s",
+			client_get_cur_dir(),
+			name);
+	if (!src) {
+		return 1;
+	}
+
+	if (!cli_resolve_path(ctx, "", auth_info, cli, src, &targetcli, &targetname)) {
+		d_printf("stat %s: %s\n", src, cli_errstr(cli));
+		return 1;
+	}
+
+	if (!SERVER_HAS_UNIX_CIFS(targetcli)) {
+		d_printf("Server doesn't support UNIX CIFS calls.\n");
+		return 1;
+	}
+
+	status = cli_unix_extensions_version(targetcli, &major, &minor,
+					     &caplow, &caphigh);
+	if (!NT_STATUS_IS_OK(status)) {
+		d_printf("Can't get UNIX CIFS version from server: %s.\n",
+			 nt_errstr(status));
+		return 1;
+	}
+
+	if (!(caplow & CIFS_UNIX_POSIX_ACLS_CAP)) {
+		d_printf("This server supports UNIX extensions "
+			"but doesn't support POSIX ACLs.\n");
+		return 1;
+	}
+
+	if (!NT_STATUS_IS_OK(cli_posix_stat(targetcli, targetname, &sbuf))) {
+		d_printf("%s getfacl doing a stat on file %s\n",
+			cli_errstr(targetcli), src);
+		return 1;
+	}
+
+	if (!NT_STATUS_IS_OK(cli_posix_getfacl(targetcli, targetname, ctx, &rb_size, &retbuf))) {
+		d_printf("%s getfacl file %s\n",
+			cli_errstr(targetcli), src);
+		return 1;
+	}
+
+	/* ToDo : Print out the ACL values. */
+	if (rb_size < 6 || SVAL(retbuf,0) != SMB_POSIX_ACL_VERSION) {
+		d_printf("getfacl file %s, unknown POSIX acl version %u.\n",
+			src, (unsigned int)CVAL(retbuf,0) );
+		return 1;
+	}
+
+	num_file_acls = SVAL(retbuf,2);
+	num_dir_acls = SVAL(retbuf,4);
+	if (rb_size != SMB_POSIX_ACL_HEADER_SIZE + SMB_POSIX_ACL_ENTRY_SIZE*(num_file_acls+num_dir_acls)) {
+		d_printf("getfacl file %s, incorrect POSIX acl buffer size (should be %u, was %u).\n",
+			src,
+			(unsigned int)(SMB_POSIX_ACL_HEADER_SIZE + SMB_POSIX_ACL_ENTRY_SIZE*(num_file_acls+num_dir_acls)),
+			(unsigned int)rb_size);
+		return 1;
+	}
+
+	d_printf("# file: %s\n", src);
+	d_printf("# owner: %u\n# group: %u\n", (unsigned int)sbuf.st_ex_uid, (unsigned int)sbuf.st_ex_gid);
+
+	if (num_file_acls == 0 && num_dir_acls == 0) {
+		d_printf("No acls found.\n");
+	}
+
+	for (i = 0; i < num_file_acls; i++) {
+		uint32 uorg;
+		fstring permstring;
+		unsigned char tagtype = CVAL(retbuf, SMB_POSIX_ACL_HEADER_SIZE+(i*SMB_POSIX_ACL_ENTRY_SIZE));
+		unsigned char perms = CVAL(retbuf, SMB_POSIX_ACL_HEADER_SIZE+(i*SMB_POSIX_ACL_ENTRY_SIZE)+1);
+
+		switch(tagtype) {
+			case SMB_POSIX_ACL_USER_OBJ:
+				d_printf("user::");
+				break;
+			case SMB_POSIX_ACL_USER:
+				uorg = IVAL(retbuf,SMB_POSIX_ACL_HEADER_SIZE+(i*SMB_POSIX_ACL_ENTRY_SIZE)+2);
+				d_printf("user:%u:", uorg);
+				break;
+			case SMB_POSIX_ACL_GROUP_OBJ:
+				d_printf("group::");
+				break;
+			case SMB_POSIX_ACL_GROUP:
+				uorg = IVAL(retbuf,SMB_POSIX_ACL_HEADER_SIZE+(i*SMB_POSIX_ACL_ENTRY_SIZE)+2);
+				d_printf("group:%u:", uorg);
+				break;
+			case SMB_POSIX_ACL_MASK:
+				d_printf("mask::");
+				break;
+			case SMB_POSIX_ACL_OTHER:
+				d_printf("other::");
+				break;
+			default:
+				d_printf("getfacl file %s, incorrect POSIX acl tagtype (%u).\n",
+					src, (unsigned int)tagtype );
+				SAFE_FREE(retbuf);
+				return 1;
+		}
+
+		d_printf("%s\n", perms_to_string(permstring, perms));
+	}
+
+	for (i = 0; i < num_dir_acls; i++) {
+		uint32 uorg;
+		fstring permstring;
+		unsigned char tagtype = CVAL(retbuf, SMB_POSIX_ACL_HEADER_SIZE+((i+num_file_acls)*SMB_POSIX_ACL_ENTRY_SIZE));
+		unsigned char perms = CVAL(retbuf, SMB_POSIX_ACL_HEADER_SIZE+((i+num_file_acls)*SMB_POSIX_ACL_ENTRY_SIZE)+1);
+
+		switch(tagtype) {
+			case SMB_POSIX_ACL_USER_OBJ:
+				d_printf("default:user::");
+				break;
+			case SMB_POSIX_ACL_USER:
+				uorg = IVAL(retbuf,SMB_POSIX_ACL_HEADER_SIZE+((i+num_file_acls)*SMB_POSIX_ACL_ENTRY_SIZE)+2);
+				d_printf("default:user:%u:", uorg);
+				break;
+			case SMB_POSIX_ACL_GROUP_OBJ:
+				d_printf("default:group::");
+				break;
+			case SMB_POSIX_ACL_GROUP:
+				uorg = IVAL(retbuf,SMB_POSIX_ACL_HEADER_SIZE+((i+num_file_acls)*SMB_POSIX_ACL_ENTRY_SIZE)+2);
+				d_printf("default:group:%u:", uorg);
+				break;
+			case SMB_POSIX_ACL_MASK:
+				d_printf("default:mask::");
+				break;
+			case SMB_POSIX_ACL_OTHER:
+				d_printf("default:other::");
+				break;
+			default:
+				d_printf("getfacl file %s, incorrect POSIX acl tagtype (%u).\n",
+					src, (unsigned int)tagtype );
+				SAFE_FREE(retbuf);
+				return 1;
+		}
+
+		d_printf("%s\n", perms_to_string(permstring, perms));
+	}
+
+	return 0;
+}
+
+/****************************************************************************
+ UNIX stat.
+****************************************************************************/
+
+static int cmd_stat(void)
+{
+	TALLOC_CTX *ctx = talloc_tos();
+	char *src = NULL;
+	char *name = NULL;
+	char *targetname = NULL;
+	struct cli_state *targetcli;
+	fstring mode_str;
+	SMB_STRUCT_STAT sbuf;
+	struct tm *lt;
+	time_t tmp_time;
+
+	if (!next_token_talloc(ctx, &cmd_ptr,&name,NULL)) {
+		d_printf("stat file\n");
+		return 1;
+	}
+	src = talloc_asprintf(ctx,
+			"%s%s",
+			client_get_cur_dir(),
+			name);
+	if (!src) {
+		return 1;
+	}
+
+	if (!cli_resolve_path(ctx, "", auth_info, cli, src, &targetcli, &targetname)) {
+		d_printf("stat %s: %s\n", src, cli_errstr(cli));
+		return 1;
+	}
+
+	if (!SERVER_HAS_UNIX_CIFS(targetcli)) {
+		d_printf("Server doesn't support UNIX CIFS calls.\n");
+		return 1;
+	}
+
+	if (!NT_STATUS_IS_OK(cli_posix_stat(targetcli, targetname, &sbuf))) {
+		d_printf("%s stat file %s\n",
+			cli_errstr(targetcli), src);
+		return 1;
+	}
+
+	/* Print out the stat values. */
+	d_printf("File: %s\n", src);
+	d_printf("Size: %-12.0f\tBlocks: %u\t%s\n",
+		(double)sbuf.st_ex_size,
+		(unsigned int)sbuf.st_ex_blocks,
+		filetype_to_str(sbuf.st_ex_mode));
+
+#if defined(S_ISCHR) && defined(S_ISBLK)
+	if (S_ISCHR(sbuf.st_ex_mode) || S_ISBLK(sbuf.st_ex_mode)) {
+		d_printf("Inode: %.0f\tLinks: %u\tDevice type: %u,%u\n",
+			(double)sbuf.st_ex_ino,
+			(unsigned int)sbuf.st_ex_nlink,
+			unix_dev_major(sbuf.st_ex_rdev),
+			unix_dev_minor(sbuf.st_ex_rdev));
+	} else
+#endif
+		d_printf("Inode: %.0f\tLinks: %u\n",
+			(double)sbuf.st_ex_ino,
+			(unsigned int)sbuf.st_ex_nlink);
+
+	d_printf("Access: (0%03o/%s)\tUid: %u\tGid: %u\n",
+		((int)sbuf.st_ex_mode & 0777),
+		unix_mode_to_str(mode_str, sbuf.st_ex_mode),
+		(unsigned int)sbuf.st_ex_uid,
+		(unsigned int)sbuf.st_ex_gid);
+
+	tmp_time = convert_timespec_to_time_t(sbuf.st_ex_atime);
+	lt = localtime(&tmp_time);
+	if (lt) {
+		strftime(mode_str, sizeof(mode_str), "%Y-%m-%d %T %z", lt);
+	} else {
+		fstrcpy(mode_str, "unknown");
+	}
+	d_printf("Access: %s\n", mode_str);
+
+	tmp_time = convert_timespec_to_time_t(sbuf.st_ex_mtime);
+	lt = localtime(&tmp_time);
+	if (lt) {
+		strftime(mode_str, sizeof(mode_str), "%Y-%m-%d %T %z", lt);
+	} else {
+		fstrcpy(mode_str, "unknown");
+	}
+	d_printf("Modify: %s\n", mode_str);
+
+	tmp_time = convert_timespec_to_time_t(sbuf.st_ex_ctime);
+	lt = localtime(&tmp_time);
+	if (lt) {
+		strftime(mode_str, sizeof(mode_str), "%Y-%m-%d %T %z", lt);
+	} else {
+		fstrcpy(mode_str, "unknown");
+	}
+	d_printf("Change: %s\n", mode_str);
+
+	return 0;
+}
+
+
+/****************************************************************************
+ UNIX chown.
+****************************************************************************/
+
+static int cmd_chown(void)
+{
+	TALLOC_CTX *ctx = talloc_tos();
+	char *src = NULL;
+	uid_t uid;
+	gid_t gid;
+	char *buf, *buf2, *buf3;
+	struct cli_state *targetcli;
+	char *targetname = NULL;
+
+	if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL) ||
+	    !next_token_talloc(ctx, &cmd_ptr,&buf2,NULL) ||
+	    !next_token_talloc(ctx, &cmd_ptr,&buf3,NULL)) {
+		d_printf("chown uid gid file\n");
+		return 1;
+	}
+
+	uid = (uid_t)atoi(buf);
+	gid = (gid_t)atoi(buf2);
+
+	src = talloc_asprintf(ctx,
+			"%s%s",
+			client_get_cur_dir(),
+			buf3);
+	if (!src) {
+		return 1;
+	}
+	if (!cli_resolve_path(ctx, "", auth_info, cli, src, &targetcli, &targetname) ) {
+		d_printf("chown %s: %s\n", src, cli_errstr(cli));
+		return 1;
+	}
+
+	if (!SERVER_HAS_UNIX_CIFS(targetcli)) {
+		d_printf("Server doesn't support UNIX CIFS calls.\n");
+		return 1;
+	}
+
+	if (!NT_STATUS_IS_OK(cli_posix_chown(targetcli, targetname, uid, gid))) {
+		d_printf("%s chown file %s uid=%d, gid=%d\n",
+			cli_errstr(targetcli), src, (int)uid, (int)gid);
+		return 1;
+	}
+
+	return 0;
+}
+
+/****************************************************************************
+ Rename some file.
+****************************************************************************/
+
+static int cmd_rename(void)
+{
+	TALLOC_CTX *ctx = talloc_tos();
+	char *src, *dest;
+	char *buf, *buf2;
+	struct cli_state *targetcli;
+	char *targetsrc;
+	char *targetdest;
+
+	if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL) ||
+	    !next_token_talloc(ctx, &cmd_ptr,&buf2,NULL)) {
+		d_printf("rename <src> <dest>\n");
+		return 1;
+	}
+
+	src = talloc_asprintf(ctx,
+			"%s%s",
+			client_get_cur_dir(),
+			buf);
+	if (!src) {
+		return 1;
+	}
+
+	dest = talloc_asprintf(ctx,
+			"%s%s",
+			client_get_cur_dir(),
+			buf2);
+	if (!dest) {
+		return 1;
+	}
+
+	if (!cli_resolve_path(ctx, "", auth_info, cli, src, &targetcli, &targetsrc)) {
+		d_printf("rename %s: %s\n", src, cli_errstr(cli));
+		return 1;
+	}
+
+	if (!cli_resolve_path(ctx, "", auth_info, cli, dest, &targetcli, &targetdest)) {
+		d_printf("rename %s: %s\n", dest, cli_errstr(cli));
+		return 1;
+	}
+
+	if (!NT_STATUS_IS_OK(cli_rename(targetcli, targetsrc, targetdest))) {
+		d_printf("%s renaming files %s -> %s \n",
+			cli_errstr(targetcli),
+			targetsrc,
+			targetdest);
+		return 1;
+	}
+
+	return 0;
+}
+
+/****************************************************************************
+ Print the volume name.
+****************************************************************************/
+
+static int cmd_volume(void)
+{
+	fstring volname;
+	uint32 serial_num;
+	time_t create_date;
+
+	if (!cli_get_fs_volume_info(cli, volname, &serial_num, &create_date)) {
+		d_printf("Errr %s getting volume info\n",cli_errstr(cli));
+		return 1;
+	}
+
+	d_printf("Volume: |%s| serial number 0x%x\n",
+			volname, (unsigned int)serial_num);
+	return 0;
+}
+
+/****************************************************************************
+ Hard link files using the NT call.
+****************************************************************************/
+
+static int cmd_hardlink(void)
+{
+	TALLOC_CTX *ctx = talloc_tos();
+	char *src, *dest;
+	char *buf, *buf2;
+	struct cli_state *targetcli;
+	char *targetname;
+
+	if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL) ||
+	    !next_token_talloc(ctx, &cmd_ptr,&buf2,NULL)) {
+		d_printf("hardlink <src> <dest>\n");
+		return 1;
+	}
+
+	src = talloc_asprintf(ctx,
+			"%s%s",
+			client_get_cur_dir(),
+			buf);
+	if (!src) {
+		return 1;
+	}
+
+	dest = talloc_asprintf(ctx,
+			"%s%s",
+			client_get_cur_dir(),
+			buf2);
+	if (!dest) {
+		return 1;
+	}
+
+	if (!cli_resolve_path(ctx, "", auth_info, cli, src, &targetcli, &targetname)) {
+		d_printf("hardlink %s: %s\n", src, cli_errstr(cli));
+		return 1;
+	}
+
+	if (!NT_STATUS_IS_OK(cli_nt_hardlink(targetcli, targetname, dest))) {
+		d_printf("%s doing an NT hard link of files\n",cli_errstr(targetcli));
+		return 1;
+	}
+
+	return 0;
+}
+
+/****************************************************************************
+ Toggle the prompt flag.
+****************************************************************************/
+
+static int cmd_prompt(void)
+{
+	prompt = !prompt;
+	DEBUG(2,("prompting is now %s\n",prompt?"on":"off"));
+	return 1;
+}
+
+/****************************************************************************
+ Set the newer than time.
+****************************************************************************/
+
+static int cmd_newer(void)
+{
+	TALLOC_CTX *ctx = talloc_tos();
+	char *buf;
+	bool ok;
+	SMB_STRUCT_STAT sbuf;
+
+	ok = next_token_talloc(ctx, &cmd_ptr,&buf,NULL);
+	if (ok && (sys_stat(buf, &sbuf, false) == 0)) {
+		newer_than = convert_timespec_to_time_t(sbuf.st_ex_mtime);
+		DEBUG(1,("Getting files newer than %s",
+			 time_to_asc(newer_than)));
+	} else {
+		newer_than = 0;
+	}
+
+	if (ok && newer_than == 0) {
+		d_printf("Error setting newer-than time\n");
+		return 1;
+	}
+
+	return 0;
+}
+
+/****************************************************************************
+ Set the archive level.
+****************************************************************************/
+
+static int cmd_archive(void)
+{
+	TALLOC_CTX *ctx = talloc_tos();
+	char *buf;
+
+	if (next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
+		archive_level = atoi(buf);
+	} else {
+		d_printf("Archive level is %d\n",archive_level);
+	}
+
+	return 0;
+}
+
+/****************************************************************************
+ Toggle the lowercaseflag.
+****************************************************************************/
+
+static int cmd_lowercase(void)
+{
+	lowercase = !lowercase;
+	DEBUG(2,("filename lowercasing is now %s\n",lowercase?"on":"off"));
+	return 0;
+}
+
+/****************************************************************************
+ Toggle the case sensitive flag.
+****************************************************************************/
+
+static int cmd_setcase(void)
+{
+	bool orig_case_sensitive = cli_set_case_sensitive(cli, false);
+
+	cli_set_case_sensitive(cli, !orig_case_sensitive);
+	DEBUG(2,("filename case sensitivity is now %s\n",!orig_case_sensitive ?
+		"on":"off"));
+	return 0;
+}
+
+/****************************************************************************
+ Toggle the showacls flag.
+****************************************************************************/
+
+static int cmd_showacls(void)
+{
+	showacls = !showacls;
+	DEBUG(2,("showacls is now %s\n",showacls?"on":"off"));
+	return 0;
+}
+
+
+/****************************************************************************
+ Toggle the recurse flag.
+****************************************************************************/
+
+static int cmd_recurse(void)
+{
+	recurse = !recurse;
+	DEBUG(2,("directory recursion is now %s\n",recurse?"on":"off"));
+	return 0;
+}
+
+/****************************************************************************
+ Toggle the translate flag.
+****************************************************************************/
+
+static int cmd_translate(void)
+{
+	translation = !translation;
+	DEBUG(2,("CR/LF<->LF and print text translation now %s\n",
+		 translation?"on":"off"));
+	return 0;
+}
+
+/****************************************************************************
+ Do the lcd command.
+ ****************************************************************************/
+
+static int cmd_lcd(void)
+{
+	TALLOC_CTX *ctx = talloc_tos();
+	char *buf;
+	char *d;
+
+	if (next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
+		if (chdir(buf) == -1) {
+			d_printf("chdir to %s failed (%s)\n",
+				buf, strerror(errno));
+		}
+	}
+	d = TALLOC_ARRAY(ctx, char, PATH_MAX+1);
+	if (!d) {
+		return 1;
+	}
+	DEBUG(2,("the local directory is now %s\n",sys_getwd(d)));
+	return 0;
+}
+
+/****************************************************************************
+ Get a file restarting at end of local file.
+ ****************************************************************************/
+
+static int cmd_reget(void)
+{
+	TALLOC_CTX *ctx = talloc_tos();
+	char *local_name = NULL;
+	char *remote_name = NULL;
+	char *fname = NULL;
+	char *p = NULL;
+
+	remote_name = talloc_strdup(ctx, client_get_cur_dir());
+	if (!remote_name) {
+		return 1;
+	}
+
+	if (!next_token_talloc(ctx, &cmd_ptr, &fname, NULL)) {
+		d_printf("reget <filename>\n");
+		return 1;
+	}
+	remote_name = talloc_asprintf_append(remote_name, "%s", fname);
+	if (!remote_name) {
+		return 1;
+	}
+	remote_name = clean_name(ctx,remote_name);
+	if (!remote_name) {
+		return 1;
+	}
+
+	local_name = fname;
+	next_token_talloc(ctx, &cmd_ptr, &p, NULL);
+	if (p) {
+		local_name = p;
+	}
+
+	return do_get(remote_name, local_name, true);
+}
+
+/****************************************************************************
+ Put a file restarting at end of local file.
+ ****************************************************************************/
+
+static int cmd_reput(void)
+{
+	TALLOC_CTX *ctx = talloc_tos();
+	char *local_name = NULL;
+	char *remote_name = NULL;
+	char *buf;
+	SMB_STRUCT_STAT st;
+
+	remote_name = talloc_strdup(ctx, client_get_cur_dir());
+	if (!remote_name) {
+		return 1;
+	}
+
+	if (!next_token_talloc(ctx, &cmd_ptr, &local_name, NULL)) {
+		d_printf("reput <filename>\n");
+		return 1;
+	}
+
+	if (!file_exist_stat(local_name, &st, false)) {
+		d_printf("%s does not exist\n", local_name);
+		return 1;
+	}
+
+	if (next_token_talloc(ctx, &cmd_ptr, &buf, NULL)) {
+		remote_name = talloc_asprintf_append(remote_name,
+						"%s", buf);
+	} else {
+		remote_name = talloc_asprintf_append(remote_name,
+						"%s", local_name);
+	}
+	if (!remote_name) {
+		return 1;
+	}
+
+	remote_name = clean_name(ctx, remote_name);
+	if (!remote_name) {
+		return 1;
+	}
+
+	return do_put(remote_name, local_name, true);
+}
+
+/****************************************************************************
+ List a share name.
+ ****************************************************************************/
+
+static void browse_fn(const char *name, uint32 m,
+                      const char *comment, void *state)
+{
+	const char *typestr = "";
+
+        switch (m & 7) {
+	case STYPE_DISKTREE:
+		typestr = "Disk";
+		break;
+	case STYPE_PRINTQ:
+		typestr = "Printer";
+		break;
+	case STYPE_DEVICE:
+		typestr = "Device";
+		break;
+	case STYPE_IPC:
+		typestr = "IPC";
+		break;
+        }
+	/* FIXME: If the remote machine returns non-ascii characters
+	   in any of these fields, they can corrupt the output.  We
+	   should remove them. */
+	if (!grepable) {
+		d_printf("\t%-15s %-10.10s%s\n",
+               		name,typestr,comment);
+	} else {
+		d_printf ("%s|%s|%s\n",typestr,name,comment);
+	}
+}
+
+static bool browse_host_rpc(bool sort)
+{
+	NTSTATUS status;
+	struct rpc_pipe_client *pipe_hnd = NULL;
+	TALLOC_CTX *frame = talloc_stackframe();
+	WERROR werr;
+	struct srvsvc_NetShareInfoCtr info_ctr;
+	struct srvsvc_NetShareCtr1 ctr1;
+	uint32_t resume_handle = 0;
+	uint32_t total_entries = 0;
+	int i;
+
+	status = cli_rpc_pipe_open_noauth(cli, &ndr_table_srvsvc.syntax_id,
+					  &pipe_hnd);
+
+	if (!NT_STATUS_IS_OK(status)) {
+		DEBUG(10, ("Could not connect to srvsvc pipe: %s\n",
+			   nt_errstr(status)));
+		TALLOC_FREE(frame);
+		return false;
+	}
+
+	ZERO_STRUCT(info_ctr);
+	ZERO_STRUCT(ctr1);
+
+	info_ctr.level = 1;
+	info_ctr.ctr.ctr1 = &ctr1;
+
+	status = rpccli_srvsvc_NetShareEnumAll(pipe_hnd, frame,
+					      pipe_hnd->desthost,
+					      &info_ctr,
+					      0xffffffff,
+					      &total_entries,
+					      &resume_handle,
+					      &werr);
+
+	if (!NT_STATUS_IS_OK(status) || !W_ERROR_IS_OK(werr)) {
+		TALLOC_FREE(pipe_hnd);
+		TALLOC_FREE(frame);
+		return false;
+	}
+
+	for (i=0; i < info_ctr.ctr.ctr1->count; i++) {
+		struct srvsvc_NetShareInfo1 info = info_ctr.ctr.ctr1->array[i];
+		browse_fn(info.name, info.type, info.comment, NULL);
+	}
+
+	TALLOC_FREE(pipe_hnd);
+	TALLOC_FREE(frame);
+	return true;
+}
+
+/****************************************************************************
+ Try and browse available connections on a host.
+****************************************************************************/
+
+static bool browse_host(bool sort)
+{
+	int ret;
+	if (!grepable) {
+	        d_printf("\n\tSharename       Type      Comment\n");
+	        d_printf("\t---------       ----      -------\n");
+	}
+
+	if (browse_host_rpc(sort)) {
+		return true;
+	}
+
+	if((ret = cli_RNetShareEnum(cli, browse_fn, NULL)) == -1)
+		d_printf("Error returning browse list: %s\n", cli_errstr(cli));
+
+	return (ret != -1);
+}
+
+/****************************************************************************
+ List a server name.
+****************************************************************************/
+
+static void server_fn(const char *name, uint32 m,
+                      const char *comment, void *state)
+{
+
+	if (!grepable){
+		d_printf("\t%-16s     %s\n", name, comment);
+	} else {
+		d_printf("%s|%s|%s\n",(char *)state, name, comment);
+	}
+}
+
+/****************************************************************************
+ Try and browse available connections on a host.
+****************************************************************************/
+
+static bool list_servers(const char *wk_grp)
+{
+	fstring state;
+
+	if (!cli->server_domain)
+		return false;
+
+	if (!grepable) {
+        	d_printf("\n\tServer               Comment\n");
+        	d_printf("\t---------            -------\n");
+	};
+	fstrcpy( state, "Server" );
+	cli_NetServerEnum(cli, cli->server_domain, SV_TYPE_ALL, server_fn,
+			  state);
+
+	if (!grepable) {
+	        d_printf("\n\tWorkgroup            Master\n");
+	        d_printf("\t---------            -------\n");
+	};
+
+	fstrcpy( state, "Workgroup" );
+	cli_NetServerEnum(cli, cli->server_domain, SV_TYPE_DOMAIN_ENUM,
+			  server_fn, state);
+	return true;
+}
+
+/****************************************************************************
+ Print or set current VUID
+****************************************************************************/
+
+static int cmd_vuid(void)
+{
+	TALLOC_CTX *ctx = talloc_tos();
+	char *buf;
+
+	if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
+		d_printf("Current VUID is %d\n", cli->vuid);
+		return 0;
+	}
+
+	cli->vuid = atoi(buf);
+	return 0;
+}
+
+/****************************************************************************
+ Setup a new VUID, by issuing a session setup
+****************************************************************************/
+
+static int cmd_logon(void)
+{
+	TALLOC_CTX *ctx = talloc_tos();
+	char *l_username, *l_password;
+
+	if (!next_token_talloc(ctx, &cmd_ptr,&l_username,NULL)) {
+		d_printf("logon <username> [<password>]\n");
+		return 0;
+	}
+
+	if (!next_token_talloc(ctx, &cmd_ptr,&l_password,NULL)) {
+		char *pass = getpass("Password: ");
+		if (pass) {
+			l_password = talloc_strdup(ctx,pass);
+		}
+	}
+	if (!l_password) {
+		return 1;
+	}
+
+	if (!NT_STATUS_IS_OK(cli_session_setup(cli, l_username,
+					       l_password, strlen(l_password),
+					       l_password, strlen(l_password),
+					       lp_workgroup()))) {
+		d_printf("session setup failed: %s\n", cli_errstr(cli));
+		return -1;
+	}
+
+	d_printf("Current VUID is %d\n", cli->vuid);
+	return 0;
+}
+
+
+/****************************************************************************
+ list active connections
+****************************************************************************/
+
+static int cmd_list_connect(void)
+{
+	cli_cm_display(cli);
+	return 0;
+}
+
+/****************************************************************************
+ display the current active client connection
+****************************************************************************/
+
+static int cmd_show_connect( void )
+{
+	TALLOC_CTX *ctx = talloc_tos();
+	struct cli_state *targetcli;
+	char *targetpath;
+
+	if (!cli_resolve_path(ctx, "", auth_info, cli, client_get_cur_dir(),
+				&targetcli, &targetpath ) ) {
+		d_printf("showconnect %s: %s\n", cur_dir, cli_errstr(cli));
+		return 1;
+	}
+
+	d_printf("//%s/%s\n", targetcli->desthost, targetcli->share);
+	return 0;
+}
+
+/****************************************************************************
+ iosize command
+***************************************************************************/
+
+int cmd_iosize(void)
+{
+	TALLOC_CTX *ctx = talloc_tos();
+	char *buf;
+	int iosize;
+
+	if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
+		if (!smb_encrypt) {
+			d_printf("iosize <n> or iosize 0x<n>. "
+				"Minimum is 16384 (0x4000), "
+				"max is 16776960 (0xFFFF00)\n");
+		} else {
+			d_printf("iosize <n> or iosize 0x<n>. "
+				"(Encrypted connection) ,"
+				"Minimum is 16384 (0x4000), "
+				"max is 130048 (0x1FC00)\n");
+		}
+		return 1;
+	}
+
+	iosize = strtol(buf,NULL,0);
+	if (smb_encrypt && (iosize < 0x4000 || iosize > 0xFC00)) {
+		d_printf("iosize out of range for encrypted "
+			"connection (min = 16384 (0x4000), "
+			"max = 130048 (0x1FC00)");
+		return 1;
+	} else if (!smb_encrypt && (iosize < 0x4000 || iosize > 0xFFFF00)) {
+		d_printf("iosize out of range (min = 16384 (0x4000), "
+			"max = 16776960 (0xFFFF00)");
+		return 1;
+	}
+
+	io_bufsize = iosize;
+	d_printf("iosize is now %d\n", io_bufsize);
+	return 0;
+}
+
+
+/* Some constants for completing filename arguments */
+
+#define COMPL_NONE        0          /* No completions */
+#define COMPL_REMOTE      1          /* Complete remote filename */
+#define COMPL_LOCAL       2          /* Complete local filename */
+
+/* This defines the commands supported by this client.
+ * NOTE: The "!" must be the last one in the list because it's fn pointer
+ *       field is NULL, and NULL in that field is used in process_tok()
+ *       (below) to indicate the end of the list.  crh
+ */
+static struct {
+	const char *name;
+	int (*fn)(void);
+	const char *description;
+	char compl_args[2];      /* Completion argument info */
+} commands[] = {
+  {"?",cmd_help,"[command] give help on a command",{COMPL_NONE,COMPL_NONE}},
+  {"allinfo",cmd_allinfo,"<file> show all available info",
+   {COMPL_NONE,COMPL_NONE}},
+  {"altname",cmd_altname,"<file> show alt name",{COMPL_NONE,COMPL_NONE}},
+  {"archive",cmd_archive,"<level>\n0=ignore archive bit\n1=only get archive files\n2=only get archive files and reset archive bit\n3=get all files and reset archive bit",{COMPL_NONE,COMPL_NONE}},
+  {"blocksize",cmd_block,"blocksize <number> (default 20)",{COMPL_NONE,COMPL_NONE}},
+  {"cancel",cmd_cancel,"<jobid> cancel a print queue entry",{COMPL_NONE,COMPL_NONE}},
+  {"case_sensitive",cmd_setcase,"toggle the case sensitive flag to server",{COMPL_NONE,COMPL_NONE}},
+  {"cd",cmd_cd,"[directory] change/report the remote directory",{COMPL_REMOTE,COMPL_NONE}},
+  {"chmod",cmd_chmod,"<src> <mode> chmod a file using UNIX permission",{COMPL_REMOTE,COMPL_REMOTE}},
+  {"chown",cmd_chown,"<src> <uid> <gid> chown a file using UNIX uids and gids",{COMPL_REMOTE,COMPL_REMOTE}},
+  {"close",cmd_close,"<fid> close a file given a fid",{COMPL_REMOTE,COMPL_REMOTE}},
+  {"del",cmd_del,"<mask> delete all matching files",{COMPL_REMOTE,COMPL_NONE}},
+  {"dir",cmd_dir,"<mask> list the contents of the current directory",{COMPL_REMOTE,COMPL_NONE}},
+  {"du",cmd_du,"<mask> computes the total size of the current directory",{COMPL_REMOTE,COMPL_NONE}},
+  {"echo",cmd_echo,"ping the server",{COMPL_NONE,COMPL_NONE}},
+  {"exit",cmd_quit,"logoff the server",{COMPL_NONE,COMPL_NONE}},
+  {"get",cmd_get,"<remote name> [local name] get a file",{COMPL_REMOTE,COMPL_LOCAL}},
+  {"getfacl",cmd_getfacl,"<file name> get the POSIX ACL on a file (UNIX extensions only)",{COMPL_REMOTE,COMPL_LOCAL}},
+  {"hardlink",cmd_hardlink,"<src> <dest> create a Windows hard link",{COMPL_REMOTE,COMPL_REMOTE}},
+  {"help",cmd_help,"[command] give help on a command",{COMPL_NONE,COMPL_NONE}},
+  {"history",cmd_history,"displays the command history",{COMPL_NONE,COMPL_NONE}},
+  {"iosize",cmd_iosize,"iosize <number> (default 64512)",{COMPL_NONE,COMPL_NONE}},
+  {"lcd",cmd_lcd,"[directory] change/report the local current working directory",{COMPL_LOCAL,COMPL_NONE}},
+  {"link",cmd_link,"<oldname> <newname> create a UNIX hard link",{COMPL_REMOTE,COMPL_REMOTE}},
+  {"lock",cmd_lock,"lock <fnum> [r|w] <hex-start> <hex-len> : set a POSIX lock",{COMPL_REMOTE,COMPL_REMOTE}},
+  {"lowercase",cmd_lowercase,"toggle lowercasing of filenames for get",{COMPL_NONE,COMPL_NONE}},  
+  {"ls",cmd_dir,"<mask> list the contents of the current directory",{COMPL_REMOTE,COMPL_NONE}},
+  {"l",cmd_dir,"<mask> list the contents of the current directory",{COMPL_REMOTE,COMPL_NONE}},
+  {"mask",cmd_select,"<mask> mask all filenames against this",{COMPL_REMOTE,COMPL_NONE}},
+  {"md",cmd_mkdir,"<directory> make a directory",{COMPL_NONE,COMPL_NONE}},
+  {"mget",cmd_mget,"<mask> get all the matching files",{COMPL_REMOTE,COMPL_NONE}},
+  {"mkdir",cmd_mkdir,"<directory> make a directory",{COMPL_NONE,COMPL_NONE}},
+  {"more",cmd_more,"<remote name> view a remote file with your pager",{COMPL_REMOTE,COMPL_NONE}},  
+  {"mput",cmd_mput,"<mask> put all matching files",{COMPL_REMOTE,COMPL_NONE}},
+  {"newer",cmd_newer,"<file> only mget files newer than the specified local file",{COMPL_LOCAL,COMPL_NONE}},
+  {"open",cmd_open,"<mask> open a file",{COMPL_REMOTE,COMPL_NONE}},
+  {"posix", cmd_posix, "turn on all POSIX capabilities", {COMPL_REMOTE,COMPL_NONE}},
+  {"posix_encrypt",cmd_posix_encrypt,"<domain> <user> <password> start up transport encryption",{COMPL_REMOTE,COMPL_NONE}},
+  {"posix_open",cmd_posix_open,"<name> 0<mode> open_flags mode open a file using POSIX interface",{COMPL_REMOTE,COMPL_NONE}},
+  {"posix_mkdir",cmd_posix_mkdir,"<name> 0<mode> creates a directory using POSIX interface",{COMPL_REMOTE,COMPL_NONE}},
+  {"posix_rmdir",cmd_posix_rmdir,"<name> removes a directory using POSIX interface",{COMPL_REMOTE,COMPL_NONE}},
+  {"posix_unlink",cmd_posix_unlink,"<name> removes a file using POSIX interface",{COMPL_REMOTE,COMPL_NONE}},
+  {"print",cmd_print,"<file name> print a file",{COMPL_NONE,COMPL_NONE}},
+  {"prompt",cmd_prompt,"toggle prompting for filenames for mget and mput",{COMPL_NONE,COMPL_NONE}},  
+  {"put",cmd_put,"<local name> [remote name] put a file",{COMPL_LOCAL,COMPL_REMOTE}},
+  {"pwd",cmd_pwd,"show current remote directory (same as 'cd' with no args)",{COMPL_NONE,COMPL_NONE}},
+  {"q",cmd_quit,"logoff the server",{COMPL_NONE,COMPL_NONE}},
+  {"queue",cmd_queue,"show the print queue",{COMPL_NONE,COMPL_NONE}},
+  {"quit",cmd_quit,"logoff the server",{COMPL_NONE,COMPL_NONE}},
+  {"readlink",cmd_readlink,"filename Do a UNIX extensions readlink call on a symlink",{COMPL_REMOTE,COMPL_REMOTE}},
+  {"rd",cmd_rmdir,"<directory> remove a directory",{COMPL_NONE,COMPL_NONE}},
+  {"recurse",cmd_recurse,"toggle directory recursion for mget and mput",{COMPL_NONE,COMPL_NONE}},  
+  {"reget",cmd_reget,"<remote name> [local name] get a file restarting at end of local file",{COMPL_REMOTE,COMPL_LOCAL}},
+  {"rename",cmd_rename,"<src> <dest> rename some files",{COMPL_REMOTE,COMPL_REMOTE}},
+  {"reput",cmd_reput,"<local name> [remote name] put a file restarting at end of remote file",{COMPL_LOCAL,COMPL_REMOTE}},
+  {"rm",cmd_del,"<mask> delete all matching files",{COMPL_REMOTE,COMPL_NONE}},
+  {"rmdir",cmd_rmdir,"<directory> remove a directory",{COMPL_NONE,COMPL_NONE}},
+  {"showacls",cmd_showacls,"toggle if ACLs are shown or not",{COMPL_NONE,COMPL_NONE}},  
+  {"setmode",cmd_setmode,"filename <setmode string> change modes of file",{COMPL_REMOTE,COMPL_NONE}},
+  {"stat",cmd_stat,"filename Do a UNIX extensions stat call on a file",{COMPL_REMOTE,COMPL_REMOTE}},
+  {"symlink",cmd_symlink,"<oldname> <newname> create a UNIX symlink",{COMPL_REMOTE,COMPL_REMOTE}},
+  {"tar",cmd_tar,"tar <c|x>[IXFqbgNan] current directory to/from <file name>",{COMPL_NONE,COMPL_NONE}},
+  {"tarmode",cmd_tarmode,"<full|inc|reset|noreset> tar's behaviour towards archive bits",{COMPL_NONE,COMPL_NONE}},
+  {"translate",cmd_translate,"toggle text translation for printing",{COMPL_NONE,COMPL_NONE}},
+  {"unlock",cmd_unlock,"unlock <fnum> <hex-start> <hex-len> : remove a POSIX lock",{COMPL_REMOTE,COMPL_REMOTE}},
+  {"volume",cmd_volume,"print the volume name",{COMPL_NONE,COMPL_NONE}},
+  {"vuid",cmd_vuid,"change current vuid",{COMPL_NONE,COMPL_NONE}},
+  {"wdel",cmd_wdel,"<attrib> <mask> wildcard delete all matching files",{COMPL_REMOTE,COMPL_NONE}},
+  {"logon",cmd_logon,"establish new logon",{COMPL_NONE,COMPL_NONE}},
+  {"listconnect",cmd_list_connect,"list open connections",{COMPL_NONE,COMPL_NONE}},
+  {"showconnect",cmd_show_connect,"display the current active connection",{COMPL_NONE,COMPL_NONE}},
+  {"..",cmd_cd_oneup,"change the remote directory (up one level)",{COMPL_REMOTE,COMPL_NONE}},
+
+  /* Yes, this must be here, see crh's comment above. */
+  {"!",NULL,"run a shell command on the local system",{COMPL_NONE,COMPL_NONE}},
+  {NULL,NULL,NULL,{COMPL_NONE,COMPL_NONE}}
+};
+
+/*******************************************************************
+ Lookup a command string in the list of commands, including
+ abbreviations.
+******************************************************************/
+
+static int process_tok(char *tok)
+{
+	int i = 0, matches = 0;
+	int cmd=0;
+	int tok_len = strlen(tok);
+
+	while (commands[i].fn != NULL) {
+		if (strequal(commands[i].name,tok)) {
+			matches = 1;
+			cmd = i;
+			break;
+		} else if (strnequal(commands[i].name, tok, tok_len)) {
+			matches++;
+			cmd = i;
+		}
+		i++;
+	}
+
+	if (matches == 0)
+		return(-1);
+	else if (matches == 1)
+		return(cmd);
+	else
+		return(-2);
+}
+
+/****************************************************************************
+ Help.
+****************************************************************************/
+
+static int cmd_help(void)
+{
+	TALLOC_CTX *ctx = talloc_tos();
+	int i=0,j;
+	char *buf;
+
+	if (next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
+		if ((i = process_tok(buf)) >= 0)
+			d_printf("HELP %s:\n\t%s\n\n",
+				commands[i].name,commands[i].description);
+	} else {
+		while (commands[i].description) {
+			for (j=0; commands[i].description && (j<5); j++) {
+				d_printf("%-15s",commands[i].name);
+				i++;
+			}
+			d_printf("\n");
+		}
+	}
+	return 0;
+}
+
+/****************************************************************************
+ Process a -c command string.
+****************************************************************************/
+
+static int process_command_string(const char *cmd_in)
+{
+	TALLOC_CTX *ctx = talloc_tos();
+	char *cmd = talloc_strdup(ctx, cmd_in);
+	int rc = 0;
+
+	if (!cmd) {
+		return 1;
+	}
+	/* establish the connection if not already */
+
+	if (!cli) {
+		cli = cli_cm_open(talloc_tos(), NULL,
+				have_ip ? dest_ss_str : desthost,
+				service, auth_info,
+				true, smb_encrypt,
+				max_protocol, port, name_type);
+		if (!cli) {
+			return 1;
+		}
+	}
+
+	while (cmd[0] != '\0')    {
+		char *line;
+		char *p;
+		char *tok;
+		int i;
+
+		if ((p = strchr_m(cmd, ';')) == 0) {
+			line = cmd;
+			cmd += strlen(cmd);
+		} else {
+			*p = '\0';
+			line = cmd;
+			cmd = p + 1;
+		}
+
+		/* and get the first part of the command */
+		cmd_ptr = line;
+		if (!next_token_talloc(ctx, &cmd_ptr,&tok,NULL)) {
+			continue;
+		}
+
+		if ((i = process_tok(tok)) >= 0) {
+			rc = commands[i].fn();
+		} else if (i == -2) {
+			d_printf("%s: command abbreviation ambiguous\n",tok);
+		} else {
+			d_printf("%s: command not found\n",tok);
+		}
+	}
+
+	return rc;
+}
+
+#define MAX_COMPLETIONS 100
+
+typedef struct {
+	char *dirmask;
+	char **matches;
+	int count, samelen;
+	const char *text;
+	int len;
+} completion_remote_t;
+
+static void completion_remote_filter(const char *mnt,
+				file_info *f,
+				const char *mask,
+				void *state)
+{
+	completion_remote_t *info = (completion_remote_t *)state;
+
+	if ((info->count < MAX_COMPLETIONS - 1) &&
+			(strncmp(info->text, f->name, info->len) == 0) &&
+			(strcmp(f->name, ".") != 0) &&
+			(strcmp(f->name, "..") != 0)) {
+		if ((info->dirmask[0] == 0) && !(f->mode & aDIR))
+			info->matches[info->count] = SMB_STRDUP(f->name);
+		else {
+			TALLOC_CTX *ctx = talloc_stackframe();
+			char *tmp;
+
+			tmp = talloc_strdup(ctx,info->dirmask);
+			if (!tmp) {
+				TALLOC_FREE(ctx);
+				return;
+			}
+			tmp = talloc_asprintf_append(tmp, "%s", f->name);
+			if (!tmp) {
+				TALLOC_FREE(ctx);
+				return;
+			}
+			if (f->mode & aDIR) {
+				tmp = talloc_asprintf_append(tmp, "%s", CLI_DIRSEP_STR);
+			}
+			if (!tmp) {
+				TALLOC_FREE(ctx);
+				return;
+			}
+			info->matches[info->count] = SMB_STRDUP(tmp);
+			TALLOC_FREE(ctx);
+		}
+		if (info->matches[info->count] == NULL) {
+			return;
+		}
+		if (f->mode & aDIR) {
+			smb_readline_ca_char(0);
+		}
+		if (info->count == 1) {
+			info->samelen = strlen(info->matches[info->count]);
+		} else {
+			while (strncmp(info->matches[info->count],
+						info->matches[info->count-1],
+						info->samelen) != 0) {
+				info->samelen--;
+			}
+		}
+		info->count++;
+	}
+}
+
+static char **remote_completion(const char *text, int len)
+{
+	TALLOC_CTX *ctx = talloc_stackframe();
+	char *dirmask = NULL;
+	char *targetpath = NULL;
+	struct cli_state *targetcli = NULL;
+	int i;
+	completion_remote_t info = { NULL, NULL, 1, 0, NULL, 0 };
+
+	/* can't have non-static intialisation on Sun CC, so do it
+	   at run time here */
+	info.samelen = len;
+	info.text = text;
+	info.len = len;
+
+	info.matches = SMB_MALLOC_ARRAY(char *,MAX_COMPLETIONS);
+	if (!info.matches) {
+		TALLOC_FREE(ctx);
+		return NULL;
+	}
+
+	/*
+	 * We're leaving matches[0] free to fill it later with the text to
+	 * display: Either the one single match or the longest common subset
+	 * of the matches.
+	 */
+	info.matches[0] = NULL;
+	info.count = 1;
+
+	for (i = len-1; i >= 0; i--) {
+		if ((text[i] == '/') || (text[i] == CLI_DIRSEP_CHAR)) {
+			break;
+		}
+	}
+
+	info.text = text+i+1;
+	info.samelen = info.len = len-i-1;
+
+	if (i > 0) {
+		info.dirmask = SMB_MALLOC_ARRAY(char, i+2);
+		if (!info.dirmask) {
+			goto cleanup;
+		}
+		strncpy(info.dirmask, text, i+1);
+		info.dirmask[i+1] = 0;
+		dirmask = talloc_asprintf(ctx,
+					"%s%*s*",
+					client_get_cur_dir(),
+					i-1,
+					text);
+	} else {
+		info.dirmask = SMB_STRDUP("");
+		if (!info.dirmask) {
+			goto cleanup;
+		}
+		dirmask = talloc_asprintf(ctx,
+					"%s*",
+					client_get_cur_dir());
+	}
+	if (!dirmask) {
+		goto cleanup;
+	}
+
+	if (!cli_resolve_path(ctx, "", auth_info, cli, dirmask, &targetcli, &targetpath)) {
+		goto cleanup;
+	}
+	if (cli_list(targetcli, targetpath, aDIR | aSYSTEM | aHIDDEN,
+				completion_remote_filter, (void *)&info) < 0) {
+		goto cleanup;
+	}
+
+	if (info.count == 1) {
+		/*
+		 * No matches at all, NULL indicates there is nothing
+		 */
+		SAFE_FREE(info.matches[0]);
+		SAFE_FREE(info.matches);
+		TALLOC_FREE(ctx);
+		return NULL;
+	}
+
+	if (info.count == 2) {
+		/*
+		 * Exactly one match in matches[1], indicate this is the one
+		 * in matches[0].
+		 */
+		info.matches[0] = info.matches[1];
+		info.matches[1] = NULL;
+		info.count -= 1;
+		TALLOC_FREE(ctx);
+		return info.matches;
+	}
+
+	/*
+	 * We got more than one possible match, set the result to the maximum
+	 * common subset
+	 */
+
+	info.matches[0] = SMB_STRNDUP(info.matches[1], info.samelen);
+	info.matches[info.count] = NULL;
+	return info.matches;
+
+cleanup:
+	for (i = 0; i < info.count; i++) {
+		SAFE_FREE(info.matches[i]);
+	}
+	SAFE_FREE(info.matches);
+	SAFE_FREE(info.dirmask);
+	TALLOC_FREE(ctx);
+	return NULL;
+}
+
+static char **completion_fn(const char *text, int start, int end)
+{
+	smb_readline_ca_char(' ');
+
+	if (start) {
+		const char *buf, *sp;
+		int i;
+		char compl_type;
+
+		buf = smb_readline_get_line_buffer();
+		if (buf == NULL)
+			return NULL;
+
+		sp = strchr(buf, ' ');
+		if (sp == NULL)
+			return NULL;
+
+		for (i = 0; commands[i].name; i++) {
+			if ((strncmp(commands[i].name, buf, sp - buf) == 0) &&
+			    (commands[i].name[sp - buf] == 0)) {
+				break;
+			}
+		}
+		if (commands[i].name == NULL)
+			return NULL;
+
+		while (*sp == ' ')
+			sp++;
+
+		if (sp == (buf + start))
+			compl_type = commands[i].compl_args[0];
+		else
+			compl_type = commands[i].compl_args[1];
+
+		if (compl_type == COMPL_REMOTE)
+			return remote_completion(text, end - start);
+		else /* fall back to local filename completion */
+			return NULL;
+	} else {
+		char **matches;
+		int i, len, samelen = 0, count=1;
+
+		matches = SMB_MALLOC_ARRAY(char *, MAX_COMPLETIONS);
+		if (!matches) {
+			return NULL;
+		}
+		matches[0] = NULL;
+
+		len = strlen(text);
+		for (i=0;commands[i].fn && count < MAX_COMPLETIONS-1;i++) {
+			if (strncmp(text, commands[i].name, len) == 0) {
+				matches[count] = SMB_STRDUP(commands[i].name);
+				if (!matches[count])
+					goto cleanup;
+				if (count == 1)
+					samelen = strlen(matches[count]);
+				else
+					while (strncmp(matches[count], matches[count-1], samelen) != 0)
+						samelen--;
+				count++;
+			}
+		}
+
+		switch (count) {
+		case 0:	/* should never happen */
+		case 1:
+			goto cleanup;
+		case 2:
+			matches[0] = SMB_STRDUP(matches[1]);
+			break;
+		default:
+			matches[0] = (char *)SMB_MALLOC(samelen+1);
+			if (!matches[0])
+				goto cleanup;
+			strncpy(matches[0], matches[1], samelen);
+			matches[0][samelen] = 0;
+		}
+		matches[count] = NULL;
+		return matches;
+
+cleanup:
+		for (i = 0; i < count; i++)
+			free(matches[i]);
+
+		free(matches);
+		return NULL;
+	}
+}
+
+static bool finished;
+
+/****************************************************************************
+ Make sure we swallow keepalives during idle time.
+****************************************************************************/
+
+static void readline_callback(void)
+{
+	fd_set fds;
+	struct timeval timeout;
+	static time_t last_t;
+	time_t t;
+
+	t = time(NULL);
+
+	if (t - last_t < 5)
+		return;
+
+	last_t = t;
+
+ again:
+
+	if (cli->fd == -1)
+		return;
+
+	FD_ZERO(&fds);
+	FD_SET(cli->fd,&fds);
+
+	timeout.tv_sec = 0;
+	timeout.tv_usec = 0;
+	sys_select_intr(cli->fd+1,&fds,NULL,NULL,&timeout);
+
+	/* We deliberately use receive_smb_raw instead of
+	   client_receive_smb as we want to receive
+	   session keepalives and then drop them here.
+	*/
+	if (FD_ISSET(cli->fd,&fds)) {
+		NTSTATUS status;
+		size_t len;
+
+		set_smb_read_error(&cli->smb_rw_error, SMB_READ_OK);
+
+		status = receive_smb_raw(cli->fd, cli->inbuf, cli->bufsize, 0, 0, &len);
+
+		if (!NT_STATUS_IS_OK(status)) {
+			DEBUG(0, ("Read from server failed, maybe it closed "
+				  "the connection\n"));
+
+			finished = true;
+			smb_readline_done();
+			if (NT_STATUS_EQUAL(status, NT_STATUS_END_OF_FILE)) {
+				set_smb_read_error(&cli->smb_rw_error,
+						   SMB_READ_EOF);
+				return;
+			}
+
+			if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) {
+				set_smb_read_error(&cli->smb_rw_error,
+						   SMB_READ_TIMEOUT);
+				return;
+			}
+
+			set_smb_read_error(&cli->smb_rw_error, SMB_READ_ERROR);
+			return;
+		}
+		if(CVAL(cli->inbuf,0) != SMBkeepalive) {
+			DEBUG(0, ("Read from server "
+				"returned unexpected packet!\n"));
+			return;
+		}
+
+		goto again;
+	}
+
+	/* Ping the server to keep the connection alive using SMBecho. */
+	{
+		NTSTATUS status;
+		unsigned char garbage[16];
+		memset(garbage, 0xf0, sizeof(garbage));
+		status = cli_echo(cli, 1, data_blob_const(garbage, sizeof(garbage)));
+
+		if (!NT_STATUS_IS_OK(status)) {
+			DEBUG(0, ("SMBecho failed. Maybe server has closed "
+				"the connection\n"));
+			finished = true;
+			smb_readline_done();
+		}
+	}
+}
+
+/****************************************************************************
+ Process commands on stdin.
+****************************************************************************/
+
+static int process_stdin(void)
+{
+	int rc = 0;
+
+	while (!finished) {
+		TALLOC_CTX *frame = talloc_stackframe();
+		char *tok = NULL;
+		char *the_prompt = NULL;
+		char *line = NULL;
+		int i;
+
+		/* display a prompt */
+		if (asprintf(&the_prompt, "smb: %s> ", client_get_cur_dir()) < 0) {
+			TALLOC_FREE(frame);
+			break;
+		}
+		line = smb_readline(the_prompt, readline_callback, completion_fn);
+		SAFE_FREE(the_prompt);
+		if (!line) {
+			TALLOC_FREE(frame);
+			break;
+		}
+
+		/* special case - first char is ! */
+		if (*line == '!') {
+			if (system(line + 1) == -1) {
+				d_printf("system() command %s failed.\n",
+					line+1);
+			}
+			SAFE_FREE(line);
+			TALLOC_FREE(frame);
+			continue;
+		}
+
+		/* and get the first part of the command */
+		cmd_ptr = line;
+		if (!next_token_talloc(frame, &cmd_ptr,&tok,NULL)) {
+			TALLOC_FREE(frame);
+			SAFE_FREE(line);
+			continue;
+		}
+
+		if ((i = process_tok(tok)) >= 0) {
+			rc = commands[i].fn();
+		} else if (i == -2) {
+			d_printf("%s: command abbreviation ambiguous\n",tok);
+		} else {
+			d_printf("%s: command not found\n",tok);
+		}
+		SAFE_FREE(line);
+		TALLOC_FREE(frame);
+	}
+	return rc;
+}
+
+/****************************************************************************
+ Process commands from the client.
+****************************************************************************/
+
+static int process(const char *base_directory)
+{
+	int rc = 0;
+
+	cli = cli_cm_open(talloc_tos(), NULL,
+			have_ip ? dest_ss_str : desthost,
+			service, auth_info, true, smb_encrypt,
+			max_protocol, port, name_type);
+	if (!cli) {
+		return 1;
+	}
+
+	if (base_directory && *base_directory) {
+		rc = do_cd(base_directory);
+		if (rc) {
+			cli_shutdown(cli);
+			return rc;
+		}
+	}
+
+	if (cmdstr) {
+		rc = process_command_string(cmdstr);
+	} else {
+		process_stdin();
+	}
+
+	cli_shutdown(cli);
+	return rc;
+}
+
+/****************************************************************************
+ Handle a -L query.
+****************************************************************************/
+
+static int do_host_query(const char *query_host)
+{
+	cli = cli_cm_open(talloc_tos(), NULL,
+			query_host, "IPC$", auth_info, true, smb_encrypt,
+			max_protocol, port, name_type);
+	if (!cli)
+		return 1;
+
+	browse_host(true);
+
+	/* Ensure that the host can do IPv4 */
+
+	if (!interpret_addr(query_host)) {
+		struct sockaddr_storage ss;
+		if (interpret_string_addr(&ss, query_host, 0) &&
+				(ss.ss_family != AF_INET)) {
+			d_printf("%s is an IPv6 address -- no workgroup available\n",
+				query_host);
+			return 1;
+		}
+	}
+
+	if (port != 139) {
+
+		/* Workgroups simply don't make sense over anything
+		   else but port 139... */
+
+		cli_shutdown(cli);
+		cli = cli_cm_open(talloc_tos(), NULL,
+				query_host, "IPC$", auth_info, true, smb_encrypt,
+				max_protocol, 139, name_type);
+	}
+
+	if (cli == NULL) {
+		d_printf("NetBIOS over TCP disabled -- no workgroup available\n");
+		return 1;
+	}
+
+	list_servers(lp_workgroup());
+
+	cli_shutdown(cli);
+
+	return(0);
+}
+
+/****************************************************************************
+ Handle a tar operation.
+****************************************************************************/
+
+static int do_tar_op(const char *base_directory)
+{
+	int ret;
+
+	/* do we already have a connection? */
+	if (!cli) {
+		cli = cli_cm_open(talloc_tos(), NULL,
+			have_ip ? dest_ss_str : desthost,
+			service, auth_info, true, smb_encrypt,
+			max_protocol, port, name_type);
+		if (!cli)
+			return 1;
+	}
+
+	recurse=true;
+
+	if (base_directory && *base_directory)  {
+		ret = do_cd(base_directory);
+		if (ret) {
+			cli_shutdown(cli);
+			return ret;
+		}
+	}
+
+	ret=process_tar();
+
+	cli_shutdown(cli);
+
+	return(ret);
+}
+
+/****************************************************************************
+ Handle a message operation.
+****************************************************************************/
+
+static int do_message_op(struct user_auth_info *a_info)
+{
+	struct sockaddr_storage ss;
+	struct nmb_name called, calling;
+	fstring server_name;
+	char name_type_hex[10];
+	int msg_port;
+	NTSTATUS status;
+
+	make_nmb_name(&calling, calling_name, 0x0);
+	make_nmb_name(&called , desthost, name_type);
+
+	fstrcpy(server_name, desthost);
+	snprintf(name_type_hex, sizeof(name_type_hex), "#%X", name_type);
+	fstrcat(server_name, name_type_hex);
+
+        zero_sockaddr(&ss);
+	if (have_ip)
+		ss = dest_ss;
+
+	/* we can only do messages over port 139 (to windows clients at least) */
+
+	msg_port = port ? port : 139;
+
+	if (!(cli=cli_initialise())) {
+		d_printf("Connection to %s failed\n", desthost);
+		return 1;
+	}
+	cli_set_port(cli, msg_port);
+
+	status = cli_connect(cli, server_name, &ss);
+	if (!NT_STATUS_IS_OK(status)) {
+		d_printf("Connection to %s failed. Error %s\n", desthost, nt_errstr(status));
+		return 1;
+	}
+
+	if (!cli_session_request(cli, &calling, &called)) {
+		d_printf("session request failed\n");
+		cli_shutdown(cli);
+		return 1;
+	}
+
+	send_message(get_cmdline_auth_info_username(a_info));
+	cli_shutdown(cli);
+
+	return 0;
+}
+
+/****************************************************************************
+  main program
+****************************************************************************/
+
+ int main(int argc,char *argv[])
+{
+	char *base_directory = NULL;
+	int opt;
+	char *query_host = NULL;
+	bool message = false;
+	static const char *new_name_resolve_order = NULL;
+	poptContext pc;
+	char *p;
+	int rc = 0;
+	fstring new_workgroup;
+	bool tar_opt = false;
+	bool service_opt = false;
+	struct poptOption long_options[] = {
+		POPT_AUTOHELP
+
+		{ "name-resolve", 'R', POPT_ARG_STRING, &new_name_resolve_order, 'R', "Use these name resolution services only", "NAME-RESOLVE-ORDER" },
+		{ "message", 'M', POPT_ARG_STRING, NULL, 'M', "Send message", "HOST" },
+		{ "ip-address", 'I', POPT_ARG_STRING, NULL, 'I', "Use this IP to connect to", "IP" },
+		{ "stderr", 'E', POPT_ARG_NONE, NULL, 'E', "Write messages to stderr instead of stdout" },
+		{ "list", 'L', POPT_ARG_STRING, NULL, 'L', "Get a list of shares available on a host", "HOST" },
+		{ "max-protocol", 'm', POPT_ARG_STRING, NULL, 'm', "Set the max protocol level", "LEVEL" },
+		{ "tar", 'T', POPT_ARG_STRING, NULL, 'T', "Command line tar", "<c|x>IXFqgbNan" },
+		{ "directory", 'D', POPT_ARG_STRING, NULL, 'D', "Start from directory", "DIR" },
+		{ "command", 'c', POPT_ARG_STRING, &cmdstr, 'c', "Execute semicolon separated commands" }, 
+		{ "send-buffer", 'b', POPT_ARG_INT, &io_bufsize, 'b', "Changes the transmit/send buffer", "BYTES" },
+		{ "port", 'p', POPT_ARG_INT, &port, 'p', "Port to connect to", "PORT" },
+		{ "grepable", 'g', POPT_ARG_NONE, NULL, 'g', "Produce grepable output" },
+                { "browse", 'B', POPT_ARG_NONE, NULL, 'B', "Browse SMB servers using DNS" },
+		POPT_COMMON_SAMBA
+		POPT_COMMON_CONNECTION
+		POPT_COMMON_CREDENTIALS
+		POPT_TABLEEND
+	};
+	TALLOC_CTX *frame = talloc_stackframe();
+
+	if (!client_set_cur_dir("\\")) {
+		exit(ENOMEM);
+	}
+
+	/* initialize the workgroup name so we can determine whether or
+	   not it was set by a command line option */
+
+	set_global_myworkgroup( "" );
+	set_global_myname( "" );
+
+        /* set default debug level to 1 regardless of what smb.conf sets */
+	setup_logging( "smbclient", true );
+	DEBUGLEVEL_CLASS[DBGC_ALL] = 1;
+	if ((dbf = x_fdup(x_stderr))) {
+		x_setbuf( dbf, NULL );
+	}
+
+	load_case_tables();
+
+	auth_info = user_auth_info_init(frame);
+	if (auth_info == NULL) {
+		exit(1);
+	}
+	popt_common_set_auth_info(auth_info);
+
+	/* skip argv(0) */
+	pc = poptGetContext("smbclient", argc, (const char **) argv, long_options, 0);
+	poptSetOtherOptionHelp(pc, "service <password>");
+
+        lp_set_in_client(true); /* Make sure that we tell lp_load we are */
+
+	while ((opt = poptGetNextOpt(pc)) != -1) {
+
+		/* if the tar option has been called previouslt, now we need to eat out the leftovers */
+		/* I see no other way to keep things sane --SSS */
+		if (tar_opt == true) {
+			while (poptPeekArg(pc)) {
+				poptGetArg(pc);
+			}
+			tar_opt = false;
+		}
+
+		/* if the service has not yet been specified lets see if it is available in the popt stack */
+		if (!service_opt && poptPeekArg(pc)) {
+			service = talloc_strdup(frame, poptGetArg(pc));
+			if (!service) {
+				exit(ENOMEM);
+			}
+			service_opt = true;
+		}
+
+		/* if the service has already been retrieved then check if we have also a password */
+		if (service_opt
+		    && (!get_cmdline_auth_info_got_pass(auth_info))
+		    && poptPeekArg(pc)) {
+			set_cmdline_auth_info_password(auth_info,
+						       poptGetArg(pc));
+		}
+
+		switch (opt) {
+		case 'M':
+			/* Messages are sent to NetBIOS name type 0x3
+			 * (Messenger Service).  Make sure we default
+			 * to port 139 instead of port 445. srl,crh
+			 */
+			name_type = 0x03;
+			desthost = talloc_strdup(frame,poptGetOptArg(pc));
+			if (!desthost) {
+				exit(ENOMEM);
+			}
+			if( !port )
+				port = 139;
+ 			message = true;
+ 			break;
+		case 'I':
+			{
+				if (!interpret_string_addr(&dest_ss, poptGetOptArg(pc), 0)) {
+					exit(1);
+				}
+				have_ip = true;
+				print_sockaddr(dest_ss_str, sizeof(dest_ss_str), &dest_ss);
+			}
+			break;
+		case 'E':
+			if (dbf) {
+				x_fclose(dbf);
+			}
+			dbf = x_stderr;
+			display_set_stderr();
+			break;
+
+		case 'L':
+			query_host = talloc_strdup(frame, poptGetOptArg(pc));
+			if (!query_host) {
+				exit(ENOMEM);
+			}
+			break;
+		case 'm':
+			max_protocol = interpret_protocol(poptGetOptArg(pc), max_protocol);
+			break;
+		case 'T':
+			/* We must use old option processing for this. Find the
+			 * position of the -T option in the raw argv[]. */
+			{
+				int i;
+				for (i = 1; i < argc; i++) {
+					if (strncmp("-T", argv[i],2)==0)
+						break;
+				}
+				i++;
+				if (!tar_parseargs(argc, argv, poptGetOptArg(pc), i)) {
+					poptPrintUsage(pc, stderr, 0);
+					exit(1);
+				}
+			}
+			/* this must be the last option, mark we have parsed it so that we know we have */
+			tar_opt = true;
+			break;
+		case 'D':
+			base_directory = talloc_strdup(frame, poptGetOptArg(pc));
+			if (!base_directory) {
+				exit(ENOMEM);
+			}
+			break;
+		case 'g':
+			grepable=true;
+			break;
+		case 'e':
+			smb_encrypt=true;
+			break;
+		case 'B':
+			return(do_smb_browse());
+
+		}
+	}
+
+	/* We may still have some leftovers after the last popt option has been called */
+	if (tar_opt == true) {
+		while (poptPeekArg(pc)) {
+			poptGetArg(pc);
+		}
+		tar_opt = false;
+	}
+
+	/* if the service has not yet been specified lets see if it is available in the popt stack */
+	if (!service_opt && poptPeekArg(pc)) {
+		service = talloc_strdup(frame,poptGetArg(pc));
+		if (!service) {
+			exit(ENOMEM);
+		}
+		service_opt = true;
+	}
+
+	/* if the service has already been retrieved then check if we have also a password */
+	if (service_opt
+	    && !get_cmdline_auth_info_got_pass(auth_info)
+	    && poptPeekArg(pc)) {
+		set_cmdline_auth_info_password(auth_info,
+					       poptGetArg(pc));
+	}
+
+	/*
+	 * Don't load debug level from smb.conf. It should be
+	 * set by cmdline arg or remain default (0)
+	 */
+	AllowDebugChange = false;
+
+	/* save the workgroup...
+
+	   FIXME!! do we need to do this for other options as well
+	   (or maybe a generic way to keep lp_load() from overwriting
+	   everything)?  */
+
+	fstrcpy( new_workgroup, lp_workgroup() );
+	calling_name = talloc_strdup(frame, global_myname() );
+	if (!calling_name) {
+		exit(ENOMEM);
+	}
+
+	if ( override_logfile )
+		setup_logging( lp_logfile(), false );
+
+	if (!lp_load(get_dyn_CONFIGFILE(),true,false,false,true)) {
+		fprintf(stderr, "%s: Can't load %s - run testparm to debug it\n",
+			argv[0], get_dyn_CONFIGFILE());
+	}
+
+	if (get_cmdline_auth_info_use_machine_account(auth_info) &&
+	    !set_cmdline_auth_info_machine_account_creds(auth_info)) {
+		exit(-1);
+	}
+
+	load_interfaces();
+
+	if (service_opt && service) {
+		size_t len;
+
+		/* Convert any '/' characters in the service name to '\' characters */
+		string_replace(service, '/','\\');
+		if (count_chars(service,'\\') < 3) {
+			d_printf("\n%s: Not enough '\\' characters in service\n",service);
+			poptPrintUsage(pc, stderr, 0);
+			exit(1);
+		}
+		/* Remove trailing slashes */
+		len = strlen(service);
+		while(len > 0 && service[len - 1] == '\\') {
+			--len;
+			service[len] = '\0';
+		}
+	}
+
+	if ( strlen(new_workgroup) != 0 ) {
+		set_global_myworkgroup( new_workgroup );
+	}
+
+	if ( strlen(calling_name) != 0 ) {
+		set_global_myname( calling_name );
+	} else {
+		TALLOC_FREE(calling_name);
+		calling_name = talloc_strdup(frame, global_myname() );
+	}
+
+	smb_encrypt = get_cmdline_auth_info_smb_encrypt(auth_info);
+	if (!init_names()) {
+		fprintf(stderr, "init_names() failed\n");
+		exit(1);
+	}
+
+	if(new_name_resolve_order)
+		lp_set_name_resolve_order(new_name_resolve_order);
+
+	if (!tar_type && !query_host && !service && !message) {
+		poptPrintUsage(pc, stderr, 0);
+		exit(1);
+	}
+
+	poptFreeContext(pc);
+
+	DEBUG(3,("Client started (version %s).\n", samba_version_string()));
+
+	/* Ensure we have a password (or equivalent). */
+	set_cmdline_auth_info_getpass(auth_info);
+
+	if (tar_type) {
+		if (cmdstr)
+			process_command_string(cmdstr);
+		return do_tar_op(base_directory);
+	}
+
+	if (query_host && *query_host) {
+		char *qhost = query_host;
+		char *slash;
+
+		while (*qhost == '\\' || *qhost == '/')
+			qhost++;
+
+		if ((slash = strchr_m(qhost, '/'))
+		    || (slash = strchr_m(qhost, '\\'))) {
+			*slash = 0;
+		}
+
+		if ((p=strchr_m(qhost, '#'))) {
+			*p = 0;
+			p++;
+			sscanf(p, "%x", &name_type);
+		}
+
+		return do_host_query(qhost);
+	}
+
+	if (message) {
+		return do_message_op(auth_info);
+	}
+
+	if (process(base_directory)) {
+		return 1;
+	}
+
+	TALLOC_FREE(frame);
+	return rc;
+}

=== added file '.pc/security-CVE-2011-0719.patch/source3/client/dnsbrowse.c'
--- .pc/security-CVE-2011-0719.patch/source3/client/dnsbrowse.c	1970-01-01 00:00:00 +0000
+++ .pc/security-CVE-2011-0719.patch/source3/client/dnsbrowse.c	2011-03-02 20:48:44 +0000
@@ -0,0 +1,237 @@
+/*
+   Unix SMB/CIFS implementation.
+   DNS-SD browse client
+   Copyright (C) Rishi Srivatsavai 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 3 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, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "client/client_proto.h"
+
+#ifdef WITH_DNSSD_SUPPORT
+
+#include <dns_sd.h>
+
+/* Holds service instances found during DNS browse */
+struct mdns_smbsrv_result
+{
+	char *serviceName;
+	char *regType;
+	char *domain;
+	uint32_t ifIndex;
+	struct mdns_smbsrv_result *nextResult;
+};
+
+/* Maintains state during DNS browse */
+struct mdns_browse_state
+{
+	struct mdns_smbsrv_result *listhead; /* Browse result list head */
+	int browseDone;
+
+};
+
+
+static void
+do_smb_resolve_reply (DNSServiceRef sdRef, DNSServiceFlags flags,
+		uint32_t interfaceIndex, DNSServiceErrorType errorCode,
+		const char *fullname, const char *hosttarget, uint16_t port,
+		uint16_t txtLen, const unsigned char *txtRecord, void *context)
+{
+	printf("SMB service available on %s port %u\n",
+		hosttarget, ntohs(port));
+}
+
+
+static void do_smb_resolve(struct mdns_smbsrv_result *browsesrv)
+{
+	DNSServiceRef mdns_conn_sdref = NULL;
+	int mdnsfd;
+	int fdsetsz;
+	int ret;
+	fd_set *fdset = NULL;
+	struct timeval tv;
+	DNSServiceErrorType err;
+
+	TALLOC_CTX * ctx = talloc_tos();
+
+	err = DNSServiceResolve(&mdns_conn_sdref, 0 /* flags */,
+		browsesrv->ifIndex,
+		browsesrv->serviceName, browsesrv->regType, browsesrv->domain,
+		do_smb_resolve_reply, NULL);
+
+	if (err != kDNSServiceErr_NoError) {
+		return;
+	}
+
+	mdnsfd = DNSServiceRefSockFD(mdns_conn_sdref);
+	for (;;)  {
+		if (fdset != NULL) {
+			TALLOC_FREE(fdset);
+		}
+
+		fdsetsz = howmany(mdnsfd + 1, NFDBITS) * sizeof(fd_mask);
+		fdset = TALLOC_ZERO(ctx, fdsetsz);
+		FD_SET(mdnsfd, fdset);
+
+		tv.tv_sec = 1;
+		tv.tv_usec = 0;
+
+		/* Wait until response received from mDNS daemon */
+		ret = sys_select(mdnsfd + 1, fdset, NULL, NULL, &tv);
+		if (ret <= 0 && errno != EINTR) {
+			break;
+		}
+
+		if (FD_ISSET(mdnsfd, fdset)) {
+			/* Invoke callback function */
+			DNSServiceProcessResult(mdns_conn_sdref);
+			break;
+		}
+	}
+
+	TALLOC_FREE(fdset);
+	DNSServiceRefDeallocate(mdns_conn_sdref);
+}
+
+
+static void
+do_smb_browse_reply(DNSServiceRef sdRef, DNSServiceFlags flags,
+        uint32_t interfaceIndex, DNSServiceErrorType errorCode,
+        const char  *serviceName, const char *regtype,
+        const char  *replyDomain, void  *context)
+{
+	struct mdns_browse_state *bstatep = (struct mdns_browse_state *)context;
+	struct mdns_smbsrv_result *bresult;
+
+	if (bstatep == NULL) {
+		return;
+	}
+
+	if (errorCode != kDNSServiceErr_NoError) {
+		bstatep->browseDone = 1;
+		return;
+	}
+
+	if (flags & kDNSServiceFlagsMoreComing) {
+		bstatep->browseDone = 0;
+	} else {
+		bstatep->browseDone = 1;
+	}
+
+	if (!(flags & kDNSServiceFlagsAdd)) {
+		return;
+	}
+
+	bresult = TALLOC_ARRAY(talloc_tos(), struct mdns_smbsrv_result, 1);
+	if (bresult == NULL) {
+		return;
+	}
+
+	if (bstatep->listhead != NULL) {
+		bresult->nextResult = bstatep->listhead;
+	}
+
+	bresult->serviceName = talloc_strdup(talloc_tos(), serviceName);
+	bresult->regType = talloc_strdup(talloc_tos(), regtype);
+	bresult->domain = talloc_strdup(talloc_tos(), replyDomain);
+	bresult->ifIndex = interfaceIndex;
+	bstatep->listhead = bresult;
+}
+
+int do_smb_browse(void)
+{
+	int mdnsfd;
+	int fdsetsz;
+	int ret;
+	fd_set *fdset = NULL;
+	struct mdns_browse_state bstate;
+	struct mdns_smbsrv_result *resptr;
+	struct timeval tv;
+	DNSServiceRef mdns_conn_sdref = NULL;
+	DNSServiceErrorType err;
+
+	TALLOC_CTX * ctx = talloc_stackframe();
+
+	ZERO_STRUCT(bstate);
+
+	err = DNSServiceBrowse(&mdns_conn_sdref, 0, 0, "_smb._tcp", "",
+			do_smb_browse_reply, &bstate);
+
+	if (err != kDNSServiceErr_NoError) {
+		d_printf("Error connecting to the Multicast DNS daemon\n");
+		TALLOC_FREE(ctx);
+		return 1;
+	}
+
+	mdnsfd = DNSServiceRefSockFD(mdns_conn_sdref);
+	for (;;)  {
+		if (fdset != NULL) {
+			TALLOC_FREE(fdset);
+		}
+
+		fdsetsz = howmany(mdnsfd + 1, NFDBITS) * sizeof(fd_mask);
+		fdset = TALLOC_ZERO(ctx, fdsetsz);
+		FD_SET(mdnsfd, fdset);
+
+		tv.tv_sec = 1;
+		tv.tv_usec = 0;
+
+		/* Wait until response received from mDNS daemon */
+		ret = sys_select(mdnsfd + 1, fdset, NULL, NULL, &tv);
+		if (ret <= 0 && errno != EINTR) {
+			break;
+		}
+
+		if (FD_ISSET(mdnsfd, fdset)) {
+			/* Invoke callback function */
+			if (DNSServiceProcessResult(mdns_conn_sdref)) {
+				break;
+			}
+			if (bstate.browseDone) {
+				break;
+			}
+		}
+	}
+
+	DNSServiceRefDeallocate(mdns_conn_sdref);
+
+	if (bstate.listhead != NULL) {
+		resptr = bstate.listhead;
+		while (resptr != NULL) {
+			struct mdns_smbsrv_result *oldresptr;
+			oldresptr = resptr;
+
+			/* Resolve smb service instance */
+			do_smb_resolve(resptr);
+
+			resptr = resptr->nextResult;
+		}
+	}
+
+	TALLOC_FREE(ctx);
+	return 0;
+}
+
+#else /* WITH_DNSSD_SUPPORT */
+
+int do_smb_browse(void)
+{
+    d_printf("DNS-SD browsing is not supported on this platform\n");
+    return 1;
+}
+
+#endif /* WITH_DNSSD_SUPPORT */
+
+

=== added directory '.pc/security-CVE-2011-0719.patch/source3/lib'
=== added file '.pc/security-CVE-2011-0719.patch/source3/lib/events.c'
--- .pc/security-CVE-2011-0719.patch/source3/lib/events.c	1970-01-01 00:00:00 +0000
+++ .pc/security-CVE-2011-0719.patch/source3/lib/events.c	2011-03-02 20:48:44 +0000
@@ -0,0 +1,330 @@
+/*
+   Unix SMB/CIFS implementation.
+   Timed event library.
+   Copyright (C) Andrew Tridgell 1992-1998
+   Copyright (C) Volker Lendecke 2005
+
+   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 3 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, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include <tevent_internal.h>
+
+void event_fd_set_writeable(struct tevent_fd *fde)
+{
+	TEVENT_FD_WRITEABLE(fde);
+}
+
+void event_fd_set_not_writeable(struct tevent_fd *fde)
+{
+	TEVENT_FD_NOT_WRITEABLE(fde);
+}
+
+void event_fd_set_readable(struct tevent_fd *fde)
+{
+	TEVENT_FD_READABLE(fde);
+}
+
+void event_fd_set_not_readable(struct tevent_fd *fde)
+{
+	TEVENT_FD_NOT_READABLE(fde);
+}
+
+/*
+ * Return if there's something in the queue
+ */
+
+bool event_add_to_select_args(struct tevent_context *ev,
+			      const struct timeval *now,
+			      fd_set *read_fds, fd_set *write_fds,
+			      struct timeval *timeout, int *maxfd)
+{
+	struct tevent_fd *fde;
+	struct timeval diff;
+	bool ret = false;
+
+	for (fde = ev->fd_events; fde; fde = fde->next) {
+		if (fde->flags & EVENT_FD_READ) {
+			FD_SET(fde->fd, read_fds);
+			ret = true;
+		}
+		if (fde->flags & EVENT_FD_WRITE) {
+			FD_SET(fde->fd, write_fds);
+			ret = true;
+		}
+
+		if ((fde->flags & (EVENT_FD_READ|EVENT_FD_WRITE))
+		    && (fde->fd > *maxfd)) {
+			*maxfd = fde->fd;
+		}
+	}
+
+	if (ev->immediate_events != NULL) {
+		*timeout = timeval_zero();
+		return true;
+	}
+
+	if (ev->timer_events == NULL) {
+		return ret;
+	}
+
+	diff = timeval_until(now, &ev->timer_events->next_event);
+	*timeout = timeval_min(timeout, &diff);
+
+	return true;
+}
+
+bool run_events(struct tevent_context *ev,
+		int selrtn, fd_set *read_fds, fd_set *write_fds)
+{
+	struct tevent_fd *fde;
+	struct timeval now;
+
+	if (ev->signal_events &&
+	    tevent_common_check_signal(ev)) {
+		return true;
+	}
+
+	if (ev->immediate_events &&
+	    tevent_common_loop_immediate(ev)) {
+		return true;
+	}
+
+	GetTimeOfDay(&now);
+
+	if ((ev->timer_events != NULL)
+	    && (timeval_compare(&now, &ev->timer_events->next_event) >= 0)) {
+		/* this older events system did not auto-free timed
+		   events on running them, and had a race condition
+		   where the event could be called twice if the
+		   talloc_free of the te happened after the callback
+		   made a call which invoked the event loop. To avoid
+		   this while still allowing old code which frees the
+		   te, we need to create a temporary context which
+		   will be used to ensure the te is freed. We also
+		   remove the te from the timed event list before we
+		   call the handler, to ensure we can't loop */
+
+		struct tevent_timer *te = ev->timer_events;
+		TALLOC_CTX *tmp_ctx = talloc_new(ev);
+
+		DEBUG(10, ("Running timed event \"%s\" %p\n",
+			   ev->timer_events->handler_name, ev->timer_events));
+
+		DLIST_REMOVE(ev->timer_events, te);
+		talloc_steal(tmp_ctx, te);
+
+		te->handler(ev, te, now, te->private_data);
+
+		talloc_free(tmp_ctx);
+		return true;
+	}
+
+	if (selrtn == 0) {
+		/*
+		 * No fd ready
+		 */
+		return false;
+	}
+
+	for (fde = ev->fd_events; fde; fde = fde->next) {
+		uint16 flags = 0;
+
+		if (FD_ISSET(fde->fd, read_fds)) flags |= EVENT_FD_READ;
+		if (FD_ISSET(fde->fd, write_fds)) flags |= EVENT_FD_WRITE;
+
+		if (flags & fde->flags) {
+			fde->handler(ev, fde, flags, fde->private_data);
+			return true;
+		}
+	}
+
+	return false;
+}
+
+
+struct timeval *get_timed_events_timeout(struct tevent_context *ev,
+					 struct timeval *to_ret)
+{
+	struct timeval now;
+
+	if ((ev->timer_events == NULL) && (ev->immediate_events == NULL)) {
+		return NULL;
+	}
+	if (ev->immediate_events != NULL) {
+		*to_ret = timeval_zero();
+		return to_ret;
+	}
+
+	now = timeval_current();
+	*to_ret = timeval_until(&now, &ev->timer_events->next_event);
+
+	DEBUG(10, ("timed_events_timeout: %d/%d\n", (int)to_ret->tv_sec,
+		(int)to_ret->tv_usec));
+
+	return to_ret;
+}
+
+static int s3_event_loop_once(struct tevent_context *ev, const char *location)
+{
+	struct timeval now, to;
+	fd_set r_fds, w_fds;
+	int maxfd = 0;
+	int ret;
+
+	FD_ZERO(&r_fds);
+	FD_ZERO(&w_fds);
+
+	to.tv_sec = 9999;	/* Max timeout */
+	to.tv_usec = 0;
+
+	if (run_events(ev, 0, NULL, NULL)) {
+		return 0;
+	}
+
+	GetTimeOfDay(&now);
+
+	if (!event_add_to_select_args(ev, &now, &r_fds, &w_fds, &to, &maxfd)) {
+		return -1;
+	}
+
+	ret = sys_select(maxfd+1, &r_fds, &w_fds, NULL, &to);
+
+	if (ret == -1 && errno != EINTR) {
+		tevent_debug(ev, TEVENT_DEBUG_FATAL,
+			     "sys_select() failed: %d:%s\n",
+			     errno, strerror(errno));
+		return -1;
+	}
+
+	run_events(ev, ret, &r_fds, &w_fds);
+	return 0;
+}
+
+void event_context_reinit(struct tevent_context *ev)
+{
+	tevent_common_context_destructor(ev);
+	return;
+}
+
+static int s3_event_context_init(struct tevent_context *ev)
+{
+	return 0;
+}
+
+void dump_event_list(struct tevent_context *ev)
+{
+	struct tevent_timer *te;
+	struct tevent_fd *fe;
+	struct timeval evt, now;
+
+	if (!ev) {
+		return;
+	}
+
+	now = timeval_current();
+
+	DEBUG(10,("dump_event_list:\n"));
+
+	for (te = ev->timer_events; te; te = te->next) {
+
+		evt = timeval_until(&now, &te->next_event);
+
+		DEBUGADD(10,("Timed Event \"%s\" %p handled in %d seconds (at %s)\n",
+			   te->handler_name,
+			   te,
+			   (int)evt.tv_sec,
+			   http_timestring(talloc_tos(), te->next_event.tv_sec)));
+	}
+
+	for (fe = ev->fd_events; fe; fe = fe->next) {
+
+		DEBUGADD(10,("FD Event %d %p, flags: 0x%04x\n",
+			   fe->fd,
+			   fe,
+			   fe->flags));
+	}
+}
+
+static const struct tevent_ops s3_event_ops = {
+	.context_init		= s3_event_context_init,
+	.add_fd			= tevent_common_add_fd,
+	.set_fd_close_fn	= tevent_common_fd_set_close_fn,
+	.get_fd_flags		= tevent_common_fd_get_flags,
+	.set_fd_flags		= tevent_common_fd_set_flags,
+	.add_timer		= tevent_common_add_timer,
+	.schedule_immediate	= tevent_common_schedule_immediate,
+	.add_signal		= tevent_common_add_signal,
+	.loop_once		= s3_event_loop_once,
+	.loop_wait		= tevent_common_loop_wait,
+};
+
+static bool s3_tevent_init(void)
+{
+	static bool initialized;
+	if (initialized) {
+		return true;
+	}
+	initialized = tevent_register_backend("s3", &s3_event_ops);
+	tevent_set_default_backend("s3");
+	return initialized;
+}
+
+/*
+  this is used to catch debug messages from events
+*/
+static void s3_event_debug(void *context, enum tevent_debug_level level,
+			   const char *fmt, va_list ap)  PRINTF_ATTRIBUTE(3,0);
+
+static void s3_event_debug(void *context, enum tevent_debug_level level,
+			   const char *fmt, va_list ap)
+{
+	int samba_level = -1;
+	char *s = NULL;
+	switch (level) {
+	case TEVENT_DEBUG_FATAL:
+		samba_level = 0;
+		break;
+	case TEVENT_DEBUG_ERROR:
+		samba_level = 1;
+		break;
+	case TEVENT_DEBUG_WARNING:
+		samba_level = 2;
+		break;
+	case TEVENT_DEBUG_TRACE:
+		samba_level = 11;
+		break;
+
+	};
+	if (vasprintf(&s, fmt, ap) == -1) {
+		return;
+	}
+	DEBUG(samba_level, ("s3_event: %s", s));
+	free(s);
+}
+
+struct tevent_context *s3_tevent_context_init(TALLOC_CTX *mem_ctx)
+{
+	struct tevent_context *ev;
+
+	s3_tevent_init();
+
+	ev = tevent_context_init_byname(mem_ctx, "s3");
+	if (ev) {
+		tevent_set_debug(ev, s3_event_debug, NULL);
+	}
+
+	return ev;
+}
+

=== added file '.pc/security-CVE-2011-0719.patch/source3/lib/g_lock.c'
--- .pc/security-CVE-2011-0719.patch/source3/lib/g_lock.c	1970-01-01 00:00:00 +0000
+++ .pc/security-CVE-2011-0719.patch/source3/lib/g_lock.c	2011-03-02 20:48:44 +0000
@@ -0,0 +1,766 @@
+/*
+   Unix SMB/CIFS implementation.
+   global locks based on dbwrap and messaging
+   Copyright (C) 2009 by Volker Lendecke
+
+   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 3 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, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "g_lock.h"
+
+static NTSTATUS g_lock_force_unlock(struct g_lock_ctx *ctx, const char *name,
+				    struct server_id pid);
+
+struct g_lock_ctx {
+	struct db_context *db;
+	struct messaging_context *msg;
+};
+
+/*
+ * The "g_lock.tdb" file contains records, indexed by the 0-terminated
+ * lockname. The record contains an array of "struct g_lock_rec"
+ * structures. Waiters have the lock_type with G_LOCK_PENDING or'ed.
+ */
+
+struct g_lock_rec {
+	enum g_lock_type lock_type;
+	struct server_id pid;
+};
+
+struct g_lock_ctx *g_lock_ctx_init(TALLOC_CTX *mem_ctx,
+				   struct messaging_context *msg)
+{
+	struct g_lock_ctx *result;
+
+	result = talloc(mem_ctx, struct g_lock_ctx);
+	if (result == NULL) {
+		return NULL;
+	}
+	result->msg = msg;
+
+	result->db = db_open(result, lock_path("g_lock.tdb"), 0,
+			     TDB_CLEAR_IF_FIRST, O_RDWR|O_CREAT, 0700);
+	if (result->db == NULL) {
+		DEBUG(1, ("g_lock_init: Could not open g_lock.tdb"));
+		TALLOC_FREE(result);
+		return NULL;
+	}
+	return result;
+}
+
+static bool g_lock_conflicts(enum g_lock_type lock_type,
+			     const struct g_lock_rec *rec)
+{
+	enum g_lock_type rec_lock = rec->lock_type;
+
+	if ((rec_lock & G_LOCK_PENDING) != 0) {
+		return false;
+	}
+
+	/*
+	 * Only tested write locks so far. Very likely this routine
+	 * needs to be fixed for read locks....
+	 */
+	if ((lock_type == G_LOCK_READ) && (rec_lock == G_LOCK_READ)) {
+		return false;
+	}
+	return true;
+}
+
+static bool g_lock_parse(TALLOC_CTX *mem_ctx, TDB_DATA data,
+			 int *pnum_locks, struct g_lock_rec **plocks)
+{
+	int i, num_locks;
+	struct g_lock_rec *locks;
+
+	if ((data.dsize % sizeof(struct g_lock_rec)) != 0) {
+		DEBUG(1, ("invalid lock record length %d\n", (int)data.dsize));
+		return false;
+	}
+
+	num_locks = data.dsize / sizeof(struct g_lock_rec);
+	locks = talloc_array(mem_ctx, struct g_lock_rec, num_locks);
+	if (locks == NULL) {
+		DEBUG(1, ("talloc failed\n"));
+		return false;
+	}
+
+	memcpy(locks, data.dptr, data.dsize);
+
+	DEBUG(10, ("locks:\n"));
+	for (i=0; i<num_locks; i++) {
+		DEBUGADD(10, ("%s: %s %s\n",
+			      procid_str(talloc_tos(), &locks[i].pid),
+			      ((locks[i].lock_type & 1) == G_LOCK_READ) ?
+			      "read" : "write",
+			      (locks[i].lock_type & G_LOCK_PENDING) ?
+			      "(pending)" : "(owner)"));
+
+		if (((locks[i].lock_type & G_LOCK_PENDING) == 0)
+		    && !process_exists(locks[i].pid)) {
+
+			DEBUGADD(10, ("lock owner %s died -- discarding\n",
+				      procid_str(talloc_tos(),
+						 &locks[i].pid)));
+
+			if (i < (num_locks-1)) {
+				locks[i] = locks[num_locks-1];
+			}
+			num_locks -= 1;
+		}
+	}
+
+	*plocks = locks;
+	*pnum_locks = num_locks;
+	return true;
+}
+
+static void g_lock_cleanup(int *pnum_locks, struct g_lock_rec *locks)
+{
+	int i, num_locks;
+
+	num_locks = *pnum_locks;
+
+	DEBUG(10, ("g_lock_cleanup: %d locks\n", num_locks));
+
+	for (i=0; i<num_locks; i++) {
+		if (process_exists(locks[i].pid)) {
+			continue;
+		}
+		DEBUGADD(10, ("%s does not exist -- discarding\n",
+			      procid_str(talloc_tos(), &locks[i].pid)));
+
+		if (i < (num_locks-1)) {
+			locks[i] = locks[num_locks-1];
+		}
+		num_locks -= 1;
+	}
+	*pnum_locks = num_locks;
+	return;
+}
+
+static struct g_lock_rec *g_lock_addrec(TALLOC_CTX *mem_ctx,
+					struct g_lock_rec *locks,
+					int *pnum_locks,
+					const struct server_id pid,
+					enum g_lock_type lock_type)
+{
+	struct g_lock_rec *result;
+	int num_locks = *pnum_locks;
+
+	result = talloc_realloc(mem_ctx, locks, struct g_lock_rec,
+				num_locks+1);
+	if (result == NULL) {
+		return NULL;
+	}
+
+	result[num_locks].pid = pid;
+	result[num_locks].lock_type = lock_type;
+	*pnum_locks += 1;
+	return result;
+}
+
+static void g_lock_got_retry(struct messaging_context *msg,
+			     void *private_data,
+			     uint32_t msg_type,
+			     struct server_id server_id,
+			     DATA_BLOB *data);
+
+static NTSTATUS g_lock_trylock(struct g_lock_ctx *ctx, const char *name,
+			       enum g_lock_type lock_type)
+{
+	struct db_record *rec = NULL;
+	struct g_lock_rec *locks = NULL;
+	int i, num_locks;
+	struct server_id self;
+	int our_index;
+	TDB_DATA data;
+	NTSTATUS status = NT_STATUS_OK;
+	NTSTATUS store_status;
+
+again:
+	rec = ctx->db->fetch_locked(ctx->db, talloc_tos(),
+				    string_term_tdb_data(name));
+	if (rec == NULL) {
+		DEBUG(10, ("fetch_locked(\"%s\") failed\n", name));
+		status = NT_STATUS_LOCK_NOT_GRANTED;
+		goto done;
+	}
+
+	if (!g_lock_parse(talloc_tos(), rec->value, &num_locks, &locks)) {
+		DEBUG(10, ("g_lock_parse for %s failed\n", name));
+		status = NT_STATUS_INTERNAL_ERROR;
+		goto done;
+	}
+
+	self = procid_self();
+	our_index = -1;
+
+	for (i=0; i<num_locks; i++) {
+		if (procid_equal(&self, &locks[i].pid)) {
+			if (our_index != -1) {
+				DEBUG(1, ("g_lock_trylock: Added ourself "
+					  "twice!\n"));
+				status = NT_STATUS_INTERNAL_ERROR;
+				goto done;
+			}
+			if ((locks[i].lock_type & G_LOCK_PENDING) == 0) {
+				DEBUG(1, ("g_lock_trylock: Found ourself not "
+					  "pending!\n"));
+				status = NT_STATUS_INTERNAL_ERROR;
+				goto done;
+			}
+
+			our_index = i;
+
+			/* never conflict with ourself */
+			continue;
+		}
+		if (g_lock_conflicts(lock_type, &locks[i])) {
+			struct server_id pid = locks[i].pid;
+
+			if (!process_exists(pid)) {
+				TALLOC_FREE(locks);
+				TALLOC_FREE(rec);
+				status = g_lock_force_unlock(ctx, name, pid);
+				if (!NT_STATUS_IS_OK(status)) {
+					DEBUG(1, ("Could not unlock dead lock "
+						  "holder!\n"));
+					goto done;
+				}
+				goto again;
+			}
+			lock_type |= G_LOCK_PENDING;
+		}
+	}
+
+	if (our_index == -1) {
+		/* First round, add ourself */
+
+		locks = g_lock_addrec(talloc_tos(), locks, &num_locks,
+				      self, lock_type);
+		if (locks == NULL) {
+			DEBUG(10, ("g_lock_addrec failed\n"));
+			status = NT_STATUS_NO_MEMORY;
+			goto done;
+		}
+	} else {
+		/*
+		 * Retry. We were pending last time. Overwrite the
+		 * stored lock_type with what we calculated, we might
+		 * have acquired the lock this time.
+		 */
+		locks[our_index].lock_type = lock_type;
+	}
+
+	if (NT_STATUS_IS_OK(status) && ((lock_type & G_LOCK_PENDING) == 0)) {
+		/*
+		 * Walk through the list of locks, search for dead entries
+		 */
+		g_lock_cleanup(&num_locks, locks);
+	}
+
+	data = make_tdb_data((uint8_t *)locks, num_locks * sizeof(*locks));
+	store_status = rec->store(rec, data, 0);
+	if (!NT_STATUS_IS_OK(store_status)) {
+		DEBUG(1, ("rec->store failed: %s\n",
+			  nt_errstr(store_status)));
+		status = store_status;
+	}
+
+done:
+	TALLOC_FREE(locks);
+	TALLOC_FREE(rec);
+
+	if (NT_STATUS_IS_OK(status) && (lock_type & G_LOCK_PENDING) != 0) {
+		return STATUS_PENDING;
+	}
+
+	return NT_STATUS_OK;
+}
+
+NTSTATUS g_lock_lock(struct g_lock_ctx *ctx, const char *name,
+		     enum g_lock_type lock_type, struct timeval timeout)
+{
+	struct tevent_timer *te = NULL;
+	NTSTATUS status;
+	bool retry = false;
+	struct timeval timeout_end;
+	struct timeval time_now;
+
+	DEBUG(10, ("Trying to acquire lock %d for %s\n", (int)lock_type,
+		   name));
+
+	if (lock_type & ~1) {
+		DEBUG(1, ("Got invalid lock type %d for %s\n",
+			  (int)lock_type, name));
+		return NT_STATUS_INVALID_PARAMETER;
+	}
+
+#ifdef CLUSTER_SUPPORT
+	if (lp_clustering()) {
+		status = ctdb_watch_us(messaging_ctdbd_connection());
+		if (!NT_STATUS_IS_OK(status)) {
+			DEBUG(10, ("could not register retry with ctdb: %s\n",
+				   nt_errstr(status)));
+			goto done;
+		}
+	}
+#endif
+
+	status = messaging_register(ctx->msg, &retry, MSG_DBWRAP_G_LOCK_RETRY,
+				    g_lock_got_retry);
+	if (!NT_STATUS_IS_OK(status)) {
+		DEBUG(10, ("messaging_register failed: %s\n",
+			   nt_errstr(status)));
+		return status;
+	}
+
+	time_now = timeval_current();
+	timeout_end = timeval_sum(&time_now, &timeout);
+
+	while (true) {
+#ifdef CLUSTER_SUPPORT
+		fd_set _r_fds;
+#endif
+		fd_set *r_fds = NULL;
+		int max_fd = 0;
+		int ret;
+		struct timeval timeout_remaining, select_timeout;
+
+		status = g_lock_trylock(ctx, name, lock_type);
+		if (NT_STATUS_IS_OK(status)) {
+			DEBUG(10, ("Got lock %s\n", name));
+			break;
+		}
+		if (!NT_STATUS_EQUAL(status, STATUS_PENDING)) {
+			DEBUG(10, ("g_lock_trylock failed: %s\n",
+				   nt_errstr(status)));
+			break;
+		}
+
+		DEBUG(10, ("g_lock_trylock: Did not get lock, waiting...\n"));
+
+		/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+		 *             !!! HACK ALERT --- FIX ME !!!
+		 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+		 * What we really want to do here is to react to
+		 * MSG_DBWRAP_G_LOCK_RETRY messages that are either sent
+		 * by a client doing g_lock_unlock or by ourselves when
+		 * we receive a CTDB_SRVID_SAMBA_NOTIFY or
+		 * CTDB_SRVID_RECONFIGURE message from ctdbd, i.e. when
+		 * either a client holding a lock or a complete node
+		 * has died.
+		 *
+		 * Doing this properly involves calling tevent_loop_once(),
+		 * but doing this here with the main ctdbd messaging context
+		 * creates a nested event loop when g_lock_lock() is called
+		 * from the main event loop, e.g. in a tcon_and_X where the
+		 * share_info.tdb needs to be initialized and is locked by
+		 * another process, or when the remore registry is accessed
+		 * for writing and some other process already holds a lock
+		 * on the registry.tdb.
+		 *
+		 * So as a quick fix, we act a little coarsely here: we do
+		 * a select on the ctdb connection fd and when it is readable
+		 * or we get EINTR, then we retry without actually parsing
+		 * any ctdb packages or dispatching messages. This means that
+		 * we retry more often than intended by design, but this does
+		 * not harm and it is unobtrusive. When we have finished,
+		 * the main loop will pick up all the messages and ctdb
+		 * packets. The only extra twist is that we cannot use timed
+		 * events here but have to handcode a timeout.
+		 */
+
+#ifdef CLUSTER_SUPPORT
+		if (lp_clustering()) {
+			struct ctdbd_connection *conn = messaging_ctdbd_connection();
+
+			r_fds = &_r_fds;
+			FD_ZERO(r_fds);
+			max_fd = ctdbd_conn_get_fd(conn);
+			FD_SET(max_fd, r_fds);
+		}
+#endif
+
+		time_now = timeval_current();
+		timeout_remaining = timeval_until(&time_now, &timeout_end);
+		select_timeout = timeval_set(60, 0);
+
+		select_timeout = timeval_min(&select_timeout,
+					     &timeout_remaining);
+
+		ret = sys_select(max_fd + 1, r_fds, NULL, NULL,
+				 &select_timeout);
+		if (ret == -1) {
+			if (errno != EINTR) {
+				DEBUG(1, ("error calling select: %s\n",
+					  strerror(errno)));
+				status = NT_STATUS_INTERNAL_ERROR;
+				break;
+			}
+			/*
+			 * errno == EINTR:
+			 * This means a signal was received.
+			 * It might have been a MSG_DBWRAP_G_LOCK_RETRY message.
+			 * ==> retry
+			 */
+		} else if (ret == 0) {
+			if (timeval_expired(&timeout_end)) {
+				DEBUG(10, ("g_lock_lock timed out\n"));
+				status = NT_STATUS_LOCK_NOT_GRANTED;
+				break;
+			} else {
+				DEBUG(10, ("select returned 0 but timeout not "
+					   "not expired, retrying\n"));
+			}
+		} else if (ret != 1) {
+			DEBUG(1, ("invalid return code of select: %d\n", ret));
+			status = NT_STATUS_INTERNAL_ERROR;
+			break;
+		}
+		/*
+		 * ret == 1:
+		 * This means ctdbd has sent us some data.
+		 * Might be a CTDB_SRVID_RECONFIGURE or a
+		 * CTDB_SRVID_SAMBA_NOTIFY message.
+		 * ==> retry
+		 */
+	}
+
+#ifdef CLUSTER_SUPPORT
+done:
+#endif
+
+	if (!NT_STATUS_IS_OK(status)) {
+		NTSTATUS unlock_status;
+
+		unlock_status = g_lock_unlock(ctx, name);
+
+		if (!NT_STATUS_IS_OK(unlock_status)) {
+			DEBUG(1, ("Could not remove ourself from the locking "
+				  "db: %s\n", nt_errstr(status)));
+		}
+	}
+
+	messaging_deregister(ctx->msg, MSG_DBWRAP_G_LOCK_RETRY, &retry);
+	TALLOC_FREE(te);
+
+	return status;
+}
+
+static void g_lock_got_retry(struct messaging_context *msg,
+			     void *private_data,
+			     uint32_t msg_type,
+			     struct server_id server_id,
+			     DATA_BLOB *data)
+{
+	bool *pretry = (bool *)private_data;
+
+	DEBUG(10, ("Got retry message from pid %s\n",
+		   procid_str(talloc_tos(), &server_id)));
+
+	*pretry = true;
+}
+
+static NTSTATUS g_lock_force_unlock(struct g_lock_ctx *ctx, const char *name,
+				    struct server_id pid)
+{
+	struct db_record *rec = NULL;
+	struct g_lock_rec *locks = NULL;
+	int i, num_locks;
+	enum g_lock_type lock_type;
+	NTSTATUS status;
+
+	rec = ctx->db->fetch_locked(ctx->db, talloc_tos(),
+				    string_term_tdb_data(name));
+	if (rec == NULL) {
+		DEBUG(10, ("fetch_locked(\"%s\") failed\n", name));
+		status = NT_STATUS_INTERNAL_ERROR;
+		goto done;
+	}
+
+	if (!g_lock_parse(talloc_tos(), rec->value, &num_locks, &locks)) {
+		DEBUG(10, ("g_lock_parse for %s failed\n", name));
+		status = NT_STATUS_INTERNAL_ERROR;
+		goto done;
+	}
+
+	for (i=0; i<num_locks; i++) {
+		if (procid_equal(&pid, &locks[i].pid)) {
+			break;
+		}
+	}
+
+	if (i == num_locks) {
+		DEBUG(10, ("g_lock_force_unlock: Lock not found\n"));
+		status = NT_STATUS_INTERNAL_ERROR;
+		goto done;
+	}
+
+	lock_type = locks[i].lock_type;
+
+	if (i < (num_locks-1)) {
+		locks[i] = locks[num_locks-1];
+	}
+	num_locks -= 1;
+
+	if (num_locks == 0) {
+		status = rec->delete_rec(rec);
+	} else {
+		TDB_DATA data;
+		data = make_tdb_data((uint8_t *)locks,
+				     sizeof(struct g_lock_rec) * num_locks);
+		status = rec->store(rec, data, 0);
+	}
+
+	if (!NT_STATUS_IS_OK(status)) {
+		DEBUG(1, ("g_lock_force_unlock: Could not store record: %s\n",
+			  nt_errstr(status)));
+		goto done;
+	}
+
+	TALLOC_FREE(rec);
+
+	if ((lock_type & G_LOCK_PENDING) == 0) {
+		int num_wakeups = 0;
+
+		/*
+		 * We've been the lock holder. Others to retry. Don't
+		 * tell all others to avoid a thundering herd. In case
+		 * this leads to a complete stall because we miss some
+		 * processes, the loop in g_lock_lock tries at least
+		 * once a minute.
+		 */
+
+		for (i=0; i<num_locks; i++) {
+			if ((locks[i].lock_type & G_LOCK_PENDING) == 0) {
+				continue;
+			}
+			if (!process_exists(locks[i].pid)) {
+				continue;
+			}
+
+			/*
+			 * Ping all waiters to retry
+			 */
+			status = messaging_send(ctx->msg, locks[i].pid,
+						MSG_DBWRAP_G_LOCK_RETRY,
+						&data_blob_null);
+			if (!NT_STATUS_IS_OK(status)) {
+				DEBUG(1, ("sending retry to %s failed: %s\n",
+					  procid_str(talloc_tos(),
+						     &locks[i].pid),
+					  nt_errstr(status)));
+			} else {
+				num_wakeups += 1;
+			}
+			if (num_wakeups > 5) {
+				break;
+			}
+		}
+	}
+done:
+	/*
+	 * For the error path, TALLOC_FREE(rec) as well. In the good
+	 * path we have already freed it.
+	 */
+	TALLOC_FREE(rec);
+
+	TALLOC_FREE(locks);
+	return status;
+}
+
+NTSTATUS g_lock_unlock(struct g_lock_ctx *ctx, const char *name)
+{
+	NTSTATUS status;
+
+	status = g_lock_force_unlock(ctx, name, procid_self());
+
+#ifdef CLUSTER_SUPPORT
+	if (lp_clustering()) {
+		ctdb_unwatch(messaging_ctdbd_connection());
+	}
+#endif
+	return status;
+}
+
+struct g_lock_locks_state {
+	int (*fn)(const char *name, void *private_data);
+	void *private_data;
+};
+
+static int g_lock_locks_fn(struct db_record *rec, void *priv)
+{
+	struct g_lock_locks_state *state = (struct g_lock_locks_state *)priv;
+
+	if ((rec->key.dsize == 0) || (rec->key.dptr[rec->key.dsize-1] != 0)) {
+		DEBUG(1, ("invalid key in g_lock.tdb, ignoring\n"));
+		return 0;
+	}
+	return state->fn((char *)rec->key.dptr, state->private_data);
+}
+
+int g_lock_locks(struct g_lock_ctx *ctx,
+		 int (*fn)(const char *name, void *private_data),
+		 void *private_data)
+{
+	struct g_lock_locks_state state;
+
+	state.fn = fn;
+	state.private_data = private_data;
+
+	return ctx->db->traverse_read(ctx->db, g_lock_locks_fn, &state);
+}
+
+NTSTATUS g_lock_dump(struct g_lock_ctx *ctx, const char *name,
+		     int (*fn)(struct server_id pid,
+			       enum g_lock_type lock_type,
+			       void *private_data),
+		     void *private_data)
+{
+	TDB_DATA data;
+	int i, num_locks;
+	struct g_lock_rec *locks = NULL;
+	bool ret;
+
+	if (ctx->db->fetch(ctx->db, talloc_tos(), string_term_tdb_data(name),
+			   &data) != 0) {
+		return NT_STATUS_NOT_FOUND;
+	}
+
+	if ((data.dsize == 0) || (data.dptr == NULL)) {
+		return NT_STATUS_OK;
+	}
+
+	ret = g_lock_parse(talloc_tos(), data, &num_locks, &locks);
+
+	TALLOC_FREE(data.dptr);
+
+	if (!ret) {
+		DEBUG(10, ("g_lock_parse for %s failed\n", name));
+		return NT_STATUS_INTERNAL_ERROR;
+	}
+
+	for (i=0; i<num_locks; i++) {
+		if (fn(locks[i].pid, locks[i].lock_type, private_data) != 0) {
+			break;
+		}
+	}
+	TALLOC_FREE(locks);
+	return NT_STATUS_OK;
+}
+
+struct g_lock_get_state {
+	bool found;
+	struct server_id *pid;
+};
+
+static int g_lock_get_fn(struct server_id pid, enum g_lock_type lock_type,
+			 void *priv)
+{
+	struct g_lock_get_state *state = (struct g_lock_get_state *)priv;
+
+	if ((lock_type & G_LOCK_PENDING) != 0) {
+		return 0;
+	}
+
+	state->found = true;
+	*state->pid = pid;
+	return 1;
+}
+
+NTSTATUS g_lock_get(struct g_lock_ctx *ctx, const char *name,
+		    struct server_id *pid)
+{
+	struct g_lock_get_state state;
+	NTSTATUS status;
+
+	state.found = false;
+	state.pid = pid;
+
+	status = g_lock_dump(ctx, name, g_lock_get_fn, &state);
+	if (!NT_STATUS_IS_OK(status)) {
+		return status;
+	}
+	if (!state.found) {
+		return NT_STATUS_NOT_FOUND;
+	}
+	return NT_STATUS_OK;
+}
+
+static bool g_lock_init_all(TALLOC_CTX *mem_ctx,
+			    struct tevent_context **pev,
+			    struct messaging_context **pmsg,
+			    struct g_lock_ctx **pg_ctx)
+{
+	struct tevent_context *ev = NULL;
+	struct messaging_context *msg = NULL;
+	struct g_lock_ctx *g_ctx = NULL;
+
+	ev = tevent_context_init(mem_ctx);
+	if (ev == NULL) {
+		d_fprintf(stderr, "ERROR: could not init event context\n");
+		goto fail;
+	}
+	msg = messaging_init(mem_ctx, procid_self(), ev);
+	if (msg == NULL) {
+		d_fprintf(stderr, "ERROR: could not init messaging context\n");
+		goto fail;
+	}
+	g_ctx = g_lock_ctx_init(mem_ctx, msg);
+	if (g_ctx == NULL) {
+		d_fprintf(stderr, "ERROR: could not init g_lock context\n");
+		goto fail;
+	}
+
+	*pev = ev;
+	*pmsg = msg;
+	*pg_ctx = g_ctx;
+	return true;
+fail:
+	TALLOC_FREE(g_ctx);
+	TALLOC_FREE(msg);
+	TALLOC_FREE(ev);
+	return false;
+}
+
+NTSTATUS g_lock_do(const char *name, enum g_lock_type lock_type,
+		   struct timeval timeout,
+		   void (*fn)(void *private_data), void *private_data)
+{
+	struct tevent_context *ev = NULL;
+	struct messaging_context *msg = NULL;
+	struct g_lock_ctx *g_ctx = NULL;
+	NTSTATUS status;
+
+	if (!g_lock_init_all(talloc_tos(), &ev, &msg, &g_ctx)) {
+		status = NT_STATUS_ACCESS_DENIED;
+		goto done;
+	}
+
+	status = g_lock_lock(g_ctx, name, lock_type, timeout);
+	if (!NT_STATUS_IS_OK(status)) {
+		goto done;
+	}
+	fn(private_data);
+	g_lock_unlock(g_ctx, name);
+
+done:
+	TALLOC_FREE(g_ctx);
+	TALLOC_FREE(msg);
+	TALLOC_FREE(ev);
+	return status;
+}

=== added file '.pc/security-CVE-2011-0719.patch/source3/lib/packet.c'
--- .pc/security-CVE-2011-0719.patch/source3/lib/packet.c	1970-01-01 00:00:00 +0000
+++ .pc/security-CVE-2011-0719.patch/source3/lib/packet.c	2011-03-02 20:48:44 +0000
@@ -0,0 +1,273 @@
+/* 
+   Unix SMB/CIFS implementation.
+   Packet handling
+   Copyright (C) Volker Lendecke 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 3 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, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+struct packet_context {
+	int fd;
+	DATA_BLOB in, out;
+};
+
+/*
+ * Close the underlying fd
+ */
+static int packet_context_destructor(struct packet_context *ctx)
+{
+	return close(ctx->fd);
+}
+
+/*
+ * Initialize a packet context. The fd is given to the packet context, meaning
+ * that it is automatically closed when the packet context is freed.
+ */
+struct packet_context *packet_init(TALLOC_CTX *mem_ctx, int fd)
+{
+	struct packet_context *result;
+
+	if (!(result = TALLOC_ZERO_P(mem_ctx, struct packet_context))) {
+		return NULL;
+	}
+
+	result->fd = fd;
+	talloc_set_destructor(result, packet_context_destructor);
+	return result;
+}
+
+/*
+ * Pull data from the fd
+ */
+NTSTATUS packet_fd_read(struct packet_context *ctx)
+{
+	int res, available;
+	size_t new_size;
+	uint8 *in;
+
+	res = ioctl(ctx->fd, FIONREAD, &available);
+
+	if (res == -1) {
+		DEBUG(10, ("ioctl(FIONREAD) failed: %s\n", strerror(errno)));
+		return map_nt_error_from_unix(errno);
+	}
+
+	SMB_ASSERT(available >= 0);
+
+	if (available == 0) {
+		return NT_STATUS_END_OF_FILE;
+	}
+
+	new_size = ctx->in.length + available;
+
+	if (new_size < ctx->in.length) {
+		DEBUG(0, ("integer wrap\n"));
+		return NT_STATUS_NO_MEMORY;
+	}
+
+	if (!(in = TALLOC_REALLOC_ARRAY(ctx, ctx->in.data, uint8, new_size))) {
+		DEBUG(10, ("talloc failed\n"));
+		return NT_STATUS_NO_MEMORY;
+	}
+
+	ctx->in.data = in;
+
+	res = recv(ctx->fd, in + ctx->in.length, available, 0);
+
+	if (res < 0) {
+		DEBUG(10, ("recv failed: %s\n", strerror(errno)));
+		return map_nt_error_from_unix(errno);
+	}
+
+	if (res == 0) {
+		return NT_STATUS_END_OF_FILE;
+	}
+
+	ctx->in.length += res;
+
+	return NT_STATUS_OK;
+}
+
+NTSTATUS packet_fd_read_sync(struct packet_context *ctx,
+			     struct timeval *timeout)
+{
+	int res;
+	fd_set r_fds;
+
+	FD_ZERO(&r_fds);
+	FD_SET(ctx->fd, &r_fds);
+
+	res = sys_select(ctx->fd+1, &r_fds, NULL, NULL, timeout);
+
+	if (res == 0) {
+		DEBUG(10, ("select timed out\n"));
+		return NT_STATUS_IO_TIMEOUT;
+	}
+
+	if (res == -1) {
+		DEBUG(10, ("select returned %s\n", strerror(errno)));
+		return map_nt_error_from_unix(errno);
+	}
+
+	return packet_fd_read(ctx);
+}
+
+bool packet_handler(struct packet_context *ctx,
+		    bool (*full_req)(const uint8_t *buf,
+				     size_t available,
+				     size_t *length,
+				     void *priv),
+		    NTSTATUS (*callback)(uint8_t *buf, size_t length,
+					 void *priv),
+		    void *priv, NTSTATUS *status)
+{
+	size_t length;
+	uint8_t *buf;
+
+	if (!full_req(ctx->in.data, ctx->in.length, &length, priv)) {
+		return False;
+	}
+
+	if (length > ctx->in.length) {
+		*status = NT_STATUS_INTERNAL_ERROR;
+		return true;
+	}
+
+	if (length == ctx->in.length) {
+		buf = ctx->in.data;
+		ctx->in.data = NULL;
+		ctx->in.length = 0;
+	} else {
+		buf = (uint8_t *)TALLOC_MEMDUP(ctx, ctx->in.data, length);
+		if (buf == NULL) {
+			*status = NT_STATUS_NO_MEMORY;
+			return true;
+		}
+
+		memmove(ctx->in.data, ctx->in.data + length,
+			ctx->in.length - length);
+		ctx->in.length -= length;
+	}
+
+	*status = callback(buf, length, priv);
+	return True;
+}
+
+/*
+ * How many bytes of outgoing data do we have pending?
+ */
+size_t packet_outgoing_bytes(struct packet_context *ctx)
+{
+	return ctx->out.length;
+}
+
+/*
+ * Push data to the fd
+ */
+NTSTATUS packet_fd_write(struct packet_context *ctx)
+{
+	ssize_t sent;
+
+	sent = send(ctx->fd, ctx->out.data, ctx->out.length, 0);
+
+	if (sent == -1) {
+		DEBUG(0, ("send failed: %s\n", strerror(errno)));
+		return map_nt_error_from_unix(errno);
+	}
+
+	memmove(ctx->out.data, ctx->out.data + sent,
+		ctx->out.length - sent);
+	ctx->out.length -= sent;
+
+	return NT_STATUS_OK;
+}
+
+/*
+ * Sync flush all outgoing bytes
+ */
+NTSTATUS packet_flush(struct packet_context *ctx)
+{
+	while (ctx->out.length != 0) {
+		NTSTATUS status = packet_fd_write(ctx);
+		if (!NT_STATUS_IS_OK(status)) {
+			return status;
+		}
+	}
+	return NT_STATUS_OK;
+}
+
+/*
+ * Send a list of DATA_BLOBs
+ *
+ * Example:  packet_send(ctx, 2, data_blob_const(&size, sizeof(size)),
+ *			 data_blob_const(buf, size));
+ */
+NTSTATUS packet_send(struct packet_context *ctx, int num_blobs, ...)
+{
+	va_list ap;
+	int i;
+	size_t len;
+	uint8 *out;
+
+	len = ctx->out.length;
+
+	va_start(ap, num_blobs);
+	for (i=0; i<num_blobs; i++) {
+		size_t tmp;
+		DATA_BLOB blob = va_arg(ap, DATA_BLOB);
+
+		tmp = len + blob.length;
+		if (tmp < len) {
+			DEBUG(0, ("integer overflow\n"));
+			va_end(ap);
+			return NT_STATUS_NO_MEMORY;
+		}
+		len = tmp;
+	}
+	va_end(ap);
+
+	if (len == 0) {
+		return NT_STATUS_OK;
+	}
+
+	if (!(out = TALLOC_REALLOC_ARRAY(ctx, ctx->out.data, uint8, len))) {
+		DEBUG(0, ("talloc failed\n"));
+		return NT_STATUS_NO_MEMORY;
+	}
+
+	ctx->out.data = out;
+
+	va_start(ap, num_blobs);
+	for (i=0; i<num_blobs; i++) {
+		DATA_BLOB blob = va_arg(ap, DATA_BLOB);
+
+		memcpy(ctx->out.data+ctx->out.length, blob.data, blob.length);
+		ctx->out.length += blob.length;
+	}
+	va_end(ap);
+
+	SMB_ASSERT(ctx->out.length == len);
+	return NT_STATUS_OK;
+}
+
+/*
+ * Get the packet context's file descriptor
+ */
+int packet_get_fd(struct packet_context *ctx)
+{
+	return ctx->fd;
+}
+

=== added file '.pc/security-CVE-2011-0719.patch/source3/lib/readline.c'
--- .pc/security-CVE-2011-0719.patch/source3/lib/readline.c	1970-01-01 00:00:00 +0000
+++ .pc/security-CVE-2011-0719.patch/source3/lib/readline.c	2011-03-02 20:48:44 +0000
@@ -0,0 +1,201 @@
+/* 
+   Unix SMB/CIFS implementation.
+   Samba readline wrapper implementation
+   Copyright (C) Simo Sorce 2001
+   Copyright (C) Andrew Tridgell 2001
+   
+   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 3 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, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+#ifdef HAVE_LIBREADLINE
+#  ifdef HAVE_READLINE_READLINE_H
+#    include <readline/readline.h>
+#    ifdef HAVE_READLINE_HISTORY_H
+#      include <readline/history.h>
+#    endif
+#  else
+#    ifdef HAVE_READLINE_H
+#      include <readline.h>
+#      ifdef HAVE_HISTORY_H
+#        include <history.h>
+#      endif
+#    else
+#      undef HAVE_LIBREADLINE
+#    endif
+#  endif
+#endif
+
+#ifdef HAVE_NEW_LIBREADLINE
+#  define RL_COMPLETION_CAST (rl_completion_func_t *)
+#else
+/* This type is missing from libreadline<4.0  (approximately) */
+#  define RL_COMPLETION_CAST
+#endif /* HAVE_NEW_LIBREADLINE */
+
+static bool smb_rl_done;
+
+#if HAVE_LIBREADLINE
+/*
+ * MacOS/X does not have rl_done in readline.h, but
+ * readline.so has it
+ */
+extern int rl_done;
+#endif
+
+void smb_readline_done(void)
+{
+	smb_rl_done = true;
+#if HAVE_LIBREADLINE
+	rl_done = 1;
+#endif
+}
+
+/****************************************************************************
+ Display the prompt and wait for input. Call callback() regularly
+****************************************************************************/
+
+static char *smb_readline_replacement(const char *prompt, void (*callback)(void), 
+				char **(completion_fn)(const char *text, int start, int end))
+{
+	fd_set fds;
+	char *line = NULL;
+	struct timeval timeout;
+	int fd = x_fileno(x_stdin);
+	char *ret;
+
+	/* Prompt might be NULL in non-interactive mode. */
+	if (prompt) {
+		x_fprintf(x_stdout, "%s", prompt);
+		x_fflush(x_stdout);
+	}
+
+	line = (char *)SMB_MALLOC(BUFSIZ);
+	if (!line) {
+		return NULL;
+	}
+
+	while (!smb_rl_done) {
+		timeout.tv_sec = 5;
+		timeout.tv_usec = 0;
+
+		FD_ZERO(&fds);
+		FD_SET(fd,&fds);
+
+		if (sys_select_intr(fd+1,&fds,NULL,NULL,&timeout) == 1) {
+			ret = x_fgets(line, BUFSIZ, x_stdin);
+			if (ret == 0) {
+				SAFE_FREE(line);
+			}
+			return ret;
+		}
+		if (callback) {
+			callback();
+		}
+	}
+	SAFE_FREE(line);
+	return NULL;
+}
+
+/****************************************************************************
+ Display the prompt and wait for input. Call callback() regularly.
+****************************************************************************/
+
+char *smb_readline(const char *prompt, void (*callback)(void),
+		   char **(completion_fn)(const char *text, int start, int end))
+{
+	char *ret;
+	bool interactive;
+
+	interactive = isatty(x_fileno(x_stdin)) || getenv("CLI_FORCE_INTERACTIVE");
+	if (!interactive) {
+		return smb_readline_replacement(NULL, callback, completion_fn);
+	}
+
+#if HAVE_LIBREADLINE
+
+	/* Aargh!  Readline does bizzare things with the terminal width
+	that mucks up expect(1).  Set CLI_NO_READLINE in the environment
+	to force readline not to be used. */
+
+	if (getenv("CLI_NO_READLINE"))
+		return smb_readline_replacement(prompt, callback, completion_fn);
+
+	if (completion_fn) {
+		/* The callback prototype has changed slightly between
+		different versions of Readline, so the same function
+		works in all of them to date, but we get compiler
+		warnings in some.  */
+		rl_attempted_completion_function = RL_COMPLETION_CAST completion_fn;
+	}
+
+#if HAVE_DECL_RL_EVENT_HOOK
+	if (callback)
+		rl_event_hook = (Function *)callback;
+#endif
+	ret = readline(prompt);
+	if (ret && *ret)
+		add_history(ret);
+
+#else
+	ret = smb_readline_replacement(prompt, callback, completion_fn);
+#endif
+
+	return ret;
+}
+
+/****************************************************************************
+ * return line buffer text
+ ****************************************************************************/
+const char *smb_readline_get_line_buffer(void)
+{
+#if defined(HAVE_LIBREADLINE)
+	return rl_line_buffer;
+#else
+	return NULL;
+#endif
+}
+
+
+/****************************************************************************
+ * set completion append character
+ ***************************************************************************/
+void smb_readline_ca_char(char c)
+{
+#if defined(HAVE_LIBREADLINE)
+	rl_completion_append_character = c;
+#endif
+}
+
+/****************************************************************************
+history
+****************************************************************************/
+int cmd_history(void)
+{
+#if defined(HAVE_LIBREADLINE) && defined(HAVE_HISTORY_LIST)
+	HIST_ENTRY **hlist;
+	int i;
+
+	hlist = history_list();
+
+	for (i = 0; hlist && hlist[i]; i++) {
+		DEBUG(0, ("%d: %s\n", i, hlist[i]->line));
+	}
+#else
+	DEBUG(0,("no history without readline support\n"));
+#endif
+
+	return 0;
+}

=== added file '.pc/security-CVE-2011-0719.patch/source3/lib/select.c'
--- .pc/security-CVE-2011-0719.patch/source3/lib/select.c	1970-01-01 00:00:00 +0000
+++ .pc/security-CVE-2011-0719.patch/source3/lib/select.c	2011-03-02 20:48:44 +0000
@@ -0,0 +1,206 @@
+/* 
+   Unix SMB/Netbios implementation.
+   Version 3.0
+   Samba select/poll implementation
+   Copyright (C) Andrew Tridgell 1992-1998
+   
+   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 3 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, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+/* This is here because it allows us to avoid a nasty race in signal handling. 
+   We need to guarantee that when we get a signal we get out of a select immediately
+   but doing that involves a race condition. We can avoid the race by getting the 
+   signal handler to write to a pipe that is in the select/poll list 
+
+   This means all Samba signal handlers should call sys_select_signal().
+*/
+
+static pid_t initialised;
+static int select_pipe[2];
+static volatile unsigned pipe_written, pipe_read;
+
+/*******************************************************************
+ Call this from all Samba signal handlers if you want to avoid a 
+ nasty signal race condition.
+********************************************************************/
+
+void sys_select_signal(char c)
+{
+	int saved_errno = errno;
+
+	if (!initialised) return;
+
+	if (pipe_written > pipe_read+256) return;
+
+	if (write(select_pipe[1], &c, 1) == 1) pipe_written++;
+
+	errno = saved_errno;
+}
+
+/*******************************************************************
+ Like select() but avoids the signal race using a pipe
+ it also guuarantees that fds on return only ever contains bits set
+ for file descriptors that were readable.
+********************************************************************/
+
+int sys_select(int maxfd, fd_set *readfds, fd_set *writefds, fd_set *errorfds, struct timeval *tval)
+{
+	int ret, saved_errno;
+	fd_set *readfds2, readfds_buf;
+
+	if (initialised != sys_getpid()) {
+		if (pipe(select_pipe) == -1)
+		{
+			DEBUG(0, ("sys_select: pipe failed (%s)\n",
+				strerror(errno)));
+			if (readfds != NULL)
+				FD_ZERO(readfds);
+			if (writefds != NULL)
+				FD_ZERO(writefds);
+			if (errorfds != NULL)
+				FD_ZERO(errorfds);
+			return -1;
+		}
+
+		/*
+		 * These next two lines seem to fix a bug with the Linux
+		 * 2.0.x kernel (and probably other UNIXes as well) where
+		 * the one byte read below can block even though the
+		 * select returned that there is data in the pipe and
+		 * the pipe_written variable was incremented. Thanks to
+		 * HP for finding this one. JRA.
+		 */
+
+		if(set_blocking(select_pipe[0],0)==-1)
+			smb_panic("select_pipe[0]: O_NONBLOCK failed");
+		if(set_blocking(select_pipe[1],0)==-1)
+			smb_panic("select_pipe[1]: O_NONBLOCK failed");
+
+		initialised = sys_getpid();
+	}
+
+	maxfd = MAX(select_pipe[0]+1, maxfd);
+
+	/* If readfds is NULL we need to provide our own set. */
+	if (readfds) {
+		readfds2 = readfds;
+	} else {
+		readfds2 = &readfds_buf;
+		FD_ZERO(readfds2);
+	}
+	FD_SET(select_pipe[0], readfds2);
+
+	errno = 0;
+	ret = select(maxfd,readfds2,writefds,errorfds,tval);
+
+	if (ret <= 0) {
+		FD_ZERO(readfds2);
+		if (writefds)
+			FD_ZERO(writefds);
+		if (errorfds)
+			FD_ZERO(errorfds);
+	} else if (FD_ISSET(select_pipe[0], readfds2)) {
+		char c;
+		saved_errno = errno;
+		if (read(select_pipe[0], &c, 1) == 1) {
+			pipe_read++;
+			/* Mark Weaver <mark-clist@npsl.co.uk> pointed out a critical
+			   fix to ensure we don't lose signals. We must always
+			   return -1 when the select pipe is set, otherwise if another
+			   fd is also ready (so ret == 2) then we used to eat the
+			   byte in the pipe and lose the signal. JRA.
+			*/
+			ret = -1;
+#if 0
+			/* JRA - we can use this to debug the signal messaging... */
+			DEBUG(0,("select got %u signal\n", (unsigned int)c));
+#endif
+			errno = EINTR;
+		} else {
+			FD_CLR(select_pipe[0], readfds2);
+			ret--;
+			errno = saved_errno;
+		}
+	}
+
+	return ret;
+}
+
+/*******************************************************************
+ Similar to sys_select() but catch EINTR and continue.
+ This is what sys_select() used to do in Samba.
+********************************************************************/
+
+int sys_select_intr(int maxfd, fd_set *readfds, fd_set *writefds, fd_set *errorfds, struct timeval *tval)
+{
+	int ret;
+	fd_set *readfds2, readfds_buf, *writefds2, writefds_buf, *errorfds2, errorfds_buf;
+	struct timeval tval2, *ptval, end_time;
+
+	readfds2 = (readfds ? &readfds_buf : NULL);
+	writefds2 = (writefds ? &writefds_buf : NULL);
+	errorfds2 = (errorfds ? &errorfds_buf : NULL);
+	if (tval) {
+		GetTimeOfDay(&end_time);
+		end_time.tv_sec += tval->tv_sec;
+		end_time.tv_usec += tval->tv_usec;
+		end_time.tv_sec += end_time.tv_usec / 1000000;
+		end_time.tv_usec %= 1000000;
+		errno = 0;
+		tval2 = *tval;
+		ptval = &tval2;
+	} else {
+		ptval = NULL;
+	}
+
+	do {
+		if (readfds)
+			readfds_buf = *readfds;
+		if (writefds)
+			writefds_buf = *writefds;
+		if (errorfds)
+			errorfds_buf = *errorfds;
+		if (ptval && (errno == EINTR)) {
+			struct timeval now_time;
+			int64_t tdif;
+
+			GetTimeOfDay(&now_time);
+			tdif = usec_time_diff(&end_time, &now_time);
+			if (tdif <= 0) {
+				ret = 0; /* time expired. */
+				break;
+			}
+			ptval->tv_sec = tdif / 1000000;
+			ptval->tv_usec = tdif % 1000000;
+		}
+
+		/* We must use select and not sys_select here. If we use
+		   sys_select we'd lose the fact a signal occurred when sys_select
+		   read a byte from the pipe. Fix from Mark Weaver
+		   <mark-clist@npsl.co.uk>
+		*/
+		ret = select(maxfd, readfds2, writefds2, errorfds2, ptval);
+	} while (ret == -1 && errno == EINTR);
+
+	if (readfds)
+		*readfds = readfds_buf;
+	if (writefds)
+		*writefds = writefds_buf;
+	if (errorfds)
+		*errorfds = errorfds_buf;
+
+	return ret;
+}

=== added file '.pc/security-CVE-2011-0719.patch/source3/lib/util_sock.c'
--- .pc/security-CVE-2011-0719.patch/source3/lib/util_sock.c	1970-01-01 00:00:00 +0000
+++ .pc/security-CVE-2011-0719.patch/source3/lib/util_sock.c	2011-03-02 20:48:44 +0000
@@ -0,0 +1,2012 @@
+/*
+   Unix SMB/CIFS implementation.
+   Samba utility functions
+   Copyright (C) Andrew Tridgell 1992-1998
+   Copyright (C) Tim Potter      2000-2001
+   Copyright (C) Jeremy Allison  1992-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 3 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, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+/****************************************************************************
+ Get a port number in host byte order from a sockaddr_storage.
+****************************************************************************/
+
+uint16_t get_sockaddr_port(const struct sockaddr_storage *pss)
+{
+	uint16_t port = 0;
+
+	if (pss->ss_family != AF_INET) {
+#if defined(HAVE_IPV6)
+		/* IPv6 */
+		const struct sockaddr_in6 *sa6 =
+			(const struct sockaddr_in6 *)pss;
+		port = ntohs(sa6->sin6_port);
+#endif
+	} else {
+		const struct sockaddr_in *sa =
+			(const struct sockaddr_in *)pss;
+		port = ntohs(sa->sin_port);
+	}
+	return port;
+}
+
+/****************************************************************************
+ Print out an IPv4 or IPv6 address from a struct sockaddr_storage.
+****************************************************************************/
+
+static char *print_sockaddr_len(char *dest,
+			size_t destlen,
+			const struct sockaddr *psa,
+			socklen_t psalen)
+{
+	if (destlen > 0) {
+		dest[0] = '\0';
+	}
+	(void)sys_getnameinfo(psa,
+			psalen,
+			dest, destlen,
+			NULL, 0,
+			NI_NUMERICHOST);
+	return dest;
+}
+
+/****************************************************************************
+ Print out an IPv4 or IPv6 address from a struct sockaddr_storage.
+****************************************************************************/
+
+char *print_sockaddr(char *dest,
+			size_t destlen,
+			const struct sockaddr_storage *psa)
+{
+	return print_sockaddr_len(dest, destlen, (struct sockaddr *)psa,
+			sizeof(struct sockaddr_storage));
+}
+
+/****************************************************************************
+ Print out a canonical IPv4 or IPv6 address from a struct sockaddr_storage.
+****************************************************************************/
+
+char *print_canonical_sockaddr(TALLOC_CTX *ctx,
+			const struct sockaddr_storage *pss)
+{
+	char addr[INET6_ADDRSTRLEN];
+	char *dest = NULL;
+	int ret;
+
+	/* Linux getnameinfo() man pages says port is unitialized if
+	   service name is NULL. */
+
+	ret = sys_getnameinfo((const struct sockaddr *)pss,
+			sizeof(struct sockaddr_storage),
+			addr, sizeof(addr),
+			NULL, 0,
+			NI_NUMERICHOST);
+	if (ret != 0) {
+		return NULL;
+	}
+
+	if (pss->ss_family != AF_INET) {
+#if defined(HAVE_IPV6)
+		dest = talloc_asprintf(ctx, "[%s]", addr);
+#else
+		return NULL;
+#endif
+	} else {
+		dest = talloc_asprintf(ctx, "%s", addr);
+	}
+	
+	return dest;
+}
+
+/****************************************************************************
+ Return the string of an IP address (IPv4 or IPv6).
+****************************************************************************/
+
+static const char *get_socket_addr(int fd, char *addr_buf, size_t addr_len)
+{
+	struct sockaddr_storage sa;
+	socklen_t length = sizeof(sa);
+
+	/* Ok, returning a hard coded IPv4 address
+ 	 * is bogus, but it's just as bogus as a
+ 	 * zero IPv6 address. No good choice here.
+ 	 */
+
+	strlcpy(addr_buf, "0.0.0.0", addr_len);
+
+	if (fd == -1) {
+		return addr_buf;
+	}
+
+	if (getsockname(fd, (struct sockaddr *)&sa, &length) < 0) {
+		DEBUG(0,("getsockname failed. Error was %s\n",
+			strerror(errno) ));
+		return addr_buf;
+	}
+
+	return print_sockaddr_len(addr_buf, addr_len, (struct sockaddr *)&sa, length);
+}
+
+/****************************************************************************
+ Return the port number we've bound to on a socket.
+****************************************************************************/
+
+int get_socket_port(int fd)
+{
+	struct sockaddr_storage sa;
+	socklen_t length = sizeof(sa);
+
+	if (fd == -1) {
+		return -1;
+	}
+
+	if (getsockname(fd, (struct sockaddr *)&sa, &length) < 0) {
+		DEBUG(0,("getpeername failed. Error was %s\n",
+			strerror(errno) ));
+		return -1;
+	}
+
+#if defined(HAVE_IPV6)
+	if (sa.ss_family == AF_INET6) {
+		return ntohs(((struct sockaddr_in6 *)&sa)->sin6_port);
+	}
+#endif
+	if (sa.ss_family == AF_INET) {
+		return ntohs(((struct sockaddr_in *)&sa)->sin_port);
+	}
+	return -1;
+}
+
+const char *client_name(int fd)
+{
+	return get_peer_name(fd,false);
+}
+
+const char *client_addr(int fd, char *addr, size_t addrlen)
+{
+	return get_peer_addr(fd,addr,addrlen);
+}
+
+const char *client_socket_addr(int fd, char *addr, size_t addr_len)
+{
+	return get_socket_addr(fd, addr, addr_len);
+}
+
+#if 0
+/* Not currently used. JRA. */
+int client_socket_port(int fd)
+{
+	return get_socket_port(fd);
+}
+#endif
+
+/****************************************************************************
+ Accessor functions to make thread-safe code easier later...
+****************************************************************************/
+
+void set_smb_read_error(enum smb_read_errors *pre,
+			enum smb_read_errors newerr)
+{
+	if (pre) {
+		*pre = newerr;
+	}
+}
+
+void cond_set_smb_read_error(enum smb_read_errors *pre,
+			enum smb_read_errors newerr)
+{
+	if (pre && *pre == SMB_READ_OK) {
+		*pre = newerr;
+	}
+}
+
+/****************************************************************************
+ Determine if a file descriptor is in fact a socket.
+****************************************************************************/
+
+bool is_a_socket(int fd)
+{
+	int v;
+	socklen_t l;
+	l = sizeof(int);
+	return(getsockopt(fd, SOL_SOCKET, SO_TYPE, (char *)&v, &l) == 0);
+}
+
+enum SOCK_OPT_TYPES {OPT_BOOL,OPT_INT,OPT_ON};
+
+typedef struct smb_socket_option {
+	const char *name;
+	int level;
+	int option;
+	int value;
+	int opttype;
+} smb_socket_option;
+
+static const smb_socket_option socket_options[] = {
+  {"SO_KEEPALIVE", SOL_SOCKET, SO_KEEPALIVE, 0, OPT_BOOL},
+  {"SO_REUSEADDR", SOL_SOCKET, SO_REUSEADDR, 0, OPT_BOOL},
+  {"SO_BROADCAST", SOL_SOCKET, SO_BROADCAST, 0, OPT_BOOL},
+#ifdef TCP_NODELAY
+  {"TCP_NODELAY", IPPROTO_TCP, TCP_NODELAY, 0, OPT_BOOL},
+#endif
+#ifdef TCP_KEEPCNT
+  {"TCP_KEEPCNT", IPPROTO_TCP, TCP_KEEPCNT, 0, OPT_INT},
+#endif
+#ifdef TCP_KEEPIDLE
+  {"TCP_KEEPIDLE", IPPROTO_TCP, TCP_KEEPIDLE, 0, OPT_INT},
+#endif
+#ifdef TCP_KEEPINTVL
+  {"TCP_KEEPINTVL", IPPROTO_TCP, TCP_KEEPINTVL, 0, OPT_INT},
+#endif
+#ifdef IPTOS_LOWDELAY
+  {"IPTOS_LOWDELAY", IPPROTO_IP, IP_TOS, IPTOS_LOWDELAY, OPT_ON},
+#endif
+#ifdef IPTOS_THROUGHPUT
+  {"IPTOS_THROUGHPUT", IPPROTO_IP, IP_TOS, IPTOS_THROUGHPUT, OPT_ON},
+#endif
+#ifdef SO_REUSEPORT
+  {"SO_REUSEPORT", SOL_SOCKET, SO_REUSEPORT, 0, OPT_BOOL},
+#endif
+#ifdef SO_SNDBUF
+  {"SO_SNDBUF", SOL_SOCKET, SO_SNDBUF, 0, OPT_INT},
+#endif
+#ifdef SO_RCVBUF
+  {"SO_RCVBUF", SOL_SOCKET, SO_RCVBUF, 0, OPT_INT},
+#endif
+#ifdef SO_SNDLOWAT
+  {"SO_SNDLOWAT", SOL_SOCKET, SO_SNDLOWAT, 0, OPT_INT},
+#endif
+#ifdef SO_RCVLOWAT
+  {"SO_RCVLOWAT", SOL_SOCKET, SO_RCVLOWAT, 0, OPT_INT},
+#endif
+#ifdef SO_SNDTIMEO
+  {"SO_SNDTIMEO", SOL_SOCKET, SO_SNDTIMEO, 0, OPT_INT},
+#endif
+#ifdef SO_RCVTIMEO
+  {"SO_RCVTIMEO", SOL_SOCKET, SO_RCVTIMEO, 0, OPT_INT},
+#endif
+#ifdef TCP_FASTACK
+  {"TCP_FASTACK", IPPROTO_TCP, TCP_FASTACK, 0, OPT_INT},
+#endif
+#ifdef TCP_QUICKACK
+  {"TCP_QUICKACK", IPPROTO_TCP, TCP_QUICKACK, 0, OPT_BOOL},
+#endif
+  {NULL,0,0,0,0}};
+
+/****************************************************************************
+ Print socket options.
+****************************************************************************/
+
+static void print_socket_options(int s)
+{
+	int value;
+	socklen_t vlen = 4;
+	const smb_socket_option *p = &socket_options[0];
+
+	/* wrapped in if statement to prevent streams
+	 * leak in SCO Openserver 5.0 */
+	/* reported on samba-technical  --jerry */
+	if ( DEBUGLEVEL >= 5 ) {
+		DEBUG(5,("Socket options:\n"));
+		for (; p->name != NULL; p++) {
+			if (getsockopt(s, p->level, p->option,
+						(void *)&value, &vlen) == -1) {
+				DEBUGADD(5,("\tCould not test socket option %s.\n",
+							p->name));
+			} else {
+				DEBUGADD(5,("\t%s = %d\n",
+							p->name,value));
+			}
+		}
+	}
+ }
+
+/****************************************************************************
+ Set user socket options.
+****************************************************************************/
+
+void set_socket_options(int fd, const char *options)
+{
+	TALLOC_CTX *ctx = talloc_stackframe();
+	char *tok;
+
+	while (next_token_talloc(ctx, &options, &tok," \t,")) {
+		int ret=0,i;
+		int value = 1;
+		char *p;
+		bool got_value = false;
+
+		if ((p = strchr_m(tok,'='))) {
+			*p = 0;
+			value = atoi(p+1);
+			got_value = true;
+		}
+
+		for (i=0;socket_options[i].name;i++)
+			if (strequal(socket_options[i].name,tok))
+				break;
+
+		if (!socket_options[i].name) {
+			DEBUG(0,("Unknown socket option %s\n",tok));
+			continue;
+		}
+
+		switch (socket_options[i].opttype) {
+		case OPT_BOOL:
+		case OPT_INT:
+			ret = setsockopt(fd,socket_options[i].level,
+					socket_options[i].option,
+					(char *)&value,sizeof(int));
+			break;
+
+		case OPT_ON:
+			if (got_value)
+				DEBUG(0,("syntax error - %s "
+					"does not take a value\n",tok));
+
+			{
+				int on = socket_options[i].value;
+				ret = setsockopt(fd,socket_options[i].level,
+					socket_options[i].option,
+					(char *)&on,sizeof(int));
+			}
+			break;
+		}
+
+		if (ret != 0) {
+			/* be aware that some systems like Solaris return
+			 * EINVAL to a setsockopt() call when the client
+			 * sent a RST previously - no need to worry */
+			DEBUG(2,("Failed to set socket option %s (Error %s)\n",
+				tok, strerror(errno) ));
+		}
+	}
+
+	TALLOC_FREE(ctx);
+	print_socket_options(fd);
+}
+
+/****************************************************************************
+ Read from a socket.
+****************************************************************************/
+
+ssize_t read_udp_v4_socket(int fd,
+			char *buf,
+			size_t len,
+			struct sockaddr_storage *psa)
+{
+	ssize_t ret;
+	socklen_t socklen = sizeof(*psa);
+	struct sockaddr_in *si = (struct sockaddr_in *)psa;
+
+	memset((char *)psa,'\0',socklen);
+
+	ret = (ssize_t)sys_recvfrom(fd,buf,len,0,
+			(struct sockaddr *)psa,&socklen);
+	if (ret <= 0) {
+		/* Don't print a low debug error for a non-blocking socket. */
+		if (errno == EAGAIN) {
+			DEBUG(10,("read_udp_v4_socket: returned EAGAIN\n"));
+		} else {
+			DEBUG(2,("read_udp_v4_socket: failed. errno=%s\n",
+				strerror(errno)));
+		}
+		return 0;
+	}
+
+	if (psa->ss_family != AF_INET) {
+		DEBUG(2,("read_udp_v4_socket: invalid address family %d "
+			"(not IPv4)\n", (int)psa->ss_family));
+		return 0;
+	}
+
+	DEBUG(10,("read_udp_v4_socket: ip %s port %d read: %lu\n",
+			inet_ntoa(si->sin_addr),
+			si->sin_port,
+			(unsigned long)ret));
+
+	return ret;
+}
+
+/****************************************************************************
+ Read data from a file descriptor with a timout in msec.
+ mincount = if timeout, minimum to read before returning
+ maxcount = number to be read.
+ time_out = timeout in milliseconds
+ NB. This can be called with a non-socket fd, don't change
+ sys_read() to sys_recv() or other socket call.
+****************************************************************************/
+
+NTSTATUS read_fd_with_timeout(int fd, char *buf,
+				  size_t mincnt, size_t maxcnt,
+				  unsigned int time_out,
+				  size_t *size_ret)
+{
+	fd_set fds;
+	int selrtn;
+	ssize_t readret;
+	size_t nread = 0;
+	struct timeval timeout;
+	char addr[INET6_ADDRSTRLEN];
+	int save_errno;
+
+	/* just checking .... */
+	if (maxcnt <= 0)
+		return NT_STATUS_OK;
+
+	/* Blocking read */
+	if (time_out == 0) {
+		if (mincnt == 0) {
+			mincnt = maxcnt;
+		}
+
+		while (nread < mincnt) {
+			readret = sys_read(fd, buf + nread, maxcnt - nread);
+
+			if (readret == 0) {
+				DEBUG(5,("read_fd_with_timeout: "
+					"blocking read. EOF from client.\n"));
+				return NT_STATUS_END_OF_FILE;
+			}
+
+			if (readret == -1) {
+				save_errno = errno;
+				if (fd == get_client_fd()) {
+					/* Try and give an error message
+					 * saying what client failed. */
+					DEBUG(0,("read_fd_with_timeout: "
+						"client %s read error = %s.\n",
+						get_peer_addr(fd,addr,sizeof(addr)),
+						strerror(save_errno) ));
+				} else {
+					DEBUG(0,("read_fd_with_timeout: "
+						"read error = %s.\n",
+						strerror(save_errno) ));
+				}
+				return map_nt_error_from_unix(save_errno);
+			}
+			nread += readret;
+		}
+		goto done;
+	}
+
+	/* Most difficult - timeout read */
+	/* If this is ever called on a disk file and
+	   mincnt is greater then the filesize then
+	   system performance will suffer severely as
+	   select always returns true on disk files */
+
+	/* Set initial timeout */
+	timeout.tv_sec = (time_t)(time_out / 1000);
+	timeout.tv_usec = (long)(1000 * (time_out % 1000));
+
+	for (nread=0; nread < mincnt; ) {
+		FD_ZERO(&fds);
+		FD_SET(fd,&fds);
+
+		selrtn = sys_select_intr(fd+1,&fds,NULL,NULL,&timeout);
+
+		/* Check if error */
+		if (selrtn == -1) {
+			save_errno = errno;
+			/* something is wrong. Maybe the socket is dead? */
+			if (fd == get_client_fd()) {
+				/* Try and give an error message saying
+				 * what client failed. */
+				DEBUG(0,("read_fd_with_timeout: timeout "
+				"read for client %s. select error = %s.\n",
+				get_peer_addr(fd,addr,sizeof(addr)),
+				strerror(save_errno) ));
+			} else {
+				DEBUG(0,("read_fd_with_timeout: timeout "
+				"read. select error = %s.\n",
+				strerror(save_errno) ));
+			}
+			return map_nt_error_from_unix(save_errno);
+		}
+
+		/* Did we timeout ? */
+		if (selrtn == 0) {
+			DEBUG(10,("read_fd_with_timeout: timeout read. "
+				"select timed out.\n"));
+			return NT_STATUS_IO_TIMEOUT;
+		}
+
+		readret = sys_read(fd, buf+nread, maxcnt-nread);
+
+		if (readret == 0) {
+			/* we got EOF on the file descriptor */
+			DEBUG(5,("read_fd_with_timeout: timeout read. "
+				"EOF from client.\n"));
+			return NT_STATUS_END_OF_FILE;
+		}
+
+		if (readret == -1) {
+			save_errno = errno;
+			/* the descriptor is probably dead */
+			if (fd == get_client_fd()) {
+				/* Try and give an error message
+				 * saying what client failed. */
+				DEBUG(0,("read_fd_with_timeout: timeout "
+					"read to client %s. read error = %s.\n",
+					get_peer_addr(fd,addr,sizeof(addr)),
+					strerror(save_errno) ));
+			} else {
+				DEBUG(0,("read_fd_with_timeout: timeout "
+					"read. read error = %s.\n",
+					strerror(save_errno) ));
+			}
+			return map_nt_error_from_unix(errno);
+		}
+
+		nread += readret;
+	}
+
+ done:
+	/* Return the number we got */
+	if (size_ret) {
+		*size_ret = nread;
+	}
+	return NT_STATUS_OK;
+}
+
+/****************************************************************************
+ Read data from an fd, reading exactly N bytes.
+ NB. This can be called with a non-socket fd, don't add dependencies
+ on socket calls.
+****************************************************************************/
+
+NTSTATUS read_data(int fd, char *buffer, size_t N)
+{
+	return read_fd_with_timeout(fd, buffer, N, N, 0, NULL);
+}
+
+/****************************************************************************
+ Write all data from an iov array
+ NB. This can be called with a non-socket fd, don't add dependencies
+ on socket calls.
+****************************************************************************/
+
+ssize_t write_data_iov(int fd, const struct iovec *orig_iov, int iovcnt)
+{
+	int i;
+	size_t to_send;
+	ssize_t thistime;
+	size_t sent;
+	struct iovec *iov_copy, *iov;
+
+	to_send = 0;
+	for (i=0; i<iovcnt; i++) {
+		to_send += orig_iov[i].iov_len;
+	}
+
+	thistime = sys_writev(fd, orig_iov, iovcnt);
+	if ((thistime <= 0) || (thistime == to_send)) {
+		return thistime;
+	}
+	sent = thistime;
+
+	/*
+	 * We could not send everything in one call. Make a copy of iov that
+	 * we can mess with. We keep a copy of the array start in iov_copy for
+	 * the TALLOC_FREE, because we're going to modify iov later on,
+	 * discarding elements.
+	 */
+
+	iov_copy = (struct iovec *)TALLOC_MEMDUP(
+		talloc_tos(), orig_iov, sizeof(struct iovec) * iovcnt);
+
+	if (iov_copy == NULL) {
+		errno = ENOMEM;
+		return -1;
+	}
+	iov = iov_copy;
+
+	while (sent < to_send) {
+		/*
+		 * We have to discard "thistime" bytes from the beginning
+		 * iov array, "thistime" contains the number of bytes sent
+		 * via writev last.
+		 */
+		while (thistime > 0) {
+			if (thistime < iov[0].iov_len) {
+				char *new_base =
+					(char *)iov[0].iov_base + thistime;
+				iov[0].iov_base = (void *)new_base;
+				iov[0].iov_len -= thistime;
+				break;
+			}
+			thistime -= iov[0].iov_len;
+			iov += 1;
+			iovcnt -= 1;
+		}
+
+		thistime = sys_writev(fd, iov, iovcnt);
+		if (thistime <= 0) {
+			break;
+		}
+		sent += thistime;
+	}
+
+	TALLOC_FREE(iov_copy);
+	return sent;
+}
+
+/****************************************************************************
+ Write data to a fd.
+ NB. This can be called with a non-socket fd, don't add dependencies
+ on socket calls.
+****************************************************************************/
+
+ssize_t write_data(int fd, const char *buffer, size_t N)
+{
+	ssize_t ret;
+	struct iovec iov;
+
+	iov.iov_base = CONST_DISCARD(void *, buffer);
+	iov.iov_len = N;
+
+	ret = write_data_iov(fd, &iov, 1);
+	if (ret >= 0) {
+		return ret;
+	}
+
+	if (fd == get_client_fd()) {
+		char addr[INET6_ADDRSTRLEN];
+		/*
+		 * Try and give an error message saying what client failed.
+		 */
+		DEBUG(0, ("write_data: write failure in writing to client %s. "
+			  "Error %s\n", get_peer_addr(fd,addr,sizeof(addr)),
+			  strerror(errno)));
+	} else {
+		DEBUG(0,("write_data: write failure. Error = %s\n",
+			 strerror(errno) ));
+	}
+
+	return -1;
+}
+
+/****************************************************************************
+ Send a keepalive packet (rfc1002).
+****************************************************************************/
+
+bool send_keepalive(int client)
+{
+	unsigned char buf[4];
+
+	buf[0] = SMBkeepalive;
+	buf[1] = buf[2] = buf[3] = 0;
+
+	return(write_data(client,(char *)buf,4) == 4);
+}
+
+/****************************************************************************
+ Read 4 bytes of a smb packet and return the smb length of the packet.
+ Store the result in the buffer.
+ This version of the function will return a length of zero on receiving
+ a keepalive packet.
+ Timeout is in milliseconds.
+****************************************************************************/
+
+NTSTATUS read_smb_length_return_keepalive(int fd, char *inbuf,
+					  unsigned int timeout,
+					  size_t *len)
+{
+	int msg_type;
+	NTSTATUS status;
+
+	status = read_fd_with_timeout(fd, inbuf, 4, 4, timeout, NULL);
+
+	if (!NT_STATUS_IS_OK(status)) {
+		return status;
+	}
+
+	*len = smb_len(inbuf);
+	msg_type = CVAL(inbuf,0);
+
+	if (msg_type == SMBkeepalive) {
+		DEBUG(5,("Got keepalive packet\n"));
+	}
+
+	DEBUG(10,("got smb length of %lu\n",(unsigned long)(*len)));
+
+	return NT_STATUS_OK;
+}
+
+/****************************************************************************
+ Read 4 bytes of a smb packet and return the smb length of the packet.
+ Store the result in the buffer. This version of the function will
+ never return a session keepalive (length of zero).
+ Timeout is in milliseconds.
+****************************************************************************/
+
+NTSTATUS read_smb_length(int fd, char *inbuf, unsigned int timeout,
+			 size_t *len)
+{
+	uint8_t msgtype = SMBkeepalive;
+
+	while (msgtype == SMBkeepalive) {
+		NTSTATUS status;
+
+		status = read_smb_length_return_keepalive(fd, inbuf, timeout,
+							  len);
+		if (!NT_STATUS_IS_OK(status)) {
+			return status;
+		}
+
+		msgtype = CVAL(inbuf, 0);
+	}
+
+	DEBUG(10,("read_smb_length: got smb length of %lu\n",
+		  (unsigned long)len));
+
+	return NT_STATUS_OK;
+}
+
+/****************************************************************************
+ Read an smb from a fd.
+ The timeout is in milliseconds.
+ This function will return on receipt of a session keepalive packet.
+ maxlen is the max number of bytes to return, not including the 4 byte
+ length. If zero it means buflen limit.
+ Doesn't check the MAC on signed packets.
+****************************************************************************/
+
+NTSTATUS receive_smb_raw(int fd, char *buffer, size_t buflen, unsigned int timeout,
+			 size_t maxlen, size_t *p_len)
+{
+	size_t len;
+	NTSTATUS status;
+
+	status = read_smb_length_return_keepalive(fd,buffer,timeout,&len);
+
+	if (!NT_STATUS_IS_OK(status)) {
+		DEBUG(10, ("receive_smb_raw: %s!\n", nt_errstr(status)));
+		return status;
+	}
+
+	if (len > buflen) {
+		DEBUG(0,("Invalid packet length! (%lu bytes).\n",
+					(unsigned long)len));
+		return NT_STATUS_INVALID_PARAMETER;
+	}
+
+	if(len > 0) {
+		if (maxlen) {
+			len = MIN(len,maxlen);
+		}
+
+		status = read_fd_with_timeout(
+			fd, buffer+4, len, len, timeout, &len);
+
+		if (!NT_STATUS_IS_OK(status)) {
+			return status;
+		}
+
+		/* not all of samba3 properly checks for packet-termination
+		 * of strings. This ensures that we don't run off into
+		 * empty space. */
+		SSVAL(buffer+4,len, 0);
+	}
+
+	*p_len = len;
+	return NT_STATUS_OK;
+}
+
+/****************************************************************************
+ Open a socket of the specified type, port, and address for incoming data.
+****************************************************************************/
+
+int open_socket_in(int type,
+		uint16_t port,
+		int dlevel,
+		const struct sockaddr_storage *psock,
+		bool rebind)
+{
+	struct sockaddr_storage sock;
+	int res;
+	socklen_t slen = sizeof(struct sockaddr_in);
+
+	sock = *psock;
+
+#if defined(HAVE_IPV6)
+	if (sock.ss_family == AF_INET6) {
+		((struct sockaddr_in6 *)&sock)->sin6_port = htons(port);
+		slen = sizeof(struct sockaddr_in6);
+	}
+#endif
+	if (sock.ss_family == AF_INET) {
+		((struct sockaddr_in *)&sock)->sin_port = htons(port);
+	}
+
+	res = socket(sock.ss_family, type, 0 );
+	if( res == -1 ) {
+		if( DEBUGLVL(0) ) {
+			dbgtext( "open_socket_in(): socket() call failed: " );
+			dbgtext( "%s\n", strerror( errno ) );
+		}
+		return -1;
+	}
+
+	/* This block sets/clears the SO_REUSEADDR and possibly SO_REUSEPORT. */
+	{
+		int val = rebind ? 1 : 0;
+		if( setsockopt(res,SOL_SOCKET,SO_REUSEADDR,
+					(char *)&val,sizeof(val)) == -1 ) {
+			if( DEBUGLVL( dlevel ) ) {
+				dbgtext( "open_socket_in(): setsockopt: " );
+				dbgtext( "SO_REUSEADDR = %s ",
+						val?"true":"false" );
+				dbgtext( "on port %d failed ", port );
+				dbgtext( "with error = %s\n", strerror(errno) );
+			}
+		}
+#ifdef SO_REUSEPORT
+		if( setsockopt(res,SOL_SOCKET,SO_REUSEPORT,
+					(char *)&val,sizeof(val)) == -1 ) {
+			if( DEBUGLVL( dlevel ) ) {
+				dbgtext( "open_socket_in(): setsockopt: ");
+				dbgtext( "SO_REUSEPORT = %s ",
+						val?"true":"false");
+				dbgtext( "on port %d failed ", port);
+				dbgtext( "with error = %s\n", strerror(errno));
+			}
+		}
+#endif /* SO_REUSEPORT */
+	}
+
+	/* now we've got a socket - we need to bind it */
+	if (bind(res, (struct sockaddr *)&sock, slen) == -1 ) {
+		if( DEBUGLVL(dlevel) && (port == SMB_PORT1 ||
+				port == SMB_PORT2 || port == NMB_PORT) ) {
+			char addr[INET6_ADDRSTRLEN];
+			print_sockaddr(addr, sizeof(addr),
+					&sock);
+			dbgtext( "bind failed on port %d ", port);
+			dbgtext( "socket_addr = %s.\n", addr);
+			dbgtext( "Error = %s\n", strerror(errno));
+		}
+		close(res);
+		return -1;
+	}
+
+	DEBUG( 10, ( "bind succeeded on port %d\n", port ) );
+	return( res );
+ }
+
+struct open_socket_out_state {
+	int fd;
+	struct event_context *ev;
+	struct sockaddr_storage ss;
+	socklen_t salen;
+	uint16_t port;
+	int wait_nsec;
+};
+
+static void open_socket_out_connected(struct tevent_req *subreq);
+
+static int open_socket_out_state_destructor(struct open_socket_out_state *s)
+{
+	if (s->fd != -1) {
+		close(s->fd);
+	}
+	return 0;
+}
+
+/****************************************************************************
+ Create an outgoing socket. timeout is in milliseconds.
+**************************************************************************/
+
+struct tevent_req *open_socket_out_send(TALLOC_CTX *mem_ctx,
+					struct event_context *ev,
+					const struct sockaddr_storage *pss,
+					uint16_t port,
+					int timeout)
+{
+	char addr[INET6_ADDRSTRLEN];
+	struct tevent_req *result, *subreq;
+	struct open_socket_out_state *state;
+	NTSTATUS status;
+
+	result = tevent_req_create(mem_ctx, &state,
+				   struct open_socket_out_state);
+	if (result == NULL) {
+		return NULL;
+	}
+	state->ev = ev;
+	state->ss = *pss;
+	state->port = port;
+	state->wait_nsec = 10000;
+	state->salen = -1;
+
+	state->fd = socket(state->ss.ss_family, SOCK_STREAM, 0);
+	if (state->fd == -1) {
+		status = map_nt_error_from_unix(errno);
+		goto post_status;
+	}
+	talloc_set_destructor(state, open_socket_out_state_destructor);
+
+	if (!tevent_req_set_endtime(
+		    result, ev, timeval_current_ofs(0, timeout*1000))) {
+		goto fail;
+	}
+
+#if defined(HAVE_IPV6)
+	if (pss->ss_family == AF_INET6) {
+		struct sockaddr_in6 *psa6;
+		psa6 = (struct sockaddr_in6 *)&state->ss;
+		psa6->sin6_port = htons(port);
+		if (psa6->sin6_scope_id == 0
+		    && IN6_IS_ADDR_LINKLOCAL(&psa6->sin6_addr)) {
+			setup_linklocal_scope_id(
+				(struct sockaddr *)&(state->ss));
+		}
+		state->salen = sizeof(struct sockaddr_in6);
+	}
+#endif
+	if (pss->ss_family == AF_INET) {
+		struct sockaddr_in *psa;
+		psa = (struct sockaddr_in *)&state->ss;
+		psa->sin_port = htons(port);
+		state->salen = sizeof(struct sockaddr_in);
+	}
+
+	if (pss->ss_family == AF_UNIX) {
+		state->salen = sizeof(struct sockaddr_un);
+	}
+
+	print_sockaddr(addr, sizeof(addr), &state->ss);
+	DEBUG(3,("Connecting to %s at port %u\n", addr,	(unsigned int)port));
+
+	subreq = async_connect_send(state, state->ev, state->fd,
+				    (struct sockaddr *)&state->ss,
+				    state->salen);
+	if ((subreq == NULL)
+	    || !tevent_req_set_endtime(
+		    subreq, state->ev,
+		    timeval_current_ofs(0, state->wait_nsec))) {
+		goto fail;
+	}
+	tevent_req_set_callback(subreq, open_socket_out_connected, result);
+	return result;
+
+ post_status:
+	tevent_req_nterror(result, status);
+	return tevent_req_post(result, ev);
+ fail:
+	TALLOC_FREE(result);
+	return NULL;
+}
+
+static void open_socket_out_connected(struct tevent_req *subreq)
+{
+	struct tevent_req *req =
+		tevent_req_callback_data(subreq, struct tevent_req);
+	struct open_socket_out_state *state =
+		tevent_req_data(req, struct open_socket_out_state);
+	int ret;
+	int sys_errno;
+
+	ret = async_connect_recv(subreq, &sys_errno);
+	TALLOC_FREE(subreq);
+	if (ret == 0) {
+		tevent_req_done(req);
+		return;
+	}
+
+	if (
+#ifdef ETIMEDOUT
+		(sys_errno == ETIMEDOUT) ||
+#endif
+		(sys_errno == EINPROGRESS) ||
+		(sys_errno == EALREADY) ||
+		(sys_errno == EAGAIN)) {
+
+		/*
+		 * retry
+		 */
+
+		if (state->wait_nsec < 250000) {
+			state->wait_nsec *= 1.5;
+		}
+
+		subreq = async_connect_send(state, state->ev, state->fd,
+					    (struct sockaddr *)&state->ss,
+					    state->salen);
+		if (tevent_req_nomem(subreq, req)) {
+			return;
+		}
+		if (!tevent_req_set_endtime(
+			    subreq, state->ev,
+			    timeval_current_ofs(0, state->wait_nsec))) {
+			tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
+			return;
+		}
+		tevent_req_set_callback(subreq, open_socket_out_connected, req);
+		return;
+	}
+
+#ifdef EISCONN
+	if (sys_errno == EISCONN) {
+		tevent_req_done(req);
+		return;
+	}
+#endif
+
+	/* real error */
+	tevent_req_nterror(req, map_nt_error_from_unix(sys_errno));
+}
+
+NTSTATUS open_socket_out_recv(struct tevent_req *req, int *pfd)
+{
+	struct open_socket_out_state *state =
+		tevent_req_data(req, struct open_socket_out_state);
+	NTSTATUS status;
+
+	if (tevent_req_is_nterror(req, &status)) {
+		return status;
+	}
+	*pfd = state->fd;
+	state->fd = -1;
+	return NT_STATUS_OK;
+}
+
+NTSTATUS open_socket_out(const struct sockaddr_storage *pss, uint16_t port,
+			 int timeout, int *pfd)
+{
+	TALLOC_CTX *frame = talloc_stackframe();
+	struct event_context *ev;
+	struct tevent_req *req;
+	NTSTATUS status = NT_STATUS_NO_MEMORY;
+
+	ev = event_context_init(frame);
+	if (ev == NULL) {
+		goto fail;
+	}
+
+	req = open_socket_out_send(frame, ev, pss, port, timeout);
+	if (req == NULL) {
+		goto fail;
+	}
+	if (!tevent_req_poll(req, ev)) {
+		status = NT_STATUS_INTERNAL_ERROR;
+		goto fail;
+	}
+	status = open_socket_out_recv(req, pfd);
+ fail:
+	TALLOC_FREE(frame);
+	return status;
+}
+
+struct open_socket_out_defer_state {
+	struct event_context *ev;
+	struct sockaddr_storage ss;
+	uint16_t port;
+	int timeout;
+	int fd;
+};
+
+static void open_socket_out_defer_waited(struct tevent_req *subreq);
+static void open_socket_out_defer_connected(struct tevent_req *subreq);
+
+struct tevent_req *open_socket_out_defer_send(TALLOC_CTX *mem_ctx,
+					      struct event_context *ev,
+					      struct timeval wait_time,
+					      const struct sockaddr_storage *pss,
+					      uint16_t port,
+					      int timeout)
+{
+	struct tevent_req *req, *subreq;
+	struct open_socket_out_defer_state *state;
+
+	req = tevent_req_create(mem_ctx, &state,
+				struct open_socket_out_defer_state);
+	if (req == NULL) {
+		return NULL;
+	}
+	state->ev = ev;
+	state->ss = *pss;
+	state->port = port;
+	state->timeout = timeout;
+
+	subreq = tevent_wakeup_send(
+		state, ev,
+		timeval_current_ofs(wait_time.tv_sec, wait_time.tv_usec));
+	if (subreq == NULL) {
+		goto fail;
+	}
+	tevent_req_set_callback(subreq, open_socket_out_defer_waited, req);
+	return req;
+ fail:
+	TALLOC_FREE(req);
+	return NULL;
+}
+
+static void open_socket_out_defer_waited(struct tevent_req *subreq)
+{
+	struct tevent_req *req = tevent_req_callback_data(
+		subreq, struct tevent_req);
+	struct open_socket_out_defer_state *state = tevent_req_data(
+		req, struct open_socket_out_defer_state);
+	bool ret;
+
+	ret = tevent_wakeup_recv(subreq);
+	TALLOC_FREE(subreq);
+	if (!ret) {
+		tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
+		return;
+	}
+
+	subreq = open_socket_out_send(state, state->ev, &state->ss,
+				      state->port, state->timeout);
+	if (tevent_req_nomem(subreq, req)) {
+		return;
+	}
+	tevent_req_set_callback(subreq, open_socket_out_defer_connected, req);
+}
+
+static void open_socket_out_defer_connected(struct tevent_req *subreq)
+{
+	struct tevent_req *req = tevent_req_callback_data(
+		subreq, struct tevent_req);
+	struct open_socket_out_defer_state *state = tevent_req_data(
+		req, struct open_socket_out_defer_state);
+	NTSTATUS status;
+
+	status = open_socket_out_recv(subreq, &state->fd);
+	TALLOC_FREE(subreq);
+	if (!NT_STATUS_IS_OK(status)) {
+		tevent_req_nterror(req, status);
+		return;
+	}
+	tevent_req_done(req);
+}
+
+NTSTATUS open_socket_out_defer_recv(struct tevent_req *req, int *pfd)
+{
+	struct open_socket_out_defer_state *state = tevent_req_data(
+		req, struct open_socket_out_defer_state);
+	NTSTATUS status;
+
+	if (tevent_req_is_nterror(req, &status)) {
+		return status;
+	}
+	*pfd = state->fd;
+	state->fd = -1;
+	return NT_STATUS_OK;
+}
+
+/*******************************************************************
+ Create an outgoing TCP socket to the first addr that connects.
+
+ This is for simultaneous connection attempts to port 445 and 139 of a host
+ or for simultatneous connection attempts to multiple DCs at once.  We return
+ a socket fd of the first successful connection.
+
+ @param[in] addrs list of Internet addresses and ports to connect to
+ @param[in] num_addrs number of address/port pairs in the addrs list
+ @param[in] timeout time after which we stop waiting for a socket connection
+            to succeed, given in milliseconds
+ @param[out] fd_index the entry in addrs which we successfully connected to
+ @param[out] fd fd of the open and connected socket
+ @return true on a successful connection, false if all connection attempts
+         failed or we timed out
+*******************************************************************/
+
+bool open_any_socket_out(struct sockaddr_storage *addrs, int num_addrs,
+			 int timeout, int *fd_index, int *fd)
+{
+	int i, resulting_index, res;
+	int *sockets;
+	bool good_connect;
+
+	fd_set r_fds, wr_fds;
+	struct timeval tv;
+	int maxfd;
+
+	int connect_loop = 10000; /* 10 milliseconds */
+
+	timeout *= 1000; 	/* convert to microseconds */
+
+	sockets = SMB_MALLOC_ARRAY(int, num_addrs);
+
+	if (sockets == NULL)
+		return false;
+
+	resulting_index = -1;
+
+	for (i=0; i<num_addrs; i++)
+		sockets[i] = -1;
+
+	for (i=0; i<num_addrs; i++) {
+		sockets[i] = socket(addrs[i].ss_family, SOCK_STREAM, 0);
+		if (sockets[i] < 0)
+			goto done;
+		set_blocking(sockets[i], false);
+	}
+
+ connect_again:
+	good_connect = false;
+
+	for (i=0; i<num_addrs; i++) {
+		const struct sockaddr * a = 
+		    (const struct sockaddr *)&(addrs[i]);
+
+		if (sockets[i] == -1)
+			continue;
+
+		if (sys_connect(sockets[i], a) == 0) {
+			/* Rather unlikely as we are non-blocking, but it
+			 * might actually happen. */
+			resulting_index = i;
+			goto done;
+		}
+
+		if (errno == EINPROGRESS || errno == EALREADY ||
+#ifdef EISCONN
+			errno == EISCONN ||
+#endif
+		    errno == EAGAIN || errno == EINTR) {
+			/* These are the error messages that something is
+			   progressing. */
+			good_connect = true;
+		} else if (errno != 0) {
+			/* There was a direct error */
+			close(sockets[i]);
+			sockets[i] = -1;
+		}
+	}
+
+	if (!good_connect) {
+		/* All of the connect's resulted in real error conditions */
+		goto done;
+	}
+
+	/* Lets see if any of the connect attempts succeeded */
+
+	maxfd = 0;
+	FD_ZERO(&wr_fds);
+	FD_ZERO(&r_fds);
+
+	for (i=0; i<num_addrs; i++) {
+		if (sockets[i] == -1)
+			continue;
+		FD_SET(sockets[i], &wr_fds);
+		FD_SET(sockets[i], &r_fds);
+		if (sockets[i]>maxfd)
+			maxfd = sockets[i];
+	}
+
+	tv.tv_sec = 0;
+	tv.tv_usec = connect_loop;
+
+	res = sys_select_intr(maxfd+1, &r_fds, &wr_fds, NULL, &tv);
+
+	if (res < 0)
+		goto done;
+
+	if (res == 0)
+		goto next_round;
+
+	for (i=0; i<num_addrs; i++) {
+
+		if (sockets[i] == -1)
+			continue;
+
+		/* Stevens, Network Programming says that if there's a
+		 * successful connect, the socket is only writable. Upon an
+		 * error, it's both readable and writable. */
+
+		if (FD_ISSET(sockets[i], &r_fds) &&
+		    FD_ISSET(sockets[i], &wr_fds)) {
+			/* readable and writable, so it's an error */
+			close(sockets[i]);
+			sockets[i] = -1;
+			continue;
+		}
+
+		if (!FD_ISSET(sockets[i], &r_fds) &&
+		    FD_ISSET(sockets[i], &wr_fds)) {
+			/* Only writable, so it's connected */
+			resulting_index = i;
+			goto done;
+		}
+	}
+
+ next_round:
+
+	timeout -= connect_loop;
+	if (timeout <= 0)
+		goto done;
+	connect_loop *= 1.5;
+	if (connect_loop > timeout)
+		connect_loop = timeout;
+	goto connect_again;
+
+ done:
+	for (i=0; i<num_addrs; i++) {
+		if (i == resulting_index)
+			continue;
+		if (sockets[i] >= 0)
+			close(sockets[i]);
+	}
+
+	if (resulting_index >= 0) {
+		*fd_index = resulting_index;
+		*fd = sockets[*fd_index];
+		set_blocking(*fd, true);
+	}
+
+	free(sockets);
+
+	return (resulting_index >= 0);
+}
+/****************************************************************************
+ Open a connected UDP socket to host on port
+**************************************************************************/
+
+int open_udp_socket(const char *host, int port)
+{
+	struct sockaddr_storage ss;
+	int res;
+
+	if (!interpret_string_addr(&ss, host, 0)) {
+		DEBUG(10,("open_udp_socket: can't resolve name %s\n",
+			host));
+		return -1;
+	}
+
+	res = socket(ss.ss_family, SOCK_DGRAM, 0);
+	if (res == -1) {
+		return -1;
+	}
+
+#if defined(HAVE_IPV6)
+	if (ss.ss_family == AF_INET6) {
+		struct sockaddr_in6 *psa6;
+		psa6 = (struct sockaddr_in6 *)&ss;
+		psa6->sin6_port = htons(port);
+		if (psa6->sin6_scope_id == 0
+				&& IN6_IS_ADDR_LINKLOCAL(&psa6->sin6_addr)) {
+			setup_linklocal_scope_id(
+				(struct sockaddr *)&ss);
+		}
+	}
+#endif
+        if (ss.ss_family == AF_INET) {
+                struct sockaddr_in *psa;
+                psa = (struct sockaddr_in *)&ss;
+                psa->sin_port = htons(port);
+        }
+
+	if (sys_connect(res,(struct sockaddr *)&ss)) {
+		close(res);
+		return -1;
+	}
+
+	return res;
+}
+
+/*******************************************************************
+ Return the IP addr of the remote end of a socket as a string.
+ Optionally return the struct sockaddr_storage.
+ ******************************************************************/
+
+static const char *get_peer_addr_internal(int fd,
+				char *addr_buf,
+				size_t addr_buf_len,
+				struct sockaddr *pss,
+				socklen_t *plength)
+{
+	struct sockaddr_storage ss;
+	socklen_t length = sizeof(ss);
+
+	strlcpy(addr_buf,"0.0.0.0",addr_buf_len);
+
+	if (fd == -1) {
+		return addr_buf;
+	}
+
+	if (pss == NULL) {
+		pss = (struct sockaddr *)&ss;
+		plength = &length;
+	}
+
+	if (getpeername(fd, (struct sockaddr *)pss, plength) < 0) {
+		DEBUG(0,("getpeername failed. Error was %s\n",
+					strerror(errno) ));
+		return addr_buf;
+	}
+
+	print_sockaddr_len(addr_buf,
+			addr_buf_len,
+			pss,
+			*plength);
+	return addr_buf;
+}
+
+/*******************************************************************
+ Matchname - determine if host name matches IP address. Used to
+ confirm a hostname lookup to prevent spoof attacks.
+******************************************************************/
+
+static bool matchname(const char *remotehost,
+		const struct sockaddr *pss,
+		socklen_t len)
+{
+	struct addrinfo *res = NULL;
+	struct addrinfo *ailist = NULL;
+	char addr_buf[INET6_ADDRSTRLEN];
+	bool ret = interpret_string_addr_internal(&ailist,
+			remotehost,
+			AI_ADDRCONFIG|AI_CANONNAME);
+
+	if (!ret || ailist == NULL) {
+		DEBUG(3,("matchname: getaddrinfo failed for "
+			"name %s [%s]\n",
+			remotehost,
+			gai_strerror(ret) ));
+		return false;
+	}
+
+	/*
+	 * Make sure that getaddrinfo() returns the "correct" host name.
+	 */
+
+	if (ailist->ai_canonname == NULL ||
+		(!strequal(remotehost, ailist->ai_canonname) &&
+		 !strequal(remotehost, "localhost"))) {
+		DEBUG(0,("matchname: host name/name mismatch: %s != %s\n",
+			 remotehost,
+			 ailist->ai_canonname ?
+				 ailist->ai_canonname : "(NULL)"));
+		freeaddrinfo(ailist);
+		return false;
+	}
+
+	/* Look up the host address in the address list we just got. */
+	for (res = ailist; res; res = res->ai_next) {
+		if (!res->ai_addr) {
+			continue;
+		}
+		if (sockaddr_equal((const struct sockaddr *)res->ai_addr,
+					(struct sockaddr *)pss)) {
+			freeaddrinfo(ailist);
+			return true;
+		}
+	}
+
+	/*
+	 * The host name does not map to the original host address. Perhaps
+	 * someone has compromised a name server. More likely someone botched
+	 * it, but that could be dangerous, too.
+	 */
+
+	DEBUG(0,("matchname: host name/address mismatch: %s != %s\n",
+		print_sockaddr_len(addr_buf,
+			sizeof(addr_buf),
+			pss,
+			len),
+		 ailist->ai_canonname ? ailist->ai_canonname : "(NULL)"));
+
+	if (ailist) {
+		freeaddrinfo(ailist);
+	}
+	return false;
+}
+
+/*******************************************************************
+ Deal with the singleton cache.
+******************************************************************/
+
+struct name_addr_pair {
+	struct sockaddr_storage ss;
+	const char *name;
+};
+
+/*******************************************************************
+ Lookup a name/addr pair. Returns memory allocated from memcache.
+******************************************************************/
+
+static bool lookup_nc(struct name_addr_pair *nc)
+{
+	DATA_BLOB tmp;
+
+	ZERO_STRUCTP(nc);
+
+	if (!memcache_lookup(
+			NULL, SINGLETON_CACHE,
+			data_blob_string_const_null("get_peer_name"),
+			&tmp)) {
+		return false;
+	}
+
+	memcpy(&nc->ss, tmp.data, sizeof(nc->ss));
+	nc->name = (const char *)tmp.data + sizeof(nc->ss);
+	return true;
+}
+
+/*******************************************************************
+ Save a name/addr pair.
+******************************************************************/
+
+static void store_nc(const struct name_addr_pair *nc)
+{
+	DATA_BLOB tmp;
+	size_t namelen = strlen(nc->name);
+
+	tmp = data_blob(NULL, sizeof(nc->ss) + namelen + 1);
+	if (!tmp.data) {
+		return;
+	}
+	memcpy(tmp.data, &nc->ss, sizeof(nc->ss));
+	memcpy(tmp.data+sizeof(nc->ss), nc->name, namelen+1);
+
+	memcache_add(NULL, SINGLETON_CACHE,
+			data_blob_string_const_null("get_peer_name"),
+			tmp);
+	data_blob_free(&tmp);
+}
+
+/*******************************************************************
+ Return the DNS name of the remote end of a socket.
+******************************************************************/
+
+const char *get_peer_name(int fd, bool force_lookup)
+{
+	struct name_addr_pair nc;
+	char addr_buf[INET6_ADDRSTRLEN];
+	struct sockaddr_storage ss;
+	socklen_t length = sizeof(ss);
+	const char *p;
+	int ret;
+	char name_buf[MAX_DNS_NAME_LENGTH];
+	char tmp_name[MAX_DNS_NAME_LENGTH];
+
+	/* reverse lookups can be *very* expensive, and in many
+	   situations won't work because many networks don't link dhcp
+	   with dns. To avoid the delay we avoid the lookup if
+	   possible */
+	if (!lp_hostname_lookups() && (force_lookup == false)) {
+		length = sizeof(nc.ss);
+		nc.name = get_peer_addr_internal(fd, addr_buf, sizeof(addr_buf),
+			(struct sockaddr *)&nc.ss, &length);
+		store_nc(&nc);
+		lookup_nc(&nc);
+		return nc.name ? nc.name : "UNKNOWN";
+	}
+
+	lookup_nc(&nc);
+
+	memset(&ss, '\0', sizeof(ss));
+	p = get_peer_addr_internal(fd, addr_buf, sizeof(addr_buf), (struct sockaddr *)&ss, &length);
+
+	/* it might be the same as the last one - save some DNS work */
+	if (sockaddr_equal((struct sockaddr *)&ss, (struct sockaddr *)&nc.ss)) {
+		return nc.name ? nc.name : "UNKNOWN";
+	}
+
+	/* Not the same. We need to lookup. */
+	if (fd == -1) {
+		return "UNKNOWN";
+	}
+
+	/* Look up the remote host name. */
+	ret = sys_getnameinfo((struct sockaddr *)&ss,
+			length,
+			name_buf,
+			sizeof(name_buf),
+			NULL,
+			0,
+			0);
+
+	if (ret) {
+		DEBUG(1,("get_peer_name: getnameinfo failed "
+			"for %s with error %s\n",
+			p,
+			gai_strerror(ret)));
+		strlcpy(name_buf, p, sizeof(name_buf));
+	} else {
+		if (!matchname(name_buf, (struct sockaddr *)&ss, length)) {
+			DEBUG(0,("Matchname failed on %s %s\n",name_buf,p));
+			strlcpy(name_buf,"UNKNOWN",sizeof(name_buf));
+		}
+	}
+
+	/* can't pass the same source and dest strings in when you
+	   use --enable-developer or the clobber_region() call will
+	   get you */
+
+	strlcpy(tmp_name, name_buf, sizeof(tmp_name));
+	alpha_strcpy(name_buf, tmp_name, "_-.", sizeof(name_buf));
+	if (strstr(name_buf,"..")) {
+		strlcpy(name_buf, "UNKNOWN", sizeof(name_buf));
+	}
+
+	nc.name = name_buf;
+	nc.ss = ss;
+
+	store_nc(&nc);
+	lookup_nc(&nc);
+	return nc.name ? nc.name : "UNKNOWN";
+}
+
+/*******************************************************************
+ Return the IP addr of the remote end of a socket as a string.
+ ******************************************************************/
+
+const char *get_peer_addr(int fd, char *addr, size_t addr_len)
+{
+	return get_peer_addr_internal(fd, addr, addr_len, NULL, NULL);
+}
+
+/*******************************************************************
+ Create protected unix domain socket.
+
+ Some unixes cannot set permissions on a ux-dom-sock, so we
+ have to make sure that the directory contains the protection
+ permissions instead.
+ ******************************************************************/
+
+int create_pipe_sock(const char *socket_dir,
+		     const char *socket_name,
+		     mode_t dir_perms)
+{
+#ifdef HAVE_UNIXSOCKET
+	struct sockaddr_un sunaddr;
+	struct stat st;
+	int sock;
+	mode_t old_umask;
+	char *path = NULL;
+
+	old_umask = umask(0);
+
+	/* Create the socket directory or reuse the existing one */
+
+	if (lstat(socket_dir, &st) == -1) {
+		if (errno == ENOENT) {
+			/* Create directory */
+			if (mkdir(socket_dir, dir_perms) == -1) {
+				DEBUG(0, ("error creating socket directory "
+					"%s: %s\n", socket_dir,
+					strerror(errno)));
+				goto out_umask;
+			}
+		} else {
+			DEBUG(0, ("lstat failed on socket directory %s: %s\n",
+				socket_dir, strerror(errno)));
+			goto out_umask;
+		}
+	} else {
+		/* Check ownership and permission on existing directory */
+		if (!S_ISDIR(st.st_mode)) {
+			DEBUG(0, ("socket directory %s isn't a directory\n",
+				socket_dir));
+			goto out_umask;
+		}
+		if ((st.st_uid != sec_initial_uid()) ||
+				((st.st_mode & 0777) != dir_perms)) {
+			DEBUG(0, ("invalid permissions on socket directory "
+				"%s\n", socket_dir));
+			goto out_umask;
+		}
+	}
+
+	/* Create the socket file */
+
+	sock = socket(AF_UNIX, SOCK_STREAM, 0);
+
+	if (sock == -1) {
+		DEBUG(0, ("create_pipe_sock: socket error %s\n",
+			strerror(errno) ));
+                goto out_close;
+	}
+
+	if (asprintf(&path, "%s/%s", socket_dir, socket_name) == -1) {
+                goto out_close;
+	}
+
+	unlink(path);
+	memset(&sunaddr, 0, sizeof(sunaddr));
+	sunaddr.sun_family = AF_UNIX;
+	strlcpy(sunaddr.sun_path, path, sizeof(sunaddr.sun_path));
+
+	if (bind(sock, (struct sockaddr *)&sunaddr, sizeof(sunaddr)) == -1) {
+		DEBUG(0, ("bind failed on pipe socket %s: %s\n", path,
+			strerror(errno)));
+		goto out_close;
+	}
+
+	if (listen(sock, 5) == -1) {
+		DEBUG(0, ("listen failed on pipe socket %s: %s\n", path,
+			strerror(errno)));
+		goto out_close;
+	}
+
+	SAFE_FREE(path);
+
+	umask(old_umask);
+	return sock;
+
+out_close:
+	SAFE_FREE(path);
+	if (sock != -1)
+		close(sock);
+
+out_umask:
+	umask(old_umask);
+	return -1;
+
+#else
+        DEBUG(0, ("create_pipe_sock: No Unix sockets on this system\n"));
+        return -1;
+#endif /* HAVE_UNIXSOCKET */
+}
+
+/****************************************************************************
+ Get my own canonical name, including domain.
+****************************************************************************/
+
+const char *get_mydnsfullname(void)
+{
+	struct addrinfo *res = NULL;
+	char my_hostname[HOST_NAME_MAX];
+	bool ret;
+	DATA_BLOB tmp;
+
+	if (memcache_lookup(NULL, SINGLETON_CACHE,
+			data_blob_string_const_null("get_mydnsfullname"),
+			&tmp)) {
+		SMB_ASSERT(tmp.length > 0);
+		return (const char *)tmp.data;
+	}
+
+	/* get my host name */
+	if (gethostname(my_hostname, sizeof(my_hostname)) == -1) {
+		DEBUG(0,("get_mydnsfullname: gethostname failed\n"));
+		return NULL;
+	}
+
+	/* Ensure null termination. */
+	my_hostname[sizeof(my_hostname)-1] = '\0';
+
+	ret = interpret_string_addr_internal(&res,
+				my_hostname,
+				AI_ADDRCONFIG|AI_CANONNAME);
+
+	if (!ret || res == NULL) {
+		DEBUG(3,("get_mydnsfullname: getaddrinfo failed for "
+			"name %s [%s]\n",
+			my_hostname,
+			gai_strerror(ret) ));
+		return NULL;
+	}
+
+	/*
+	 * Make sure that getaddrinfo() returns the "correct" host name.
+	 */
+
+	if (res->ai_canonname == NULL) {
+		DEBUG(3,("get_mydnsfullname: failed to get "
+			"canonical name for %s\n",
+			my_hostname));
+		freeaddrinfo(res);
+		return NULL;
+	}
+
+	/* This copies the data, so we must do a lookup
+	 * afterwards to find the value to return.
+	 */
+
+	memcache_add(NULL, SINGLETON_CACHE,
+			data_blob_string_const_null("get_mydnsfullname"),
+			data_blob_string_const_null(res->ai_canonname));
+
+	if (!memcache_lookup(NULL, SINGLETON_CACHE,
+			data_blob_string_const_null("get_mydnsfullname"),
+			&tmp)) {
+		tmp = data_blob_talloc(talloc_tos(), res->ai_canonname,
+				strlen(res->ai_canonname) + 1);
+	}
+
+	freeaddrinfo(res);
+
+	return (const char *)tmp.data;
+}
+
+/************************************************************
+ Is this my name ?
+************************************************************/
+
+bool is_myname_or_ipaddr(const char *s)
+{
+	TALLOC_CTX *ctx = talloc_tos();
+	char addr[INET6_ADDRSTRLEN];
+	char *name = NULL;
+	const char *dnsname;
+	char *servername = NULL;
+
+	if (!s) {
+		return false;
+	}
+
+	/* Santize the string from '\\name' */
+	name = talloc_strdup(ctx, s);
+	if (!name) {
+		return false;
+	}
+
+	servername = strrchr_m(name, '\\' );
+	if (!servername) {
+		servername = name;
+	} else {
+		servername++;
+	}
+
+	/* Optimize for the common case */
+	if (strequal(servername, global_myname())) {
+		return true;
+	}
+
+	/* Check for an alias */
+	if (is_myname(servername)) {
+		return true;
+	}
+
+	/* Check for loopback */
+	if (strequal(servername, "127.0.0.1") ||
+			strequal(servername, "::1")) {
+		return true;
+	}
+
+	if (strequal(servername, "localhost")) {
+		return true;
+	}
+
+	/* Maybe it's my dns name */
+	dnsname = get_mydnsfullname();
+	if (dnsname && strequal(servername, dnsname)) {
+		return true;
+	}
+
+	/* Handle possible CNAME records - convert to an IP addr. */
+	if (!is_ipaddress(servername)) {
+		/* Use DNS to resolve the name, but only the first address */
+		struct sockaddr_storage ss;
+		if (interpret_string_addr(&ss, servername, 0)) {
+			print_sockaddr(addr,
+					sizeof(addr),
+					&ss);
+			servername = addr;
+		}
+	}
+
+	/* Maybe its an IP address? */
+	if (is_ipaddress(servername)) {
+		struct sockaddr_storage ss;
+		struct iface_struct *nics;
+		int i, n;
+
+		if (!interpret_string_addr(&ss, servername, AI_NUMERICHOST)) {
+			return false;
+		}
+
+		if (ismyaddr((struct sockaddr *)&ss)) {
+			return true;
+		}
+
+		if (is_zero_addr((struct sockaddr *)&ss) || 
+			is_loopback_addr((struct sockaddr *)&ss)) {
+			return false;
+		}
+
+		n = get_interfaces(talloc_tos(), &nics);
+		for (i=0; i<n; i++) {
+			if (sockaddr_equal((struct sockaddr *)&nics[i].ip, (struct sockaddr *)&ss)) {
+				TALLOC_FREE(nics);
+				return true;
+			}
+		}
+		TALLOC_FREE(nics);
+	}
+
+	/* No match */
+	return false;
+}
+
+struct getaddrinfo_state {
+	const char *node;
+	const char *service;
+	const struct addrinfo *hints;
+	struct addrinfo *res;
+	int ret;
+};
+
+static void getaddrinfo_do(void *private_data);
+static void getaddrinfo_done(struct tevent_req *subreq);
+
+struct tevent_req *getaddrinfo_send(TALLOC_CTX *mem_ctx,
+				    struct tevent_context *ev,
+				    struct fncall_context *ctx,
+				    const char *node,
+				    const char *service,
+				    const struct addrinfo *hints)
+{
+	struct tevent_req *req, *subreq;
+	struct getaddrinfo_state *state;
+
+	req = tevent_req_create(mem_ctx, &state, struct getaddrinfo_state);
+	if (req == NULL) {
+		return NULL;
+	}
+
+	state->node = node;
+	state->service = service;
+	state->hints = hints;
+
+	subreq = fncall_send(state, ev, ctx, getaddrinfo_do, state);
+	if (tevent_req_nomem(subreq, req)) {
+		return tevent_req_post(req, ev);
+	}
+	tevent_req_set_callback(subreq, getaddrinfo_done, req);
+	return req;
+}
+
+static void getaddrinfo_do(void *private_data)
+{
+	struct getaddrinfo_state *state =
+		(struct getaddrinfo_state *)private_data;
+
+	state->ret = getaddrinfo(state->node, state->service, state->hints,
+				 &state->res);
+}
+
+static void getaddrinfo_done(struct tevent_req *subreq)
+{
+	struct tevent_req *req = tevent_req_callback_data(
+		subreq, struct tevent_req);
+	int ret, err;
+
+	ret = fncall_recv(subreq, &err);
+	TALLOC_FREE(subreq);
+	if (ret == -1) {
+		tevent_req_error(req, err);
+		return;
+	}
+	tevent_req_done(req);
+}
+
+int getaddrinfo_recv(struct tevent_req *req, struct addrinfo **res)
+{
+	struct getaddrinfo_state *state = tevent_req_data(
+		req, struct getaddrinfo_state);
+	int err;
+
+	if (tevent_req_is_unix_error(req, &err)) {
+		switch(err) {
+		case ENOMEM:
+			return EAI_MEMORY;
+		default:
+			return EAI_FAIL;
+		}
+	}
+	if (state->ret == 0) {
+		*res = state->res;
+	}
+	return state->ret;
+}

=== added directory '.pc/security-CVE-2011-0719.patch/source3/libaddns'
=== added file '.pc/security-CVE-2011-0719.patch/source3/libaddns/dnssock.c'
--- .pc/security-CVE-2011-0719.patch/source3/libaddns/dnssock.c	1970-01-01 00:00:00 +0000
+++ .pc/security-CVE-2011-0719.patch/source3/libaddns/dnssock.c	2011-03-02 20:48:44 +0000
@@ -0,0 +1,377 @@
+/*
+  Linux DNS client library implementation
+
+  Copyright (C) 2006 Krishna Ganugapati <krishnag@centeris.com>
+  Copyright (C) 2006 Gerald Carter <jerry@samba.org>
+
+     ** NOTE! The following LGPL license applies to the libaddns
+     ** library. This does NOT imply that all of Samba is released
+     ** under the LGPL
+
+  This library is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Lesser General Public
+  License as published by the Free Software Foundation; either
+  version 2.1 of the License, or (at your option) any later version.
+
+  This library 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
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public
+  License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "dns.h"
+#include <sys/time.h>
+#include <unistd.h>
+
+static int destroy_dns_connection(struct dns_connection *conn)
+{
+	return close(conn->s);
+}
+
+/********************************************************************
+********************************************************************/
+
+static DNS_ERROR dns_tcp_open( const char *nameserver,
+			       TALLOC_CTX *mem_ctx,
+			       struct dns_connection **result )
+{
+	uint32_t ulAddress;
+	struct hostent *pHost;
+	struct sockaddr_in s_in;
+	struct dns_connection *conn;
+	int res;
+
+	if (!(conn = talloc(mem_ctx, struct dns_connection))) {
+		return ERROR_DNS_NO_MEMORY;
+	}
+
+	if ( (ulAddress = inet_addr( nameserver )) == INADDR_NONE ) {
+		if ( (pHost = gethostbyname( nameserver )) == NULL ) {
+			TALLOC_FREE(conn);
+			return ERROR_DNS_INVALID_NAME_SERVER;
+		}
+		memcpy( &ulAddress, pHost->h_addr, pHost->h_length );
+	}
+
+	conn->s = socket( PF_INET, SOCK_STREAM, 0 );
+	if (conn->s == -1) {
+		TALLOC_FREE(conn);
+		return ERROR_DNS_CONNECTION_FAILED;
+	}
+
+	talloc_set_destructor(conn, destroy_dns_connection);
+
+	s_in.sin_family = AF_INET;
+	s_in.sin_addr.s_addr = ulAddress;
+	s_in.sin_port = htons( DNS_TCP_PORT );
+
+	res = connect(conn->s, (struct sockaddr*)&s_in, sizeof( s_in ));
+	if (res == -1) {
+		TALLOC_FREE(conn);
+		return ERROR_DNS_CONNECTION_FAILED;
+	}
+
+	conn->hType = DNS_TCP;
+
+	*result = conn;
+	return ERROR_DNS_SUCCESS;
+}
+
+/********************************************************************
+********************************************************************/
+
+static DNS_ERROR dns_udp_open( const char *nameserver,
+			       TALLOC_CTX *mem_ctx,
+			       struct dns_connection **result )
+{
+	unsigned long ulAddress;
+	struct hostent *pHost;
+	struct sockaddr_in RecvAddr;
+	struct dns_connection *conn;
+
+	if (!(conn = talloc(NULL, struct dns_connection))) {
+		return ERROR_DNS_NO_MEMORY;
+	}
+
+	if ( (ulAddress = inet_addr( nameserver )) == INADDR_NONE ) {
+		if ( (pHost = gethostbyname( nameserver )) == NULL ) {
+			TALLOC_FREE(conn);
+			return ERROR_DNS_INVALID_NAME_SERVER;
+		}
+		memcpy( &ulAddress, pHost->h_addr, pHost->h_length );
+	}
+	
+	/* Create a socket for sending data */
+
+	conn->s = socket( AF_INET, SOCK_DGRAM, IPPROTO_UDP );
+	if (conn->s == -1) {
+		TALLOC_FREE(conn);
+		return ERROR_DNS_CONNECTION_FAILED;
+	}
+
+	talloc_set_destructor(conn, destroy_dns_connection);
+
+	/* Set up the RecvAddr structure with the IP address of
+	   the receiver (in this example case "123.456.789.1")
+	   and the specified port number. */
+
+	ZERO_STRUCT(RecvAddr);
+	RecvAddr.sin_family = AF_INET;
+	RecvAddr.sin_port = htons( DNS_UDP_PORT );
+	RecvAddr.sin_addr.s_addr = ulAddress;
+
+	conn->hType = DNS_UDP;
+	memcpy( &conn->RecvAddr, &RecvAddr, sizeof( struct sockaddr_in ) );
+
+	*result = conn;
+	return ERROR_DNS_SUCCESS;
+}
+
+/********************************************************************
+********************************************************************/
+
+DNS_ERROR dns_open_connection( const char *nameserver, int32 dwType,
+		    TALLOC_CTX *mem_ctx,
+		    struct dns_connection **conn )
+{
+	switch ( dwType ) {
+	case DNS_TCP:
+		return dns_tcp_open( nameserver, mem_ctx, conn );
+	case DNS_UDP:
+		return dns_udp_open( nameserver, mem_ctx, conn );
+	}
+	
+	return ERROR_DNS_INVALID_PARAMETER;
+}
+
+static DNS_ERROR write_all(int fd, uint8 *data, size_t len)
+{
+	size_t total = 0;
+
+	while (total < len) {
+
+		ssize_t ret = write(fd, data + total, len - total);
+
+		if (ret <= 0) {
+			/*
+			 * EOF or error
+			 */
+			return ERROR_DNS_SOCKET_ERROR;
+		}
+
+		total += ret;
+	}
+
+	return ERROR_DNS_SUCCESS;
+}
+
+static DNS_ERROR dns_send_tcp(struct dns_connection *conn,
+			      const struct dns_buffer *buf)
+{
+	uint16 len = htons(buf->offset);
+	DNS_ERROR err;
+
+	err = write_all(conn->s, (uint8 *)&len, sizeof(len));
+	if (!ERR_DNS_IS_OK(err)) return err;
+
+	return write_all(conn->s, buf->data, buf->offset);
+}
+
+static DNS_ERROR dns_send_udp(struct dns_connection *conn,
+			      const struct dns_buffer *buf)
+{
+	ssize_t ret;
+
+	ret = sendto(conn->s, buf->data, buf->offset, 0,
+		     (struct sockaddr *)&conn->RecvAddr,
+		     sizeof(conn->RecvAddr));
+
+	if (ret != buf->offset) {
+		return ERROR_DNS_SOCKET_ERROR;
+	}
+
+	return ERROR_DNS_SUCCESS;
+}
+
+DNS_ERROR dns_send(struct dns_connection *conn, const struct dns_buffer *buf)
+{
+	if (conn->hType == DNS_TCP) {
+		return dns_send_tcp(conn, buf);
+	}
+
+	if (conn->hType == DNS_UDP) {
+		return dns_send_udp(conn, buf);
+	}
+
+	return ERROR_DNS_INVALID_PARAMETER;
+}
+
+static DNS_ERROR read_all(int fd, uint8 *data, size_t len)
+{
+	size_t total = 0;
+	fd_set rfds;
+	struct timeval tv;
+
+	while (total < len) {
+		ssize_t ret;
+		int fd_ready;
+		
+		FD_ZERO( &rfds );
+		FD_SET( fd, &rfds );
+
+		/* 10 second timeout */
+		tv.tv_sec = 10;
+		tv.tv_usec = 0;
+		
+		fd_ready = select( fd+1, &rfds, NULL, NULL, &tv );
+		if ( fd_ready == 0 ) {
+			/* read timeout */
+			return ERROR_DNS_SOCKET_ERROR;
+		}
+
+		ret = read(fd, data + total, len - total);
+		if (ret <= 0) {
+			/* EOF or error */
+			return ERROR_DNS_SOCKET_ERROR;
+		}
+
+		total += ret;
+	}
+
+	return ERROR_DNS_SUCCESS;
+}
+
+static DNS_ERROR dns_receive_tcp(TALLOC_CTX *mem_ctx,
+				 struct dns_connection *conn,
+				 struct dns_buffer **presult)
+{
+	struct dns_buffer *buf;
+	DNS_ERROR err;
+	uint16 len;
+
+	if (!(buf = TALLOC_ZERO_P(mem_ctx, struct dns_buffer))) {
+		return ERROR_DNS_NO_MEMORY;
+	}
+
+	err = read_all(conn->s, (uint8 *)&len, sizeof(len));
+	if (!ERR_DNS_IS_OK(err)) {
+		return err;
+	}
+
+	buf->size = ntohs(len);
+
+	if (buf->size) {
+		if (!(buf->data = TALLOC_ARRAY(buf, uint8, buf->size))) {
+			TALLOC_FREE(buf);
+			return ERROR_DNS_NO_MEMORY;
+		}
+	} else {
+		buf->data = NULL;
+	}
+
+	err = read_all(conn->s, buf->data, buf->size);
+	if (!ERR_DNS_IS_OK(err)) {
+		TALLOC_FREE(buf);
+		return err;
+	}
+
+	*presult = buf;
+	return ERROR_DNS_SUCCESS;
+}
+
+static DNS_ERROR dns_receive_udp(TALLOC_CTX *mem_ctx,
+				 struct dns_connection *conn,
+				 struct dns_buffer **presult)
+{
+	struct dns_buffer *buf;
+	ssize_t received;
+
+	if (!(buf = TALLOC_ZERO_P(mem_ctx, struct dns_buffer))) {
+		return ERROR_DNS_NO_MEMORY;
+	}
+
+	/*
+	 * UDP based DNS can only be 512 bytes
+	 */
+
+	if (!(buf->data = TALLOC_ARRAY(buf, uint8, 512))) {
+		TALLOC_FREE(buf);
+		return ERROR_DNS_NO_MEMORY;
+	}
+
+	received = recv(conn->s, (void *)buf->data, 512, 0);
+
+	if (received == -1) {
+		TALLOC_FREE(buf);
+		return ERROR_DNS_SOCKET_ERROR;
+	}
+
+	if (received > 512) {
+		TALLOC_FREE(buf);
+		return ERROR_DNS_BAD_RESPONSE;
+	}
+
+	buf->size = received;
+	buf->offset = 0;
+
+	*presult = buf;
+	return ERROR_DNS_SUCCESS;
+}
+
+DNS_ERROR dns_receive(TALLOC_CTX *mem_ctx, struct dns_connection *conn,
+		      struct dns_buffer **presult)
+{
+	if (conn->hType == DNS_TCP) {
+		return dns_receive_tcp(mem_ctx, conn, presult);
+	}
+
+	if (conn->hType == DNS_UDP) {
+		return dns_receive_udp(mem_ctx, conn, presult);
+	}
+
+	return ERROR_DNS_INVALID_PARAMETER;
+}
+
+DNS_ERROR dns_transaction(TALLOC_CTX *mem_ctx, struct dns_connection *conn,
+			  const struct dns_request *req,
+			  struct dns_request **resp)
+{
+	struct dns_buffer *buf = NULL;
+	DNS_ERROR err;
+
+	err = dns_marshall_request(conn, req, &buf);
+	if (!ERR_DNS_IS_OK(err)) goto error;
+
+	err = dns_send(conn, buf);
+	if (!ERR_DNS_IS_OK(err)) goto error;
+	TALLOC_FREE(buf);
+
+	err = dns_receive(mem_ctx, conn, &buf);
+	if (!ERR_DNS_IS_OK(err)) goto error;
+
+	err = dns_unmarshall_request(mem_ctx, buf, resp);
+
+ error:
+	TALLOC_FREE(buf);
+	return err;
+}
+
+DNS_ERROR dns_update_transaction(TALLOC_CTX *mem_ctx,
+				 struct dns_connection *conn,
+				 struct dns_update_request *up_req,
+				 struct dns_update_request **up_resp)
+{
+	struct dns_request *resp;
+	DNS_ERROR err;
+
+	err = dns_transaction(mem_ctx, conn, dns_update2request(up_req),
+			      &resp);
+
+	if (!ERR_DNS_IS_OK(err)) return err;
+
+	*up_resp = dns_request2update(resp);
+	return ERROR_DNS_SUCCESS;
+}

=== added directory '.pc/security-CVE-2011-0719.patch/source3/libsmb'
=== added file '.pc/security-CVE-2011-0719.patch/source3/libsmb/nmblib.c'
--- .pc/security-CVE-2011-0719.patch/source3/libsmb/nmblib.c	1970-01-01 00:00:00 +0000
+++ .pc/security-CVE-2011-0719.patch/source3/libsmb/nmblib.c	2011-03-02 20:48:44 +0000
@@ -0,0 +1,1404 @@
+/*
+   Unix SMB/CIFS implementation.
+   NBT netbios library routines
+   Copyright (C) Andrew Tridgell 1994-1998
+   Copyright (C) Jeremy Allison 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 3 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, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "includes.h"
+
+static const struct opcode_names {
+	const char *nmb_opcode_name;
+	int opcode;
+} nmb_header_opcode_names[] = {
+	{"Query",           0 },
+	{"Registration",      5 },
+	{"Release",           6 },
+	{"WACK",              7 },
+	{"Refresh",           8 },
+	{"Refresh(altcode)",  9 },
+	{"Multi-homed Registration", 15 },
+	{0, -1 }
+};
+
+/****************************************************************************
+ Lookup a nmb opcode name.
+****************************************************************************/
+
+static const char *lookup_opcode_name( int opcode )
+{
+	const struct opcode_names *op_namep;
+	int i;
+
+	for(i = 0; nmb_header_opcode_names[i].nmb_opcode_name != 0; i++) {
+		op_namep = &nmb_header_opcode_names[i];
+		if(opcode == op_namep->opcode)
+			return op_namep->nmb_opcode_name;
+	}
+	return "<unknown opcode>";
+}
+
+/****************************************************************************
+ Print out a res_rec structure.
+****************************************************************************/
+
+static void debug_nmb_res_rec(struct res_rec *res, const char *hdr)
+{
+	int i, j;
+
+	DEBUGADD( 4, ( "    %s: nmb_name=%s rr_type=%d rr_class=%d ttl=%d\n",
+		hdr,
+		nmb_namestr(&res->rr_name),
+		res->rr_type,
+		res->rr_class,
+		res->ttl ) );
+
+	if( res->rdlength == 0 || res->rdata == NULL )
+		return;
+
+	for (i = 0; i < res->rdlength; i+= MAX_NETBIOSNAME_LEN) {
+		DEBUGADD(4, ("    %s %3x char ", hdr, i));
+
+		for (j = 0; j < MAX_NETBIOSNAME_LEN; j++) {
+			unsigned char x = res->rdata[i+j];
+			if (x < 32 || x > 127)
+				x = '.';
+
+			if (i+j >= res->rdlength)
+				break;
+			DEBUGADD(4, ("%c", x));
+		}
+
+		DEBUGADD(4, ("   hex "));
+
+		for (j = 0; j < MAX_NETBIOSNAME_LEN; j++) {
+			if (i+j >= res->rdlength)
+				break;
+			DEBUGADD(4, ("%02X", (unsigned char)res->rdata[i+j]));
+		}
+
+		DEBUGADD(4, ("\n"));
+	}
+}
+
+/****************************************************************************
+ Process a nmb packet.
+****************************************************************************/
+
+void debug_nmb_packet(struct packet_struct *p)
+{
+	struct nmb_packet *nmb = &p->packet.nmb;
+
+	if( DEBUGLVL( 4 ) ) {
+		dbgtext( "nmb packet from %s(%d) header: id=%d "
+				"opcode=%s(%d) response=%s\n",
+			inet_ntoa(p->ip), p->port,
+			nmb->header.name_trn_id,
+			lookup_opcode_name(nmb->header.opcode),
+			nmb->header.opcode,
+			BOOLSTR(nmb->header.response) );
+		dbgtext( "    header: flags: bcast=%s rec_avail=%s "
+				"rec_des=%s trunc=%s auth=%s\n",
+			BOOLSTR(nmb->header.nm_flags.bcast),
+			BOOLSTR(nmb->header.nm_flags.recursion_available),
+			BOOLSTR(nmb->header.nm_flags.recursion_desired),
+			BOOLSTR(nmb->header.nm_flags.trunc),
+			BOOLSTR(nmb->header.nm_flags.authoritative) );
+		dbgtext( "    header: rcode=%d qdcount=%d ancount=%d "
+				"nscount=%d arcount=%d\n",
+			nmb->header.rcode,
+			nmb->header.qdcount,
+			nmb->header.ancount,
+			nmb->header.nscount,
+			nmb->header.arcount );
+	}
+
+	if (nmb->header.qdcount) {
+		DEBUGADD( 4, ( "    question: q_name=%s q_type=%d q_class=%d\n",
+			nmb_namestr(&nmb->question.question_name),
+			nmb->question.question_type,
+			nmb->question.question_class) );
+	}
+
+	if (nmb->answers && nmb->header.ancount) {
+		debug_nmb_res_rec(nmb->answers,"answers");
+	}
+	if (nmb->nsrecs && nmb->header.nscount) {
+		debug_nmb_res_rec(nmb->nsrecs,"nsrecs");
+	}
+	if (nmb->additional && nmb->header.arcount) {
+		debug_nmb_res_rec(nmb->additional,"additional");
+	}
+}
+
+/*******************************************************************
+ Handle "compressed" name pointers.
+******************************************************************/
+
+static bool handle_name_ptrs(unsigned char *ubuf,int *offset,int length,
+			     bool *got_pointer,int *ret)
+{
+	int loop_count=0;
+
+	while ((ubuf[*offset] & 0xC0) == 0xC0) {
+		if (!*got_pointer)
+			(*ret) += 2;
+		(*got_pointer)=True;
+		(*offset) = ((ubuf[*offset] & ~0xC0)<<8) | ubuf[(*offset)+1];
+		if (loop_count++ == 10 ||
+				(*offset) < 0 || (*offset)>(length-2)) {
+			return False;
+		}
+	}
+	return True;
+}
+
+/*******************************************************************
+ Parse a nmb name from "compressed" format to something readable
+ return the space taken by the name, or 0 if the name is invalid
+******************************************************************/
+
+static int parse_nmb_name(char *inbuf,int ofs,int length, struct nmb_name *name)
+{
+	int m,n=0;
+	unsigned char *ubuf = (unsigned char *)inbuf;
+	int ret = 0;
+	bool got_pointer=False;
+	int loop_count=0;
+	int offset = ofs;
+
+	if (length - offset < 2)
+		return(0);
+
+	/* handle initial name pointers */
+	if (!handle_name_ptrs(ubuf,&offset,length,&got_pointer,&ret))
+		return(0);
+
+	m = ubuf[offset];
+
+	if (!m)
+		return(0);
+	if ((m & 0xC0) || offset+m+2 > length)
+		return(0);
+
+	memset((char *)name,'\0',sizeof(*name));
+
+	/* the "compressed" part */
+	if (!got_pointer)
+		ret += m + 2;
+	offset++;
+	while (m > 0) {
+		unsigned char c1,c2;
+		c1 = ubuf[offset++]-'A';
+		c2 = ubuf[offset++]-'A';
+		if ((c1 & 0xF0) || (c2 & 0xF0) || (n > sizeof(name->name)-1))
+			return(0);
+		name->name[n++] = (c1<<4) | c2;
+		m -= 2;
+	}
+	name->name[n] = 0;
+
+	if (n==MAX_NETBIOSNAME_LEN) {
+		/* parse out the name type, its always
+		 * in the 16th byte of the name */
+		name->name_type = ((unsigned char)name->name[15]) & 0xff;
+
+		/* remove trailing spaces */
+		name->name[15] = 0;
+		n = 14;
+		while (n && name->name[n]==' ')
+			name->name[n--] = 0;
+	}
+
+	/* now the domain parts (if any) */
+	n = 0;
+	while (ubuf[offset]) {
+		/* we can have pointers within the domain part as well */
+		if (!handle_name_ptrs(ubuf,&offset,length,&got_pointer,&ret))
+			return(0);
+
+		m = ubuf[offset];
+		/*
+		 * Don't allow null domain parts.
+		 */
+		if (!m)
+			return(0);
+		if (!got_pointer)
+			ret += m+1;
+		if (n)
+			name->scope[n++] = '.';
+		if (m+2+offset>length || n+m+1>sizeof(name->scope))
+			return(0);
+		offset++;
+		while (m--)
+			name->scope[n++] = (char)ubuf[offset++];
+
+		/*
+		 * Watch for malicious loops.
+		 */
+		if (loop_count++ == 10)
+			return 0;
+	}
+	name->scope[n++] = 0;
+
+	return(ret);
+}
+
+/****************************************************************************
+ Put a netbios name, padding(s) and a name type into a 16 character buffer.
+ name is already in DOS charset.
+ [15 bytes name + padding][1 byte name type].
+****************************************************************************/
+
+void put_name(char *dest, const char *name, int pad, unsigned int name_type)
+{
+	size_t len = strlen(name);
+
+	memcpy(dest, name, (len < MAX_NETBIOSNAME_LEN) ?
+			len : MAX_NETBIOSNAME_LEN - 1);
+	if (len < MAX_NETBIOSNAME_LEN - 1) {
+		memset(dest + len, pad, MAX_NETBIOSNAME_LEN - 1 - len);
+	}
+	dest[MAX_NETBIOSNAME_LEN - 1] = name_type;
+}
+
+/*******************************************************************
+ Put a compressed nmb name into a buffer. Return the length of the
+ compressed name.
+
+ Compressed names are really weird. The "compression" doubles the
+ size. The idea is that it also means that compressed names conform
+ to the doman name system. See RFC1002.
+
+ If buf == NULL this is a length calculation.
+******************************************************************/
+
+static int put_nmb_name(char *buf,int offset,struct nmb_name *name)
+{
+	int ret,m;
+	nstring buf1;
+	char *p;
+
+	if (strcmp(name->name,"*") == 0) {
+		/* special case for wildcard name */
+		put_name(buf1, "*", '\0', name->name_type);
+	} else {
+		put_name(buf1, name->name, ' ', name->name_type);
+	}
+
+	if (buf) {
+		buf[offset] = 0x20;
+	}
+
+	ret = 34;
+
+	for (m=0;m<MAX_NETBIOSNAME_LEN;m++) {
+		if (buf) {
+			buf[offset+1+2*m] = 'A' + ((buf1[m]>>4)&0xF);
+			buf[offset+2+2*m] = 'A' + (buf1[m]&0xF);
+		}
+	}
+	offset += 33;
+
+	if (buf) {
+		buf[offset] = 0;
+	}
+
+	if (name->scope[0]) {
+		/* XXXX this scope handling needs testing */
+		ret += strlen(name->scope) + 1;
+		if (buf) {
+			safe_strcpy(&buf[offset+1],name->scope,
+					sizeof(name->scope));
+
+			p = &buf[offset+1];
+			while ((p = strchr_m(p,'.'))) {
+				buf[offset] = PTR_DIFF(p,&buf[offset+1]);
+				offset += (buf[offset] + 1);
+				p = &buf[offset+1];
+			}
+			buf[offset] = strlen(&buf[offset+1]);
+		}
+	}
+
+	return ret;
+}
+
+/*******************************************************************
+ Useful for debugging messages.
+******************************************************************/
+
+char *nmb_namestr(const struct nmb_name *n)
+{
+	fstring name;
+	char *result;
+
+	pull_ascii_fstring(name, n->name);
+	if (!n->scope[0])
+		result = talloc_asprintf(talloc_tos(), "%s<%02x>", name,
+					 n->name_type);
+	else
+		result = talloc_asprintf(talloc_tos(), "%s<%02x>.%s", name,
+					 n->name_type, n->scope);
+
+	SMB_ASSERT(result != NULL);
+	return result;
+}
+
+/*******************************************************************
+ Allocate and parse some resource records.
+******************************************************************/
+
+static bool parse_alloc_res_rec(char *inbuf,int *offset,int length,
+				struct res_rec **recs, int count)
+{
+	int i;
+
+	*recs = SMB_MALLOC_ARRAY(struct res_rec, count);
+	if (!*recs)
+		return(False);
+
+	memset((char *)*recs,'\0',sizeof(**recs)*count);
+
+	for (i=0;i<count;i++) {
+		int l = parse_nmb_name(inbuf,*offset,length,
+				&(*recs)[i].rr_name);
+		(*offset) += l;
+		if (!l || (*offset)+10 > length) {
+			SAFE_FREE(*recs);
+			return(False);
+		}
+		(*recs)[i].rr_type = RSVAL(inbuf,(*offset));
+		(*recs)[i].rr_class = RSVAL(inbuf,(*offset)+2);
+		(*recs)[i].ttl = RIVAL(inbuf,(*offset)+4);
+		(*recs)[i].rdlength = RSVAL(inbuf,(*offset)+8);
+		(*offset) += 10;
+		if ((*recs)[i].rdlength>sizeof((*recs)[i].rdata) ||
+				(*offset)+(*recs)[i].rdlength > length) {
+			SAFE_FREE(*recs);
+			return(False);
+		}
+		memcpy((*recs)[i].rdata,inbuf+(*offset),(*recs)[i].rdlength);
+		(*offset) += (*recs)[i].rdlength;
+	}
+	return(True);
+}
+
+/*******************************************************************
+ Put a resource record into a packet.
+ If buf == NULL this is a length calculation.
+******************************************************************/
+
+static int put_res_rec(char *buf,int offset,struct res_rec *recs,int count)
+{
+	int ret=0;
+	int i;
+
+	for (i=0;i<count;i++) {
+		int l = put_nmb_name(buf,offset,&recs[i].rr_name);
+		offset += l;
+		ret += l;
+		if (buf) {
+			RSSVAL(buf,offset,recs[i].rr_type);
+			RSSVAL(buf,offset+2,recs[i].rr_class);
+			RSIVAL(buf,offset+4,recs[i].ttl);
+			RSSVAL(buf,offset+8,recs[i].rdlength);
+			memcpy(buf+offset+10,recs[i].rdata,recs[i].rdlength);
+		}
+		offset += 10+recs[i].rdlength;
+		ret += 10+recs[i].rdlength;
+	}
+
+	return ret;
+}
+
+/*******************************************************************
+ Put a compressed name pointer record into a packet.
+ If buf == NULL this is a length calculation.
+******************************************************************/
+
+static int put_compressed_name_ptr(unsigned char *buf,
+				int offset,
+				struct res_rec *rec,
+				int ptr_offset)
+{
+	int ret=0;
+	if (buf) {
+		buf[offset] = (0xC0 | ((ptr_offset >> 8) & 0xFF));
+		buf[offset+1] = (ptr_offset & 0xFF);
+	}
+	offset += 2;
+	ret += 2;
+	if (buf) {
+		RSSVAL(buf,offset,rec->rr_type);
+		RSSVAL(buf,offset+2,rec->rr_class);
+		RSIVAL(buf,offset+4,rec->ttl);
+		RSSVAL(buf,offset+8,rec->rdlength);
+		memcpy(buf+offset+10,rec->rdata,rec->rdlength);
+	}
+	offset += 10+rec->rdlength;
+	ret += 10+rec->rdlength;
+
+	return ret;
+}
+
+/*******************************************************************
+ Parse a dgram packet. Return False if the packet can't be parsed
+ or is invalid for some reason, True otherwise.
+
+ This is documented in section 4.4.1 of RFC1002.
+******************************************************************/
+
+static bool parse_dgram(char *inbuf,int length,struct dgram_packet *dgram)
+{
+	int offset;
+	int flags;
+
+	memset((char *)dgram,'\0',sizeof(*dgram));
+
+	if (length < 14)
+		return(False);
+
+	dgram->header.msg_type = CVAL(inbuf,0);
+	flags = CVAL(inbuf,1);
+	dgram->header.flags.node_type = (enum node_type)((flags>>2)&3);
+	if (flags & 1)
+		dgram->header.flags.more = True;
+	if (flags & 2)
+		dgram->header.flags.first = True;
+	dgram->header.dgm_id = RSVAL(inbuf,2);
+	putip((char *)&dgram->header.source_ip,inbuf+4);
+	dgram->header.source_port = RSVAL(inbuf,8);
+	dgram->header.dgm_length = RSVAL(inbuf,10);
+	dgram->header.packet_offset = RSVAL(inbuf,12);
+
+	offset = 14;
+
+	if (dgram->header.msg_type == 0x10 ||
+			dgram->header.msg_type == 0x11 ||
+			dgram->header.msg_type == 0x12) {
+		offset += parse_nmb_name(inbuf,offset,length,
+				&dgram->source_name);
+		offset += parse_nmb_name(inbuf,offset,length,
+				&dgram->dest_name);
+	}
+
+	if (offset >= length || (length-offset > sizeof(dgram->data)))
+		return(False);
+
+	dgram->datasize = length-offset;
+	memcpy(dgram->data,inbuf+offset,dgram->datasize);
+
+	/* Paranioa. Ensure the last 2 bytes in the dgram buffer are
+	   zero. This should be true anyway, just enforce it for
+	   paranioa sake. JRA. */
+	SMB_ASSERT(dgram->datasize <= (sizeof(dgram->data)-2));
+	memset(&dgram->data[sizeof(dgram->data)-2], '\0', 2);
+
+	return(True);
+}
+
+/*******************************************************************
+ Parse a nmb packet. Return False if the packet can't be parsed
+ or is invalid for some reason, True otherwise.
+******************************************************************/
+
+static bool parse_nmb(char *inbuf,int length,struct nmb_packet *nmb)
+{
+	int nm_flags,offset;
+
+	memset((char *)nmb,'\0',sizeof(*nmb));
+
+	if (length < 12)
+		return(False);
+
+	/* parse the header */
+	nmb->header.name_trn_id = RSVAL(inbuf,0);
+
+	DEBUG(10,("parse_nmb: packet id = %d\n", nmb->header.name_trn_id));
+
+	nmb->header.opcode = (CVAL(inbuf,2) >> 3) & 0xF;
+	nmb->header.response = ((CVAL(inbuf,2)>>7)&1)?True:False;
+	nm_flags = ((CVAL(inbuf,2) & 0x7) << 4) + (CVAL(inbuf,3)>>4);
+	nmb->header.nm_flags.bcast = (nm_flags&1)?True:False;
+	nmb->header.nm_flags.recursion_available = (nm_flags&8)?True:False;
+	nmb->header.nm_flags.recursion_desired = (nm_flags&0x10)?True:False;
+	nmb->header.nm_flags.trunc = (nm_flags&0x20)?True:False;
+	nmb->header.nm_flags.authoritative = (nm_flags&0x40)?True:False;
+	nmb->header.rcode = CVAL(inbuf,3) & 0xF;
+	nmb->header.qdcount = RSVAL(inbuf,4);
+	nmb->header.ancount = RSVAL(inbuf,6);
+	nmb->header.nscount = RSVAL(inbuf,8);
+	nmb->header.arcount = RSVAL(inbuf,10);
+
+	if (nmb->header.qdcount) {
+		offset = parse_nmb_name(inbuf,12,length,
+				&nmb->question.question_name);
+		if (!offset)
+			return(False);
+
+		if (length - (12+offset) < 4)
+			return(False);
+		nmb->question.question_type = RSVAL(inbuf,12+offset);
+		nmb->question.question_class = RSVAL(inbuf,12+offset+2);
+
+		offset += 12+4;
+	} else {
+		offset = 12;
+	}
+
+	/* and any resource records */
+	if (nmb->header.ancount &&
+			!parse_alloc_res_rec(inbuf,&offset,length,&nmb->answers,
+					nmb->header.ancount))
+		return(False);
+
+	if (nmb->header.nscount &&
+			!parse_alloc_res_rec(inbuf,&offset,length,&nmb->nsrecs,
+					nmb->header.nscount))
+		return(False);
+
+	if (nmb->header.arcount &&
+			!parse_alloc_res_rec(inbuf,&offset,length,
+				&nmb->additional, nmb->header.arcount))
+		return(False);
+
+	return(True);
+}
+
+/*******************************************************************
+ 'Copy constructor' for an nmb packet.
+******************************************************************/
+
+static struct packet_struct *copy_nmb_packet(struct packet_struct *packet)
+{
+	struct nmb_packet *nmb;
+	struct nmb_packet *copy_nmb;
+	struct packet_struct *pkt_copy;
+
+	if(( pkt_copy = SMB_MALLOC_P(struct packet_struct)) == NULL) {
+		DEBUG(0,("copy_nmb_packet: malloc fail.\n"));
+		return NULL;
+	}
+
+	/* Structure copy of entire thing. */
+
+	*pkt_copy = *packet;
+
+	/* Ensure this copy is not locked. */
+	pkt_copy->locked = False;
+	pkt_copy->recv_fd = -1;
+	pkt_copy->send_fd = -1;
+
+	/* Ensure this copy has no resource records. */
+	nmb = &packet->packet.nmb;
+	copy_nmb = &pkt_copy->packet.nmb;
+
+	copy_nmb->answers = NULL;
+	copy_nmb->nsrecs = NULL;
+	copy_nmb->additional = NULL;
+
+	/* Now copy any resource records. */
+
+	if (nmb->answers) {
+		if((copy_nmb->answers = SMB_MALLOC_ARRAY(
+				struct res_rec,nmb->header.ancount)) == NULL)
+			goto free_and_exit;
+		memcpy((char *)copy_nmb->answers, (char *)nmb->answers,
+				nmb->header.ancount * sizeof(struct res_rec));
+	}
+	if (nmb->nsrecs) {
+		if((copy_nmb->nsrecs = SMB_MALLOC_ARRAY(
+				struct res_rec, nmb->header.nscount)) == NULL)
+			goto free_and_exit;
+		memcpy((char *)copy_nmb->nsrecs, (char *)nmb->nsrecs,
+				nmb->header.nscount * sizeof(struct res_rec));
+	}
+	if (nmb->additional) {
+		if((copy_nmb->additional = SMB_MALLOC_ARRAY(
+				struct res_rec, nmb->header.arcount)) == NULL)
+			goto free_and_exit;
+		memcpy((char *)copy_nmb->additional, (char *)nmb->additional,
+				nmb->header.arcount * sizeof(struct res_rec));
+	}
+
+	return pkt_copy;
+
+ free_and_exit:
+
+	SAFE_FREE(copy_nmb->answers);
+	SAFE_FREE(copy_nmb->nsrecs);
+	SAFE_FREE(copy_nmb->additional);
+	SAFE_FREE(pkt_copy);
+
+	DEBUG(0,("copy_nmb_packet: malloc fail in resource records.\n"));
+	return NULL;
+}
+
+/*******************************************************************
+  'Copy constructor' for a dgram packet.
+******************************************************************/
+
+static struct packet_struct *copy_dgram_packet(struct packet_struct *packet)
+{
+	struct packet_struct *pkt_copy;
+
+	if(( pkt_copy = SMB_MALLOC_P(struct packet_struct)) == NULL) {
+		DEBUG(0,("copy_dgram_packet: malloc fail.\n"));
+		return NULL;
+	}
+
+	/* Structure copy of entire thing. */
+
+	*pkt_copy = *packet;
+
+	/* Ensure this copy is not locked. */
+	pkt_copy->locked = False;
+	pkt_copy->recv_fd = -1;
+	pkt_copy->send_fd = -1;
+
+	/* There are no additional pointers in a dgram packet,
+		we are finished. */
+	return pkt_copy;
+}
+
+/*******************************************************************
+ 'Copy constructor' for a generic packet.
+******************************************************************/
+
+struct packet_struct *copy_packet(struct packet_struct *packet)
+{
+	if(packet->packet_type == NMB_PACKET)
+		return copy_nmb_packet(packet);
+	else if (packet->packet_type == DGRAM_PACKET)
+		return copy_dgram_packet(packet);
+	return NULL;
+}
+
+/*******************************************************************
+ Free up any resources associated with an nmb packet.
+******************************************************************/
+
+static void free_nmb_packet(struct nmb_packet *nmb)
+{
+	SAFE_FREE(nmb->answers);
+	SAFE_FREE(nmb->nsrecs);
+	SAFE_FREE(nmb->additional);
+}
+
+/*******************************************************************
+ Free up any resources associated with a dgram packet.
+******************************************************************/
+
+static void free_dgram_packet(struct dgram_packet *nmb)
+{
+	/* We have nothing to do for a dgram packet. */
+}
+
+/*******************************************************************
+ Free up any resources associated with a packet.
+******************************************************************/
+
+void free_packet(struct packet_struct *packet)
+{
+	if (packet->locked)
+		return;
+	if (packet->packet_type == NMB_PACKET)
+		free_nmb_packet(&packet->packet.nmb);
+	else if (packet->packet_type == DGRAM_PACKET)
+		free_dgram_packet(&packet->packet.dgram);
+	ZERO_STRUCTPN(packet);
+	SAFE_FREE(packet);
+}
+
+/*******************************************************************
+ Parse a packet buffer into a packet structure.
+******************************************************************/
+
+struct packet_struct *parse_packet(char *buf,int length,
+				   enum packet_type packet_type,
+				   struct in_addr ip,
+				   int port)
+{
+	struct packet_struct *p;
+	bool ok=False;
+
+	p = SMB_MALLOC_P(struct packet_struct);
+	if (!p)
+		return(NULL);
+
+	ZERO_STRUCTP(p);	/* initialize for possible padding */
+
+	p->next = NULL;
+	p->prev = NULL;
+	p->ip = ip;
+	p->port = port;
+	p->locked = False;
+	p->timestamp = time(NULL);
+	p->packet_type = packet_type;
+
+	switch (packet_type) {
+	case NMB_PACKET:
+		ok = parse_nmb(buf,length,&p->packet.nmb);
+		break;
+
+	case DGRAM_PACKET:
+		ok = parse_dgram(buf,length,&p->packet.dgram);
+		break;
+	}
+
+	if (!ok) {
+		free_packet(p);
+		return NULL;
+	}
+
+	return p;
+}
+
+/*******************************************************************
+ Read a packet from a socket and parse it, returning a packet ready
+ to be used or put on the queue. This assumes a UDP socket.
+******************************************************************/
+
+struct packet_struct *read_packet(int fd,enum packet_type packet_type)
+{
+	struct packet_struct *packet;
+	struct sockaddr_storage sa;
+	struct sockaddr_in *si = (struct sockaddr_in *)&sa;
+	char buf[MAX_DGRAM_SIZE];
+	int length;
+
+	length = read_udp_v4_socket(fd,buf,sizeof(buf),&sa);
+	if (length < MIN_DGRAM_SIZE || sa.ss_family != AF_INET) {
+		return NULL;
+	}
+
+	packet = parse_packet(buf,
+			length,
+			packet_type,
+			si->sin_addr,
+			ntohs(si->sin_port));
+	if (!packet)
+		return NULL;
+
+	packet->recv_fd = fd;
+	packet->send_fd = -1;
+
+	DEBUG(5,("Received a packet of len %d from (%s) port %d\n",
+		 length, inet_ntoa(packet->ip), packet->port ) );
+
+	return(packet);
+}
+
+/*******************************************************************
+ Send a udp packet on a already open socket.
+******************************************************************/
+
+static bool send_udp(int fd,char *buf,int len,struct in_addr ip,int port)
+{
+	bool ret = False;
+	int i;
+	struct sockaddr_in sock_out;
+
+	/* set the address and port */
+	memset((char *)&sock_out,'\0',sizeof(sock_out));
+	putip((char *)&sock_out.sin_addr,(char *)&ip);
+	sock_out.sin_port = htons( port );
+	sock_out.sin_family = AF_INET;
+
+	DEBUG( 5, ( "Sending a packet of len %d to (%s) on port %d\n",
+			len, inet_ntoa(ip), port ) );
+
+	/*
+	 * Patch to fix asynch error notifications from Linux kernel.
+	 */
+
+	for (i = 0; i < 5; i++) {
+		ret = (sendto(fd,buf,len,0,(struct sockaddr *)&sock_out,
+					sizeof(sock_out)) >= 0);
+		if (ret || errno != ECONNREFUSED)
+			break;
+	}
+
+	if (!ret)
+		DEBUG(0,("Packet send failed to %s(%d) ERRNO=%s\n",
+			inet_ntoa(ip),port,strerror(errno)));
+
+	return(ret);
+}
+
+/*******************************************************************
+ Build a dgram packet ready for sending.
+ If buf == NULL this is a length calculation.
+******************************************************************/
+
+static int build_dgram(char *buf, size_t len, struct dgram_packet *dgram)
+{
+	unsigned char *ubuf = (unsigned char *)buf;
+	int offset=0;
+
+	/* put in the header */
+	if (buf) {
+		ubuf[0] = dgram->header.msg_type;
+		ubuf[1] = (((int)dgram->header.flags.node_type)<<2);
+		if (dgram->header.flags.more)
+			ubuf[1] |= 1;
+		if (dgram->header.flags.first)
+			ubuf[1] |= 2;
+		RSSVAL(ubuf,2,dgram->header.dgm_id);
+		putip(ubuf+4,(char *)&dgram->header.source_ip);
+		RSSVAL(ubuf,8,dgram->header.source_port);
+		RSSVAL(ubuf,12,dgram->header.packet_offset);
+	}
+
+	offset = 14;
+
+	if (dgram->header.msg_type == 0x10 ||
+			dgram->header.msg_type == 0x11 ||
+			dgram->header.msg_type == 0x12) {
+		offset += put_nmb_name((char *)ubuf,offset,&dgram->source_name);
+		offset += put_nmb_name((char *)ubuf,offset,&dgram->dest_name);
+	}
+
+	if (buf) {
+		memcpy(ubuf+offset,dgram->data,dgram->datasize);
+	}
+	offset += dgram->datasize;
+
+	/* automatically set the dgm_length
+	 * NOTE: RFC1002 says the dgm_length does *not*
+	 *       include the fourteen-byte header. crh
+	 */
+	dgram->header.dgm_length = (offset - 14);
+	if (buf) {
+		RSSVAL(ubuf,10,dgram->header.dgm_length);
+	}
+
+	return offset;
+}
+
+/*******************************************************************
+ Build a nmb name
+*******************************************************************/
+
+void make_nmb_name( struct nmb_name *n, const char *name, int type)
+{
+	fstring unix_name;
+	memset( (char *)n, '\0', sizeof(struct nmb_name) );
+	fstrcpy(unix_name, name);
+	strupper_m(unix_name);
+	push_ascii(n->name, unix_name, sizeof(n->name), STR_TERMINATE);
+	n->name_type = (unsigned int)type & 0xFF;
+	push_ascii(n->scope,  global_scope(), 64, STR_TERMINATE);
+}
+
+/*******************************************************************
+  Compare two nmb names
+******************************************************************/
+
+bool nmb_name_equal(struct nmb_name *n1, struct nmb_name *n2)
+{
+	return ((n1->name_type == n2->name_type) &&
+		strequal(n1->name ,n2->name ) &&
+		strequal(n1->scope,n2->scope));
+}
+
+/*******************************************************************
+ Build a nmb packet ready for sending.
+ If buf == NULL this is a length calculation.
+******************************************************************/
+
+static int build_nmb(char *buf, size_t len, struct nmb_packet *nmb)
+{
+	unsigned char *ubuf = (unsigned char *)buf;
+	int offset=0;
+
+	if (len && len < 12) {
+		return 0;
+	}
+
+	/* put in the header */
+	if (buf) {
+		RSSVAL(ubuf,offset,nmb->header.name_trn_id);
+		ubuf[offset+2] = (nmb->header.opcode & 0xF) << 3;
+		if (nmb->header.response)
+			ubuf[offset+2] |= (1<<7);
+		if (nmb->header.nm_flags.authoritative &&
+				nmb->header.response)
+			ubuf[offset+2] |= 0x4;
+		if (nmb->header.nm_flags.trunc)
+			ubuf[offset+2] |= 0x2;
+		if (nmb->header.nm_flags.recursion_desired)
+			ubuf[offset+2] |= 0x1;
+		if (nmb->header.nm_flags.recursion_available &&
+				nmb->header.response)
+			ubuf[offset+3] |= 0x80;
+		if (nmb->header.nm_flags.bcast)
+			ubuf[offset+3] |= 0x10;
+		ubuf[offset+3] |= (nmb->header.rcode & 0xF);
+
+		RSSVAL(ubuf,offset+4,nmb->header.qdcount);
+		RSSVAL(ubuf,offset+6,nmb->header.ancount);
+		RSSVAL(ubuf,offset+8,nmb->header.nscount);
+		RSSVAL(ubuf,offset+10,nmb->header.arcount);
+	}
+
+	offset += 12;
+	if (nmb->header.qdcount) {
+		/* XXXX this doesn't handle a qdcount of > 1 */
+		if (len) {
+			/* Length check. */
+			int extra = put_nmb_name(NULL,offset,
+					&nmb->question.question_name);
+			if (offset + extra > len) {
+				return 0;
+			}
+		}
+		offset += put_nmb_name((char *)ubuf,offset,
+				&nmb->question.question_name);
+		if (buf) {
+			RSSVAL(ubuf,offset,nmb->question.question_type);
+			RSSVAL(ubuf,offset+2,nmb->question.question_class);
+		}
+		offset += 4;
+	}
+
+	if (nmb->header.ancount) {
+		if (len) {
+			/* Length check. */
+			int extra = put_res_rec(NULL,offset,nmb->answers,
+					nmb->header.ancount);
+			if (offset + extra > len) {
+				return 0;
+			}
+		}
+		offset += put_res_rec((char *)ubuf,offset,nmb->answers,
+				nmb->header.ancount);
+	}
+
+	if (nmb->header.nscount) {
+		if (len) {
+			/* Length check. */
+			int extra = put_res_rec(NULL,offset,nmb->nsrecs,
+				nmb->header.nscount);
+			if (offset + extra > len) {
+				return 0;
+			}
+		}
+		offset += put_res_rec((char *)ubuf,offset,nmb->nsrecs,
+				nmb->header.nscount);
+	}
+
+	/*
+	 * The spec says we must put compressed name pointers
+	 * in the following outgoing packets :
+	 * NAME_REGISTRATION_REQUEST, NAME_REFRESH_REQUEST,
+	 * NAME_RELEASE_REQUEST.
+	 */
+
+	if((nmb->header.response == False) &&
+		((nmb->header.opcode == NMB_NAME_REG_OPCODE) ||
+		(nmb->header.opcode == NMB_NAME_RELEASE_OPCODE) ||
+		(nmb->header.opcode == NMB_NAME_REFRESH_OPCODE_8) ||
+		(nmb->header.opcode == NMB_NAME_REFRESH_OPCODE_9) ||
+		(nmb->header.opcode == NMB_NAME_MULTIHOMED_REG_OPCODE)) &&
+		(nmb->header.arcount == 1)) {
+
+		if (len) {
+			/* Length check. */
+			int extra = put_compressed_name_ptr(NULL,offset,
+					nmb->additional,12);
+			if (offset + extra > len) {
+				return 0;
+			}
+		}
+		offset += put_compressed_name_ptr(ubuf,offset,
+				nmb->additional,12);
+	} else if (nmb->header.arcount) {
+		if (len) {
+			/* Length check. */
+			int extra = put_res_rec(NULL,offset,nmb->additional,
+				nmb->header.arcount);
+			if (offset + extra > len) {
+				return 0;
+			}
+		}
+		offset += put_res_rec((char *)ubuf,offset,nmb->additional,
+			nmb->header.arcount);
+	}
+	return offset;
+}
+
+/*******************************************************************
+ Linearise a packet.
+******************************************************************/
+
+int build_packet(char *buf, size_t buflen, struct packet_struct *p)
+{
+	int len = 0;
+
+	switch (p->packet_type) {
+	case NMB_PACKET:
+		len = build_nmb(buf,buflen,&p->packet.nmb);
+		break;
+
+	case DGRAM_PACKET:
+		len = build_dgram(buf,buflen,&p->packet.dgram);
+		break;
+	}
+
+	return len;
+}
+
+/*******************************************************************
+ Send a packet_struct.
+******************************************************************/
+
+bool send_packet(struct packet_struct *p)
+{
+	char buf[1024];
+	int len=0;
+
+	memset(buf,'\0',sizeof(buf));
+
+	len = build_packet(buf, sizeof(buf), p);
+
+	if (!len)
+		return(False);
+
+	return(send_udp(p->send_fd,buf,len,p->ip,p->port));
+}
+
+/****************************************************************************
+ Receive a packet with timeout on a open UDP filedescriptor.
+ The timeout is in milliseconds
+***************************************************************************/
+
+struct packet_struct *receive_packet(int fd,enum packet_type type,int t)
+{
+	fd_set fds;
+	struct timeval timeout;
+	int ret;
+
+	FD_ZERO(&fds);
+	FD_SET(fd,&fds);
+	timeout.tv_sec = t/1000;
+	timeout.tv_usec = 1000*(t%1000);
+
+	if ((ret = sys_select_intr(fd+1,&fds,NULL,NULL,&timeout)) == -1) {
+		/* errno should be EBADF or EINVAL. */
+		DEBUG(0,("select returned -1, errno = %s (%d)\n",
+					strerror(errno), errno));
+		return NULL;
+	}
+
+	if (ret == 0) /* timeout */
+		return NULL;
+
+	if (FD_ISSET(fd,&fds))
+		return(read_packet(fd,type));
+
+	return(NULL);
+}
+
+/****************************************************************************
+ Receive a UDP/137 packet either via UDP or from the unexpected packet
+ queue. The packet must be a reply packet and have the specified trn_id.
+ The timeout is in milliseconds.
+***************************************************************************/
+
+struct packet_struct *receive_nmb_packet(int fd, int t, int trn_id)
+{
+	struct packet_struct *p;
+
+	p = receive_packet(fd, NMB_PACKET, t);
+
+	if (p && p->packet.nmb.header.response &&
+			p->packet.nmb.header.name_trn_id == trn_id) {
+		return p;
+	}
+	if (p)
+		free_packet(p);
+
+	/* try the unexpected packet queue */
+	return receive_unexpected(NMB_PACKET, trn_id, NULL);
+}
+
+/****************************************************************************
+ Receive a UDP/138 packet either via UDP or from the unexpected packet
+ queue. The packet must be a reply packet and have the specified mailslot name
+ The timeout is in milliseconds.
+***************************************************************************/
+
+struct packet_struct *receive_dgram_packet(int fd, int t,
+		const char *mailslot_name)
+{
+	struct packet_struct *p;
+
+	p = receive_packet(fd, DGRAM_PACKET, t);
+
+	if (p && match_mailslot_name(p, mailslot_name)) {
+		return p;
+	}
+	if (p)
+		free_packet(p);
+
+	/* try the unexpected packet queue */
+	return receive_unexpected(DGRAM_PACKET, 0, mailslot_name);
+}
+
+/****************************************************************************
+ See if a datagram has the right mailslot name.
+***************************************************************************/
+
+bool match_mailslot_name(struct packet_struct *p, const char *mailslot_name)
+{
+	struct dgram_packet *dgram = &p->packet.dgram;
+	char *buf;
+
+	buf = &dgram->data[0];
+	buf -= 4;
+
+	buf = smb_buf(buf);
+
+	if (memcmp(buf, mailslot_name, strlen(mailslot_name)+1) == 0) {
+		return True;
+	}
+
+	return False;
+}
+
+/****************************************************************************
+ Return the number of bits that match between two len character buffers
+***************************************************************************/
+
+int matching_len_bits(unsigned char *p1, unsigned char *p2, size_t len)
+{
+	size_t i, j;
+	int ret = 0;
+	for (i=0; i<len; i++) {
+		if (p1[i] != p2[i])
+			break;
+		ret += 8;
+	}
+
+	if (i==len)
+		return ret;
+
+	for (j=0; j<8; j++) {
+		if ((p1[i] & (1<<(7-j))) != (p2[i] & (1<<(7-j))))
+			break;
+		ret++;
+	}
+
+	return ret;
+}
+
+static unsigned char sort_ip[4];
+
+/****************************************************************************
+ Compare two query reply records.
+***************************************************************************/
+
+static int name_query_comp(unsigned char *p1, unsigned char *p2)
+{
+	return matching_len_bits(p2+2, sort_ip, 4) -
+		matching_len_bits(p1+2, sort_ip, 4);
+}
+
+/****************************************************************************
+ Sort a set of 6 byte name query response records so that the IPs that
+ have the most leading bits in common with the specified address come first.
+***************************************************************************/
+
+void sort_query_replies(char *data, int n, struct in_addr ip)
+{
+	if (n <= 1)
+		return;
+
+	putip(sort_ip, (char *)&ip);
+
+	qsort(data, n, 6, QSORT_CAST name_query_comp);
+}
+
+/****************************************************************************
+ Interpret the weird netbios "name" into a unix fstring. Return the name type.
+****************************************************************************/
+
+static int name_interpret(char *in, fstring name)
+{
+	int ret;
+	int len = (*in++) / 2;
+	fstring out_string;
+	char *out = out_string;
+
+	*out=0;
+
+	if (len > 30 || len<1)
+		return(0);
+
+	while (len--) {
+		if (in[0] < 'A' || in[0] > 'P' || in[1] < 'A' || in[1] > 'P') {
+			*out = 0;
+			return(0);
+		}
+		*out = ((in[0]-'A')<<4) + (in[1]-'A');
+		in += 2;
+		out++;
+	}
+	ret = out[-1];
+	out[-1] = 0;
+
+#ifdef NETBIOS_SCOPE
+	/* Handle any scope names */
+	while(*in) {
+		*out++ = '.'; /* Scope names are separated by periods */
+		len = *(unsigned char *)in++;
+		StrnCpy(out, in, len);
+		out += len;
+		*out=0;
+		in += len;
+	}
+#endif
+	pull_ascii_fstring(name, out_string);
+
+	return(ret);
+}
+
+/****************************************************************************
+ Mangle a name into netbios format.
+ Note:  <Out> must be (33 + strlen(scope) + 2) bytes long, at minimum.
+****************************************************************************/
+
+char *name_mangle(TALLOC_CTX *mem_ctx, char *In, char name_type)
+{
+	int   i;
+	int   len;
+	nstring buf;
+	char *result;
+	char *p;
+
+	result = talloc_array(mem_ctx, char, 33 + strlen(global_scope()) + 2);
+	if (result == NULL) {
+		return NULL;
+	}
+	p = result;
+
+	/* Safely copy the input string, In, into buf[]. */
+	if (strcmp(In,"*") == 0)
+		put_name(buf, "*", '\0', 0x00);
+	else {
+		/* We use an fstring here as mb dos names can expend x3 when
+		   going to utf8. */
+		fstring buf_unix;
+		nstring buf_dos;
+
+		pull_ascii_fstring(buf_unix, In);
+		strupper_m(buf_unix);
+
+		push_ascii_nstring(buf_dos, buf_unix);
+		put_name(buf, buf_dos, ' ', name_type);
+	}
+
+	/* Place the length of the first field into the output buffer. */
+	p[0] = 32;
+	p++;
+
+	/* Now convert the name to the rfc1001/1002 format. */
+	for( i = 0; i < MAX_NETBIOSNAME_LEN; i++ ) {
+		p[i*2]     = ( (buf[i] >> 4) & 0x000F ) + 'A';
+		p[(i*2)+1] = (buf[i] & 0x000F) + 'A';
+	}
+	p += 32;
+	p[0] = '\0';
+
+	/* Add the scope string. */
+	for( i = 0, len = 0; *(global_scope()) != '\0'; i++, len++ ) {
+		switch( (global_scope())[i] ) {
+			case '\0':
+				p[0] = len;
+				if( len > 0 )
+					p[len+1] = 0;
+				return result;
+			case '.':
+				p[0] = len;
+				p   += (len + 1);
+				len  = -1;
+				break;
+			default:
+				p[len+1] = (global_scope())[i];
+				break;
+		}
+	}
+
+	return result;
+}
+
+/****************************************************************************
+ Find a pointer to a netbios name.
+****************************************************************************/
+
+static char *name_ptr(char *buf,int ofs)
+{
+	unsigned char c = *(unsigned char *)(buf+ofs);
+
+	if ((c & 0xC0) == 0xC0) {
+		uint16 l = RSVAL(buf, ofs) & 0x3FFF;
+		DEBUG(5,("name ptr to pos %d from %d is %s\n",l,ofs,buf+l));
+		return(buf + l);
+	} else {
+		return(buf+ofs);
+	}
+}
+
+/****************************************************************************
+ Extract a netbios name from a buf (into a unix string) return name type.
+****************************************************************************/
+
+int name_extract(char *buf,int ofs, fstring name)
+{
+	char *p = name_ptr(buf,ofs);
+	int d = PTR_DIFF(p,buf+ofs);
+
+	name[0] = '\0';
+	if (d < -50 || d > 50)
+		return(0);
+	return(name_interpret(p,name));
+}
+
+/****************************************************************************
+ Return the total storage length of a mangled name.
+****************************************************************************/
+
+int name_len(char *s1)
+{
+	/* NOTE: this argument _must_ be unsigned */
+	unsigned char *s = (unsigned char *)s1;
+	int len;
+
+	/* If the two high bits of the byte are set, return 2. */
+	if (0xC0 == (*s & 0xC0))
+		return(2);
+
+	/* Add up the length bytes. */
+	for (len = 1; (*s); s += (*s) + 1) {
+		len += *s + 1;
+		SMB_ASSERT(len < 80);
+	}
+
+	return(len);
+}

=== added directory '.pc/security-CVE-2011-0719.patch/source3/nmbd'
=== added file '.pc/security-CVE-2011-0719.patch/source3/nmbd/nmbd_packets.c'
--- .pc/security-CVE-2011-0719.patch/source3/nmbd/nmbd_packets.c	1970-01-01 00:00:00 +0000
+++ .pc/security-CVE-2011-0719.patch/source3/nmbd/nmbd_packets.c	2011-03-02 20:48:44 +0000
@@ -0,0 +1,2119 @@
+/* 
+   Unix SMB/CIFS implementation.
+   NBT netbios routines and daemon - version 2
+   Copyright (C) Andrew Tridgell 1994-1998
+   Copyright (C) Luke Kenneth Casson Leighton 1994-1998
+   Copyright (C) Jeremy Allison 1994-2003
+   
+   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 3 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, see <http://www.gnu.org/licenses/>.
+   
+*/
+
+#include "includes.h"
+
+extern int ClientNMB;
+extern int ClientDGRAM;
+extern int global_nmb_port;
+
+extern int num_response_packets;
+
+bool rescan_listen_set = False;
+
+
+/*******************************************************************
+  The global packet linked-list. Incoming entries are 
+  added to the end of this list. It is supposed to remain fairly 
+  short so we won't bother with an end pointer.
+******************************************************************/
+
+static struct packet_struct *packet_queue = NULL;
+
+/***************************************************************************
+Utility function to find the specific fd to send a packet out on.
+**************************************************************************/
+
+static int find_subnet_fd_for_address( struct in_addr local_ip )
+{
+	struct subnet_record *subrec;
+
+	for( subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec))
+		if(ip_equal_v4(local_ip, subrec->myip))
+			return subrec->nmb_sock;
+
+	return ClientNMB;
+}
+
+/***************************************************************************
+Utility function to find the specific fd to send a mailslot packet out on.
+**************************************************************************/
+
+static int find_subnet_mailslot_fd_for_address( struct in_addr local_ip )
+{
+	struct subnet_record *subrec;
+
+	for( subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec))
+		if(ip_equal_v4(local_ip, subrec->myip))
+			return subrec->dgram_sock;
+
+	return ClientDGRAM;
+}
+
+/***************************************************************************
+Get/Set problematic nb_flags as network byte order 16 bit int.
+**************************************************************************/
+
+uint16 get_nb_flags(char *buf)
+{
+	return ((((uint16)*buf)&0xFFFF) & NB_FLGMSK);
+}
+
+void set_nb_flags(char *buf, uint16 nb_flags)
+{
+	*buf++ = ((nb_flags & NB_FLGMSK) & 0xFF);
+	*buf = '\0';
+}
+
+/***************************************************************************
+Dumps out the browse packet data.
+**************************************************************************/
+
+static void debug_browse_data(char *outbuf, int len)
+{
+	int i,j;
+
+	DEBUG( 4, ( "debug_browse_data():\n" ) );
+	for (i = 0; i < len; i+= 16) {
+		DEBUGADD( 4, ( "%3x char ", i ) );
+
+		for (j = 0; j < 16; j++) {
+			unsigned char x;
+			if (i+j >= len)
+				break;
+
+			x = outbuf[i+j];
+			if (x < 32 || x > 127) 
+				x = '.';
+	    
+			DEBUGADD( 4, ( "%c", x ) );
+		}
+
+		DEBUGADD( 4, ( "%*s hex", 16-j, "" ) );
+
+		for (j = 0; j < 16; j++) {
+			if (i+j >= len) 
+				break;
+			DEBUGADD( 4, ( " %02x", (unsigned char)outbuf[i+j] ) );
+		}
+
+		DEBUGADD( 4, ("\n") );
+	}
+}
+
+/***************************************************************************
+  Generates the unique transaction identifier
+**************************************************************************/
+
+static uint16 name_trn_id=0;
+
+static uint16 generate_name_trn_id(void)
+{
+	if (!name_trn_id) {
+		name_trn_id = ((unsigned)time(NULL)%(unsigned)0x7FFF) + ((unsigned)sys_getpid()%(unsigned)100);
+	}
+	name_trn_id = (name_trn_id+1) % (unsigned)0x7FFF;
+	return name_trn_id;
+}
+
+/***************************************************************************
+ Either loops back or sends out a completed NetBIOS packet.
+**************************************************************************/
+
+static bool send_netbios_packet(struct packet_struct *p)
+{
+	bool loopback_this_packet = False;
+
+	/* Check if we are sending to or from ourselves as a WINS server. */
+	if(ismyip_v4(p->ip) && (p->port == global_nmb_port))
+		loopback_this_packet = True;
+
+	if(loopback_this_packet) {
+		struct packet_struct *lo_packet = NULL;
+		DEBUG(5,("send_netbios_packet: sending packet to ourselves.\n"));
+		if((lo_packet = copy_packet(p)) == NULL)
+			return False;
+		queue_packet(lo_packet);
+	} else if (!send_packet(p)) {
+		DEBUG(0,("send_netbios_packet: send_packet() to IP %s port %d failed\n",
+			inet_ntoa(p->ip),p->port));
+		return False;
+	}
+  
+	return True;
+} 
+
+/***************************************************************************
+ Sets up the common elements of an outgoing NetBIOS packet.
+
+ Note: do not attempt to rationalise whether rec_des should be set or not
+ in a particular situation. Just follow rfc_1002 or look at examples from WinXX.
+ It does NOT follow the rule that requests to the wins server always have
+ rec_des true. See for example name releases and refreshes
+**************************************************************************/
+
+static struct packet_struct *create_and_init_netbios_packet(struct nmb_name *nmbname,
+                                                            bool bcast, bool rec_des,
+                                                            struct in_addr to_ip)
+{
+	struct packet_struct *packet = NULL;
+	struct nmb_packet *nmb = NULL;
+
+	/* Allocate the packet_struct we will return. */
+	if((packet = SMB_MALLOC_P(struct packet_struct)) == NULL) {
+		DEBUG(0,("create_and_init_netbios_packet: malloc fail (1) for packet struct.\n"));
+		return NULL;
+	}
+    
+	memset((char *)packet,'\0',sizeof(*packet));
+
+	nmb = &packet->packet.nmb;
+
+	nmb->header.name_trn_id = generate_name_trn_id();
+	nmb->header.response = False;
+	nmb->header.nm_flags.recursion_desired = rec_des;
+	nmb->header.nm_flags.recursion_available = False;
+	nmb->header.nm_flags.trunc = False;
+	nmb->header.nm_flags.authoritative = False;
+	nmb->header.nm_flags.bcast = bcast;
+  
+	nmb->header.rcode = 0;
+	nmb->header.qdcount = 1;
+	nmb->header.ancount = 0;
+	nmb->header.nscount = 0;
+
+	nmb->question.question_name = *nmbname;
+	nmb->question.question_type = QUESTION_TYPE_NB_QUERY;
+	nmb->question.question_class = QUESTION_CLASS_IN;
+
+	packet->ip = to_ip;
+	packet->port = NMB_PORT;
+	packet->recv_fd = -1;
+	packet->send_fd = ClientNMB;
+	packet->timestamp = time(NULL);
+	packet->packet_type = NMB_PACKET;
+	packet->locked = False;
+  
+	return packet; /* Caller must free. */
+}
+
+/***************************************************************************
+ Sets up the common elements of register, refresh or release packet.
+**************************************************************************/
+
+static bool create_and_init_additional_record(struct packet_struct *packet,
+                                                     uint16 nb_flags,
+                                                     const struct in_addr *register_ip)
+{
+	struct nmb_packet *nmb = &packet->packet.nmb;
+
+	if((nmb->additional = SMB_MALLOC_P(struct res_rec)) == NULL) {
+		DEBUG(0,("create_and_init_additional_record: malloc fail for additional record.\n"));
+		return False;
+	}
+
+	memset((char *)nmb->additional,'\0',sizeof(struct res_rec));
+
+	nmb->additional->rr_name  = nmb->question.question_name;
+	nmb->additional->rr_type  = RR_TYPE_NB;
+	nmb->additional->rr_class = RR_CLASS_IN;
+	
+	/* See RFC 1002, sections 5.1.1.1, 5.1.1.2 and 5.1.1.3 */
+	if (nmb->header.nm_flags.bcast)
+		nmb->additional->ttl = PERMANENT_TTL;
+	else
+		nmb->additional->ttl = lp_max_ttl();
+	
+	nmb->additional->rdlength = 6;
+	
+	set_nb_flags(nmb->additional->rdata,nb_flags);
+	
+	/* Set the address for the name we are registering. */
+	putip(&nmb->additional->rdata[2], register_ip);
+	
+	/* 
+	   it turns out that Jeremys code was correct, we are supposed
+	   to send registrations from the IP we are registering. The
+	   trick is what to do on timeouts! When we send on a
+	   non-routable IP then the reply will timeout, and we should
+	   treat this as success, not failure. That means we go into
+	   our standard refresh cycle for that name which copes nicely
+	   with disconnected networks.
+	*/
+	packet->recv_fd = -1;
+	packet->send_fd = find_subnet_fd_for_address(*register_ip);
+
+	return True;
+}
+
+/***************************************************************************
+ Sends out a name query.
+**************************************************************************/
+
+static bool initiate_name_query_packet( struct packet_struct *packet)
+{
+	struct nmb_packet *nmb = NULL;
+
+	nmb = &packet->packet.nmb;
+
+	nmb->header.opcode = NMB_NAME_QUERY_OPCODE;
+	nmb->header.arcount = 0;
+
+	nmb->header.nm_flags.recursion_desired = True;
+
+	DEBUG(4,("initiate_name_query_packet: sending query for name %s (bcast=%s) to IP %s\n",
+		nmb_namestr(&nmb->question.question_name), 
+		BOOLSTR(nmb->header.nm_flags.bcast), inet_ntoa(packet->ip)));
+
+	return send_netbios_packet( packet );
+}
+
+/***************************************************************************
+ Sends out a name query - from a WINS server. 
+**************************************************************************/
+
+static bool initiate_name_query_packet_from_wins_server( struct packet_struct *packet)
+{   
+	struct nmb_packet *nmb = NULL;
+  
+	nmb = &packet->packet.nmb;
+
+	nmb->header.opcode = NMB_NAME_QUERY_OPCODE;
+	nmb->header.arcount = 0;
+    
+	nmb->header.nm_flags.recursion_desired = False;
+  
+	DEBUG(4,("initiate_name_query_packet_from_wins_server: sending query for name %s (bcast=%s) to IP %s\n",
+		nmb_namestr(&nmb->question.question_name),
+		BOOLSTR(nmb->header.nm_flags.bcast), inet_ntoa(packet->ip)));
+    
+	return send_netbios_packet( packet );
+} 
+
+/***************************************************************************
+ Sends out a name register.
+**************************************************************************/
+
+static bool initiate_name_register_packet( struct packet_struct *packet,
+                                    uint16 nb_flags, const struct in_addr *register_ip)
+{
+	struct nmb_packet *nmb = &packet->packet.nmb;
+
+	nmb->header.opcode = NMB_NAME_REG_OPCODE;
+	nmb->header.arcount = 1;
+
+	nmb->header.nm_flags.recursion_desired = True;
+
+	if(create_and_init_additional_record(packet, nb_flags, register_ip) == False)
+		return False;
+
+	DEBUG(4,("initiate_name_register_packet: sending registration for name %s (bcast=%s) to IP %s\n",
+		nmb_namestr(&nmb->additional->rr_name),
+		BOOLSTR(nmb->header.nm_flags.bcast), inet_ntoa(packet->ip)));
+
+	return send_netbios_packet( packet );
+}
+
+/***************************************************************************
+ Sends out a multihomed name register.
+**************************************************************************/
+
+static bool initiate_multihomed_name_register_packet(struct packet_struct *packet,
+						     uint16 nb_flags, struct in_addr *register_ip)
+{
+	struct nmb_packet *nmb = &packet->packet.nmb;
+	fstring second_ip_buf;
+
+	fstrcpy(second_ip_buf, inet_ntoa(packet->ip));
+
+	nmb->header.opcode = NMB_NAME_MULTIHOMED_REG_OPCODE;
+	nmb->header.arcount = 1;
+
+	nmb->header.nm_flags.recursion_desired = True;
+	
+	if(create_and_init_additional_record(packet, nb_flags, register_ip) == False)
+		return False;
+	
+	DEBUG(4,("initiate_multihomed_name_register_packet: sending registration \
+for name %s IP %s (bcast=%s) to IP %s\n",
+		 nmb_namestr(&nmb->additional->rr_name), inet_ntoa(*register_ip),
+		 BOOLSTR(nmb->header.nm_flags.bcast), second_ip_buf ));
+
+	return send_netbios_packet( packet );
+} 
+
+/***************************************************************************
+ Sends out a name refresh.
+**************************************************************************/
+
+static bool initiate_name_refresh_packet( struct packet_struct *packet,
+                                   uint16 nb_flags, struct in_addr *refresh_ip)
+{
+	struct nmb_packet *nmb = &packet->packet.nmb;
+
+	nmb->header.opcode = NMB_NAME_REFRESH_OPCODE_8;
+	nmb->header.arcount = 1;
+
+	nmb->header.nm_flags.recursion_desired = False;
+
+	if(create_and_init_additional_record(packet, nb_flags, refresh_ip) == False)
+		return False;
+
+	DEBUG(4,("initiate_name_refresh_packet: sending refresh for name %s (bcast=%s) to IP %s\n",
+		nmb_namestr(&nmb->additional->rr_name),
+		BOOLSTR(nmb->header.nm_flags.bcast), inet_ntoa(packet->ip)));
+
+	return send_netbios_packet( packet );
+} 
+
+/***************************************************************************
+ Sends out a name release.
+**************************************************************************/
+
+static bool initiate_name_release_packet( struct packet_struct *packet,
+                                   uint16 nb_flags, struct in_addr *release_ip)
+{
+	struct nmb_packet *nmb = &packet->packet.nmb;
+
+	nmb->header.opcode = NMB_NAME_RELEASE_OPCODE;
+	nmb->header.arcount = 1;
+
+	nmb->header.nm_flags.recursion_desired = False;
+
+	if(create_and_init_additional_record(packet, nb_flags, release_ip) == False)
+		return False;
+
+	DEBUG(4,("initiate_name_release_packet: sending release for name %s (bcast=%s) to IP %s\n",
+		nmb_namestr(&nmb->additional->rr_name),
+		BOOLSTR(nmb->header.nm_flags.bcast), inet_ntoa(packet->ip)));
+
+	return send_netbios_packet( packet );
+} 
+
+/***************************************************************************
+ Sends out a node status.
+**************************************************************************/
+
+static bool initiate_node_status_packet( struct packet_struct *packet )
+{
+	struct nmb_packet *nmb = &packet->packet.nmb;
+
+	nmb->header.opcode = NMB_NAME_QUERY_OPCODE;
+	nmb->header.arcount = 0;
+
+	nmb->header.nm_flags.recursion_desired = False;
+
+	nmb->question.question_type = QUESTION_TYPE_NB_STATUS;
+
+	DEBUG(4,("initiate_node_status_packet: sending node status request for name %s to IP %s\n",
+		nmb_namestr(&nmb->question.question_name),
+		inet_ntoa(packet->ip)));
+
+	return send_netbios_packet( packet );
+}
+
+/****************************************************************************
+  Simplification functions for queuing standard packets.
+  These should be the only publicly callable functions for sending
+  out packets.
+****************************************************************************/
+
+/****************************************************************************
+ Assertion - we should never be sending nmbd packets on the remote
+ broadcast subnet.
+****************************************************************************/
+
+static bool assert_check_subnet(struct subnet_record *subrec)
+{
+	if( subrec == remote_broadcast_subnet) {
+		DEBUG(0,("assert_check_subnet: Attempt to send packet on remote broadcast subnet. \
+This is a bug.\n"));
+		return True;
+	}
+	return False;
+}
+
+/****************************************************************************
+ Queue a register name packet to the broadcast address of a subnet.
+****************************************************************************/
+
+struct response_record *queue_register_name( struct subnet_record *subrec,
+                          response_function resp_fn,
+                          timeout_response_function timeout_fn,
+                          register_name_success_function success_fn,
+                          register_name_fail_function fail_fn,
+                          struct userdata_struct *userdata,
+                          struct nmb_name *nmbname,
+                          uint16 nb_flags)
+{
+	struct packet_struct *p;
+	struct response_record *rrec;
+	struct sockaddr_storage ss;
+	const struct sockaddr_storage *pss = NULL;
+	if(assert_check_subnet(subrec))
+		return NULL;
+
+	/* note that all name registration requests have RD set (rfc1002 - section 4.2.2 */
+	if ((p = create_and_init_netbios_packet(nmbname, (subrec != unicast_subnet), True,
+				subrec->bcast_ip)) == NULL)
+		return NULL;
+
+	in_addr_to_sockaddr_storage(&ss, subrec->bcast_ip);
+	pss = iface_ip((struct sockaddr *)&ss);
+	if (!pss || pss->ss_family != AF_INET) {
+		p->locked = False;
+		free_packet(p);
+		return NULL;
+	}
+
+	if(initiate_name_register_packet(p, nb_flags,
+			&((const struct sockaddr_in *)pss)->sin_addr) == False) {
+		p->locked = False;
+		free_packet(p);
+		return NULL;
+	}
+
+	if((rrec = make_response_record(subrec,        /* subnet record. */
+				p,                     /* packet we sent. */
+				resp_fn,               /* function to call on response. */
+				timeout_fn,            /* function to call on timeout. */
+				(success_function)success_fn,            /* function to call on operation success. */
+				(fail_function)fail_fn,               /* function to call on operation fail. */
+				userdata)) == NULL)  {
+		p->locked = False;
+		free_packet(p);
+		return NULL;
+	}
+
+	return rrec;
+}
+
+/****************************************************************************
+ Queue a refresh name packet to the broadcast address of a subnet.
+****************************************************************************/
+
+void queue_wins_refresh(struct nmb_name *nmbname,
+			response_function resp_fn,
+			timeout_response_function timeout_fn,
+			uint16 nb_flags,
+			struct in_addr refresh_ip,
+			const char *tag)
+{
+	struct packet_struct *p;
+	struct response_record *rrec;
+	struct in_addr wins_ip;
+	struct userdata_struct *userdata;
+	fstring ip_str;
+
+	wins_ip = wins_srv_ip_tag(tag, refresh_ip);
+
+	if ((p = create_and_init_netbios_packet(nmbname, False, False, wins_ip)) == NULL) {
+		return;
+	}
+
+	if (!initiate_name_refresh_packet(p, nb_flags, &refresh_ip)) {
+		p->locked = False;
+		free_packet(p);
+		return;
+	}
+
+	fstrcpy(ip_str, inet_ntoa(refresh_ip));
+
+	DEBUG(6,("Refreshing name %s IP %s with WINS server %s using tag '%s'\n",
+		 nmb_namestr(nmbname), ip_str, inet_ntoa(wins_ip), tag));
+
+	userdata = (struct userdata_struct *)SMB_MALLOC(sizeof(*userdata) + strlen(tag) + 1);
+	if (!userdata) {
+		p->locked = False;
+		free_packet(p);
+		DEBUG(0,("Failed to allocate userdata structure!\n"));
+		return;
+	}
+	ZERO_STRUCTP(userdata);
+	userdata->userdata_len = strlen(tag) + 1;
+	strlcpy(userdata->data, tag, userdata->userdata_len);	
+
+	if ((rrec = make_response_record(unicast_subnet,
+					 p,
+					 resp_fn, timeout_fn,
+					 NULL,
+					 NULL,
+					 userdata)) == NULL) {
+		p->locked = False;
+		free_packet(p);
+		return;
+	}
+
+	free(userdata);
+
+	/* we don't want to repeat refresh packets */
+	rrec->repeat_count = 0;
+}
+
+
+/****************************************************************************
+ Queue a multihomed register name packet to a given WINS server IP
+****************************************************************************/
+
+struct response_record *queue_register_multihomed_name( struct subnet_record *subrec,
+							response_function resp_fn,
+							timeout_response_function timeout_fn,
+							register_name_success_function success_fn,
+							register_name_fail_function fail_fn,
+							struct userdata_struct *userdata,
+							struct nmb_name *nmbname,
+							uint16 nb_flags,
+							struct in_addr register_ip,
+							struct in_addr wins_ip)
+{
+	struct packet_struct *p;
+	struct response_record *rrec;
+	bool ret;
+	
+	/* Sanity check. */
+	if(subrec != unicast_subnet) {
+		DEBUG(0,("queue_register_multihomed_name: should only be done on \
+unicast subnet. subnet is %s\n.", subrec->subnet_name ));
+		return NULL;
+	}
+
+	if(assert_check_subnet(subrec))
+		return NULL;
+     
+	if ((p = create_and_init_netbios_packet(nmbname, False, True, wins_ip)) == NULL)
+		return NULL;
+
+	if (nb_flags & NB_GROUP)
+		ret = initiate_name_register_packet( p, nb_flags, &register_ip);
+	else
+		ret = initiate_multihomed_name_register_packet(p, nb_flags, &register_ip);
+
+	if (ret == False) {  
+		p->locked = False;
+		free_packet(p);
+		return NULL;
+	}  
+  
+	if ((rrec = make_response_record(subrec,    /* subnet record. */
+					 p,                     /* packet we sent. */
+					 resp_fn,               /* function to call on response. */
+					 timeout_fn,            /* function to call on timeout. */
+					 (success_function)success_fn, /* function to call on operation success. */
+					 (fail_function)fail_fn,       /* function to call on operation fail. */
+					 userdata)) == NULL) {  
+		p->locked = False;
+		free_packet(p);
+		return NULL;
+	}  
+	
+	return rrec;
+}
+
+/****************************************************************************
+ Queue a release name packet to the broadcast address of a subnet.
+****************************************************************************/
+
+struct response_record *queue_release_name( struct subnet_record *subrec,
+					    response_function resp_fn,
+					    timeout_response_function timeout_fn,
+					    release_name_success_function success_fn,
+					    release_name_fail_function fail_fn,
+					    struct userdata_struct *userdata,
+					    struct nmb_name *nmbname,
+					    uint16 nb_flags,
+					    struct in_addr release_ip,
+					    struct in_addr dest_ip)
+{
+	struct packet_struct *p;
+	struct response_record *rrec;
+
+	if(assert_check_subnet(subrec))
+		return NULL;
+
+	if ((p = create_and_init_netbios_packet(nmbname, (subrec != unicast_subnet), False, dest_ip)) == NULL)
+		return NULL;
+
+	if(initiate_name_release_packet( p, nb_flags, &release_ip) == False) {
+		p->locked = False;
+		free_packet(p);
+		return NULL;
+	}
+
+	if((rrec = make_response_record(subrec,                /* subnet record. */
+					p,                     /* packet we sent. */
+					resp_fn,               /* function to call on response. */
+					timeout_fn,            /* function to call on timeout. */
+					(success_function)success_fn,            /* function to call on operation success. */
+					(fail_function)fail_fn,               /* function to call on operation fail. */
+					userdata)) == NULL)  {
+		p->locked = False;
+		free_packet(p);
+		return NULL;
+	}
+
+	/*
+	 * For a broadcast release packet, only send once.
+	 * This will cause us to remove the name asap. JRA.
+	 */
+
+	if (subrec != unicast_subnet) {
+		rrec->repeat_count = 0;
+		rrec->repeat_time = 0;
+	}
+
+	return rrec;
+}
+
+/****************************************************************************
+ Queue a query name packet to the broadcast address of a subnet.
+****************************************************************************/
+ 
+struct response_record *queue_query_name( struct subnet_record *subrec,
+                          response_function resp_fn,
+                          timeout_response_function timeout_fn,
+                          query_name_success_function success_fn,
+                          query_name_fail_function fail_fn,
+                          struct userdata_struct *userdata,
+                          struct nmb_name *nmbname)
+{
+	struct packet_struct *p;
+	struct response_record *rrec;
+	struct in_addr to_ip;
+
+	if(assert_check_subnet(subrec))
+		return NULL;
+
+	to_ip = subrec->bcast_ip;
+  
+	/* queries to the WINS server turn up here as queries to IP 0.0.0.0 
+			These need to be handled a bit differently */
+	if (subrec->type == UNICAST_SUBNET && is_zero_ip_v4(to_ip)) {
+		/* What we really need to do is loop over each of our wins
+		 * servers and wins server tags here, but that just doesn't
+		 * fit our architecture at the moment (userdata may already
+		 * be used when we get here). For now we just query the first
+		 * active wins server on the first tag.
+		 */ 
+		char **tags = wins_srv_tags();
+		if (!tags) {
+			return NULL;
+		}
+		to_ip = wins_srv_ip_tag(tags[0], to_ip);
+		wins_srv_tags_free(tags);
+	}
+
+	if(( p = create_and_init_netbios_packet(nmbname, 
+					(subrec != unicast_subnet), 
+					(subrec == unicast_subnet), 
+					to_ip)) == NULL)
+		return NULL;
+
+	if(lp_bind_interfaces_only()) {
+		int i;
+
+		DEBUG(10,("queue_query_name: bind_interfaces_only is set, looking for suitable source IP\n"));
+		for(i = 0; i < iface_count(); i++) {
+			const struct in_addr *ifip = iface_n_ip_v4(i);
+
+			if (ifip == NULL) {
+				DEBUG(0,("queue_query_name: interface %d has NULL IP address !\n", i));
+				continue;
+			}
+
+			if (is_loopback_ip_v4(*ifip)) {
+				DEBUG(5,("queue_query_name: ignoring loopback interface (%d)\n", i));
+				continue;
+			}
+
+			DEBUG(10,("queue_query_name: using source IP %s\n",inet_ntoa(*ifip)));
+				p->send_fd = find_subnet_fd_for_address( *ifip );
+				break;
+		}
+	}
+
+	if(initiate_name_query_packet( p ) == False) {
+		p->locked = False;
+		free_packet(p);
+		return NULL;
+	}
+
+	if((rrec = make_response_record(subrec,                /* subnet record. */
+					p,                     /* packet we sent. */
+					resp_fn,               /* function to call on response. */
+					timeout_fn,            /* function to call on timeout. */
+					(success_function)success_fn,            /* function to call on operation success. */
+					(fail_function)fail_fn,               /* function to call on operation fail. */
+					userdata)) == NULL) {
+		p->locked = False;
+		free_packet(p);
+		return NULL;
+	}
+
+	return rrec;
+}
+
+/****************************************************************************
+ Queue a query name packet to a given address from the WINS subnet.
+****************************************************************************/
+
+struct response_record *queue_query_name_from_wins_server( struct in_addr to_ip,
+                          response_function resp_fn,
+                          timeout_response_function timeout_fn,
+                          query_name_success_function success_fn,
+                          query_name_fail_function fail_fn,
+                          struct userdata_struct *userdata,
+                          struct nmb_name *nmbname)
+{
+	struct packet_struct *p;
+	struct response_record *rrec;
+
+	if ((p = create_and_init_netbios_packet(nmbname, False, False, to_ip)) == NULL)
+		return NULL;
+
+	if(initiate_name_query_packet_from_wins_server( p ) == False) {
+		p->locked = False;
+		free_packet(p);
+		return NULL;
+	}
+
+	if((rrec = make_response_record(wins_server_subnet,            /* subnet record. */
+						p,                     /* packet we sent. */
+						resp_fn,               /* function to call on response. */
+						timeout_fn,            /* function to call on timeout. */
+						(success_function)success_fn,            /* function to call on operation success. */
+						(fail_function)fail_fn,               /* function to call on operation fail. */
+						userdata)) == NULL) {
+		p->locked = False;
+		free_packet(p);
+		return NULL;
+	}
+
+	return rrec;
+}
+
+/****************************************************************************
+ Queue a node status packet to a given name and address.
+****************************************************************************/
+
+struct response_record *queue_node_status( struct subnet_record *subrec,
+                          response_function resp_fn,
+                          timeout_response_function timeout_fn,
+                          node_status_success_function success_fn,
+                          node_status_fail_function fail_fn,
+                          struct userdata_struct *userdata,
+                          struct nmb_name *nmbname,
+                          struct in_addr send_ip)
+{
+	struct packet_struct *p;
+	struct response_record *rrec;
+
+	/* Sanity check. */
+	if(subrec != unicast_subnet) {
+		DEBUG(0,("queue_register_multihomed_name: should only be done on \
+unicast subnet. subnet is %s\n.", subrec->subnet_name ));
+		return NULL;
+	}
+
+	if(assert_check_subnet(subrec))
+		return NULL;
+
+	if(( p = create_and_init_netbios_packet(nmbname, False, False, send_ip)) == NULL)
+		return NULL;
+
+	if(initiate_node_status_packet(p) == False) {
+		p->locked = False;
+		free_packet(p);
+		return NULL;
+	}
+
+	if((rrec = make_response_record(subrec,           /* subnet record. */
+					p,                     /* packet we sent. */
+					resp_fn,               /* function to call on response. */
+					timeout_fn,            /* function to call on timeout. */
+					(success_function)success_fn,            /* function to call on operation success. */
+					(fail_function)fail_fn,               /* function to call on operation fail. */
+					userdata)) == NULL) {
+		p->locked = False;
+		free_packet(p);
+		return NULL;
+	}
+
+	return rrec;
+}
+
+/****************************************************************************
+  Reply to a netbios name packet.  see rfc1002.txt
+****************************************************************************/
+
+void reply_netbios_packet(struct packet_struct *orig_packet,
+                          int rcode, enum netbios_reply_type_code rcv_code, int opcode,
+                          int ttl, char *data,int len)
+{
+	struct packet_struct packet;
+	struct nmb_packet *nmb = NULL;
+	struct res_rec answers;
+	struct nmb_packet *orig_nmb = &orig_packet->packet.nmb;
+	bool loopback_this_packet = False;
+	int rr_type = RR_TYPE_NB;
+	const char *packet_type = "unknown";
+
+	/* Check if we are sending to or from ourselves. */
+	if(ismyip_v4(orig_packet->ip) && (orig_packet->port == global_nmb_port))
+		loopback_this_packet = True;
+
+	nmb = &packet.packet.nmb;
+
+	/* Do a partial copy of the packet. We clear the locked flag and
+			the resource record pointers. */
+	packet = *orig_packet;   /* Full structure copy. */
+	packet.locked = False;
+	nmb->answers = NULL;
+	nmb->nsrecs = NULL;
+	nmb->additional = NULL;
+
+	switch (rcv_code) {
+		case NMB_STATUS:
+			packet_type = "nmb_status";
+			nmb->header.nm_flags.recursion_desired = False;
+			nmb->header.nm_flags.recursion_available = False;
+			rr_type = RR_TYPE_NBSTAT;
+			break;
+		case NMB_QUERY:
+			packet_type = "nmb_query";
+			nmb->header.nm_flags.recursion_desired = True;
+			nmb->header.nm_flags.recursion_available = True;
+			if (rcode) {
+				rr_type = RR_TYPE_NULL;
+			}
+			break;
+		case NMB_REG:
+		case NMB_REG_REFRESH:
+			packet_type = "nmb_reg";
+			nmb->header.nm_flags.recursion_desired = True;
+			nmb->header.nm_flags.recursion_available = True;
+			break;
+		case NMB_REL:
+			packet_type = "nmb_rel";
+			nmb->header.nm_flags.recursion_desired = False;
+			nmb->header.nm_flags.recursion_available = False;
+			break;
+		case NMB_WAIT_ACK:
+			packet_type = "nmb_wack";
+			nmb->header.nm_flags.recursion_desired = False;
+			nmb->header.nm_flags.recursion_available = False;
+			rr_type = RR_TYPE_NULL;
+			break;
+		case WINS_REG:
+			packet_type = "wins_reg";
+			nmb->header.nm_flags.recursion_desired = True;
+			nmb->header.nm_flags.recursion_available = True;
+			break;
+		case WINS_QUERY:
+			packet_type = "wins_query";
+			nmb->header.nm_flags.recursion_desired = True;
+			nmb->header.nm_flags.recursion_available = True;
+			if (rcode) {
+				rr_type = RR_TYPE_NULL;
+			}
+			break;
+		default:
+			DEBUG(0,("reply_netbios_packet: Unknown packet type: %s %s to ip %s\n",
+				packet_type, nmb_namestr(&orig_nmb->question.question_name),
+				inet_ntoa(packet.ip)));
+			return;
+	}
+
+	DEBUG(4,("reply_netbios_packet: sending a reply of packet type: %s %s to ip %s \
+for id %hu\n", packet_type, nmb_namestr(&orig_nmb->question.question_name),
+			inet_ntoa(packet.ip), orig_nmb->header.name_trn_id));
+
+	nmb->header.name_trn_id = orig_nmb->header.name_trn_id;
+	nmb->header.opcode = opcode;
+	nmb->header.response = True;
+	nmb->header.nm_flags.bcast = False;
+	nmb->header.nm_flags.trunc = False;
+	nmb->header.nm_flags.authoritative = True;
+
+	nmb->header.rcode = rcode;
+	nmb->header.qdcount = 0;
+	nmb->header.ancount = 1;
+	nmb->header.nscount = 0;
+	nmb->header.arcount = 0;
+
+	memset((char*)&nmb->question,'\0',sizeof(nmb->question));
+
+	nmb->answers = &answers;
+	memset((char*)nmb->answers,'\0',sizeof(*nmb->answers));
+
+	nmb->answers->rr_name  = orig_nmb->question.question_name;
+	nmb->answers->rr_type  = rr_type;
+	nmb->answers->rr_class = RR_CLASS_IN;
+	nmb->answers->ttl      = ttl;
+
+	if (data && len) {
+		if (len < 0 || len > sizeof(nmb->answers->rdata)) {
+			DEBUG(5,("reply_netbios_packet: "
+				"invalid packet len (%d)\n",
+				len ));
+			return;
+		}
+		nmb->answers->rdlength = len;
+		memcpy(nmb->answers->rdata, data, len);
+	}
+
+	packet.packet_type = NMB_PACKET;
+	packet.recv_fd = -1;
+	/* Ensure we send out on the same fd that the original
+		packet came in on to give the correct source IP address. */
+	if (orig_packet->send_fd != -1) {
+		packet.send_fd = orig_packet->send_fd;
+	} else {
+		packet.send_fd = orig_packet->recv_fd;
+	}
+	packet.timestamp = time(NULL);
+
+	debug_nmb_packet(&packet);
+
+	if(loopback_this_packet) {
+		struct packet_struct *lo_packet;
+		DEBUG(5,("reply_netbios_packet: sending packet to ourselves.\n"));
+		if((lo_packet = copy_packet(&packet)) == NULL)
+			return;
+		queue_packet(lo_packet);
+	} else if (!send_packet(&packet)) {
+		DEBUG(0,("reply_netbios_packet: send_packet to IP %s port %d failed\n",
+			inet_ntoa(packet.ip),packet.port));
+	}
+}
+
+/*******************************************************************
+  Queue a packet into a packet queue
+******************************************************************/
+
+void queue_packet(struct packet_struct *packet)
+{
+	struct packet_struct *p;
+
+	if (!packet_queue) {
+		packet->prev = NULL;
+		packet->next = NULL;
+		packet_queue = packet;
+		return;
+	}
+
+	/* find the bottom */
+	for (p=packet_queue;p->next;p=p->next)
+		;
+
+	p->next = packet;
+	packet->next = NULL;
+	packet->prev = p;
+}
+
+/****************************************************************************
+ Try and find a matching subnet record for a datagram port 138 packet.
+****************************************************************************/
+
+static struct subnet_record *find_subnet_for_dgram_browse_packet(struct packet_struct *p)
+{
+	struct subnet_record *subrec;
+
+	/* Go through all the broadcast subnets and see if the mask matches. */
+	for (subrec = FIRST_SUBNET; subrec ; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec)) {
+		if(same_net_v4(p->ip, subrec->bcast_ip, subrec->mask_ip))
+			return subrec;
+	}
+
+	/* If the subnet record is the remote announce broadcast subnet,
+		hack it here to be the first subnet. This is really gross and
+		is needed due to people turning on port 137/138 broadcast
+		forwarding on their routers. May fire and brimstone rain
+		down upon them...
+	*/
+
+	return FIRST_SUBNET;
+}
+
+/****************************************************************************
+Dispatch a browse frame from port 138 to the correct processing function.
+****************************************************************************/
+
+static void process_browse_packet(struct packet_struct *p, char *buf,int len)
+{
+	struct dgram_packet *dgram = &p->packet.dgram;
+	int command = CVAL(buf,0);
+	struct subnet_record *subrec = find_subnet_for_dgram_browse_packet(p);
+	char scope[64];
+	unstring src_name;
+
+	/* Drop the packet if it's a different NetBIOS scope, or the source is from one of our names. */
+	pull_ascii(scope, dgram->dest_name.scope, 64, 64, STR_TERMINATE);
+	if (!strequal(scope, global_scope())) {
+		DEBUG(7,("process_browse_packet: Discarding datagram from IP %s. Scope (%s) \
+mismatch with our scope (%s).\n", inet_ntoa(p->ip), scope, global_scope()));
+		return;
+	}
+
+	pull_ascii_nstring(src_name, sizeof(src_name), dgram->source_name.name);
+	if (is_myname(src_name)) {
+		DEBUG(7,("process_browse_packet: Discarding datagram from IP %s. Source name \
+%s is one of our names !\n", inet_ntoa(p->ip), nmb_namestr(&dgram->source_name)));
+		return;
+	}
+
+	switch (command) {
+		case ANN_HostAnnouncement:
+			debug_browse_data(buf, len);
+			process_host_announce(subrec, p, buf+1);
+			break;
+		case ANN_DomainAnnouncement:
+			debug_browse_data(buf, len);
+			process_workgroup_announce(subrec, p, buf+1);
+			break;
+		case ANN_LocalMasterAnnouncement:
+			debug_browse_data(buf, len);
+			process_local_master_announce(subrec, p, buf+1);
+			break;
+		case ANN_AnnouncementRequest:
+			debug_browse_data(buf, len);
+			process_announce_request(subrec, p, buf+1);
+			break;
+		case ANN_Election:
+			debug_browse_data(buf, len);
+			process_election(subrec, p, buf+1);
+			break;
+		case ANN_GetBackupListReq:
+			debug_browse_data(buf, len);
+			process_get_backup_list_request(subrec, p, buf+1);
+			break;
+		case ANN_GetBackupListResp:
+			debug_browse_data(buf, len);
+			/* We never send ANN_GetBackupListReq so we should never get these. */
+			DEBUG(0,("process_browse_packet: Discarding GetBackupListResponse \
+packet from %s IP %s\n", nmb_namestr(&dgram->source_name), inet_ntoa(p->ip)));
+			break;
+		case ANN_ResetBrowserState:
+			debug_browse_data(buf, len);
+			process_reset_browser(subrec, p, buf+1);
+			break;
+		case ANN_MasterAnnouncement:
+			/* Master browser datagrams must be processed on the unicast subnet. */
+			subrec = unicast_subnet;
+
+			debug_browse_data(buf, len);
+			process_master_browser_announce(subrec, p, buf+1);
+			break;
+		case ANN_BecomeBackup:
+			/*
+			 * We don't currently implement this. Log it just in case.
+			 */
+			debug_browse_data(buf, len);
+			DEBUG(10,("process_browse_packet: On subnet %s ignoring browse packet \
+command ANN_BecomeBackup from %s IP %s to %s\n", subrec->subnet_name, nmb_namestr(&dgram->source_name),
+					inet_ntoa(p->ip), nmb_namestr(&dgram->dest_name)));
+			break;
+		default:
+			debug_browse_data(buf, len);
+			DEBUG(0,("process_browse_packet: On subnet %s ignoring browse packet \
+command code %d from %s IP %s to %s\n", subrec->subnet_name, command, nmb_namestr(&dgram->source_name),
+				inet_ntoa(p->ip), nmb_namestr(&dgram->dest_name)));
+			break;
+	}
+}
+
+/****************************************************************************
+ Dispatch a LanMan browse frame from port 138 to the correct processing function.
+****************************************************************************/
+
+static void process_lanman_packet(struct packet_struct *p, char *buf,int len)
+{
+	struct dgram_packet *dgram = &p->packet.dgram;
+	int command = SVAL(buf,0);
+	struct subnet_record *subrec = find_subnet_for_dgram_browse_packet(p);
+	char scope[64];
+	unstring src_name;
+
+	/* Drop the packet if it's a different NetBIOS scope, or the source is from one of our names. */
+
+	pull_ascii(scope, dgram->dest_name.scope, 64, 64, STR_TERMINATE);
+	if (!strequal(scope, global_scope())) {
+		DEBUG(7,("process_lanman_packet: Discarding datagram from IP %s. Scope (%s) \
+mismatch with our scope (%s).\n", inet_ntoa(p->ip), scope, global_scope()));
+		return;
+	}
+
+	pull_ascii_nstring(src_name, sizeof(src_name), dgram->source_name.name);
+	if (is_myname(src_name)) {
+		DEBUG(0,("process_lanman_packet: Discarding datagram from IP %s. Source name \
+%s is one of our names !\n", inet_ntoa(p->ip), nmb_namestr(&dgram->source_name)));
+		return;
+	}
+
+	switch (command) {
+		case ANN_HostAnnouncement:
+			debug_browse_data(buf, len);
+			process_lm_host_announce(subrec, p, buf+1, len > 1 ? len-1 : 0);
+			break;
+		case ANN_AnnouncementRequest:
+			process_lm_announce_request(subrec, p, buf+1, len > 1 ? len-1 : 0);
+			break;
+		default:
+			DEBUG(0,("process_lanman_packet: On subnet %s ignoring browse packet \
+command code %d from %s IP %s to %s\n", subrec->subnet_name, command, nmb_namestr(&dgram->source_name),
+				inet_ntoa(p->ip), nmb_namestr(&dgram->dest_name)));
+			break;
+	}
+}
+
+/****************************************************************************
+  Determine if a packet is for us on port 138. Note that to have any chance of
+  being efficient we need to drop as many packets as possible at this
+  stage as subsequent processing is expensive. 
+****************************************************************************/
+
+static bool listening(struct packet_struct *p,struct nmb_name *nbname)
+{
+	struct subnet_record *subrec = NULL;
+
+	for (subrec = FIRST_SUBNET; subrec ; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec)) {
+		if(same_net_v4(p->ip, subrec->bcast_ip, subrec->mask_ip))
+			break;
+	}
+
+	if(subrec == NULL)
+		subrec = unicast_subnet;
+
+	return (find_name_on_subnet(subrec, nbname, FIND_SELF_NAME) != NULL);
+}
+
+/****************************************************************************
+  Process udp 138 datagrams
+****************************************************************************/
+
+static void process_dgram(struct packet_struct *p)
+{
+	char *buf;
+	char *buf2;
+	int len;
+	struct dgram_packet *dgram = &p->packet.dgram;
+
+	/* If we aren't listening to the destination name then ignore the packet */
+	if (!listening(p,&dgram->dest_name)) {
+			unexpected_packet(p);
+			DEBUG(5,("process_dgram: ignoring dgram packet sent to name %s from %s\n",
+				nmb_namestr(&dgram->dest_name), inet_ntoa(p->ip)));
+			return;
+	}
+
+	if (dgram->header.msg_type != 0x10 && dgram->header.msg_type != 0x11 && dgram->header.msg_type != 0x12) {
+		unexpected_packet(p);
+		/* Don't process error packets etc yet */
+		DEBUG(5,("process_dgram: ignoring dgram packet sent to name %s from IP %s as it is \
+an error packet of type %x\n", nmb_namestr(&dgram->dest_name), inet_ntoa(p->ip), dgram->header.msg_type));
+		return;
+	}
+
+	/* Ensure we have a large enough packet before looking inside. */
+	if (dgram->datasize < (smb_vwv12 - 2)) {
+		/* That's the offset minus the 4 byte length + 2 bytes of offset. */
+		DEBUG(0,("process_dgram: ignoring too short dgram packet (%u) sent to name %s from IP %s\n",
+			(unsigned int)dgram->datasize,
+			nmb_namestr(&dgram->dest_name),
+			inet_ntoa(p->ip) ));
+		return;
+	}
+
+	buf = &dgram->data[0];
+	buf -= 4; /* XXXX for the pseudo tcp length - someday I need to get rid of this */
+
+	if (CVAL(buf,smb_com) != SMBtrans)
+		return;
+
+	len = SVAL(buf,smb_vwv11);
+	buf2 = smb_base(buf) + SVAL(buf,smb_vwv12);
+
+	if (len <= 0 || len > dgram->datasize) {
+		DEBUG(0,("process_dgram: ignoring malformed1 (datasize = %d, len = %d) datagram \
+packet sent to name %s from IP %s\n",
+			dgram->datasize,
+			len,
+			nmb_namestr(&dgram->dest_name),
+			inet_ntoa(p->ip) ));
+		return;
+	}
+
+	if (buf2 < dgram->data || (buf2 >= dgram->data + dgram->datasize)) {
+		DEBUG(0,("process_dgram: ignoring malformed2 (datasize = %d, len=%d, off=%d) datagram \
+packet sent to name %s from IP %s\n",
+			dgram->datasize,
+			len,
+			(int)PTR_DIFF(buf2, dgram->data),
+			nmb_namestr(&dgram->dest_name),
+			inet_ntoa(p->ip) ));
+		return;
+	}
+
+	if ((buf2 + len < dgram->data) || (buf2 + len > dgram->data + dgram->datasize)) {
+		DEBUG(0,("process_dgram: ignoring malformed3 (datasize = %d, len=%d, off=%d) datagram \
+packet sent to name %s from IP %s\n",
+			dgram->datasize,
+			len,
+			(int)PTR_DIFF(buf2, dgram->data),
+			nmb_namestr(&dgram->dest_name),
+			inet_ntoa(p->ip) ));
+		return;
+	}
+
+	DEBUG(4,("process_dgram: datagram from %s to %s IP %s for %s of type %d len=%d\n",
+		nmb_namestr(&dgram->source_name),nmb_namestr(&dgram->dest_name),
+		inet_ntoa(p->ip), smb_buf(buf),CVAL(buf2,0),len));
+
+	/* Datagram packet received for the browser mailslot */
+	if (strequal(smb_buf(buf),BROWSE_MAILSLOT)) {
+		process_browse_packet(p,buf2,len);
+		return;
+	}
+
+	/* Datagram packet received for the LAN Manager mailslot */
+	if (strequal(smb_buf(buf),LANMAN_MAILSLOT)) {
+		process_lanman_packet(p,buf2,len);
+		return;
+	}
+
+	/* Datagram packet received for the domain logon mailslot */
+	if (strequal(smb_buf(buf),NET_LOGON_MAILSLOT)) {
+		process_logon_packet(p,buf2,len,NET_LOGON_MAILSLOT);
+		return;
+	}
+
+	/* Datagram packet received for the NT domain logon mailslot */
+	if (strequal(smb_buf(buf),NT_LOGON_MAILSLOT)) {
+		process_logon_packet(p,buf2,len,NT_LOGON_MAILSLOT);
+		return;
+	}
+
+	unexpected_packet(p);
+}
+
+/****************************************************************************
+  Validate a response nmb packet.
+****************************************************************************/
+
+static bool validate_nmb_response_packet( struct nmb_packet *nmb )
+{
+	bool ignore = False;
+
+	switch (nmb->header.opcode) {
+		case NMB_NAME_REG_OPCODE:
+		case NMB_NAME_REFRESH_OPCODE_8: /* ambiguity in rfc1002 about which is correct. */
+		case NMB_NAME_REFRESH_OPCODE_9: /* WinNT uses 8 by default. */
+			if (nmb->header.ancount == 0) {
+				DEBUG(0,("validate_nmb_response_packet: Bad REG/REFRESH Packet. "));
+				ignore = True;
+			}
+			break;
+
+		case NMB_NAME_QUERY_OPCODE:
+			if ((nmb->header.ancount != 0) && (nmb->header.ancount != 1)) {
+				DEBUG(0,("validate_nmb_response_packet: Bad QUERY Packet. "));
+				ignore = True;
+			}
+			break;
+
+		case NMB_NAME_RELEASE_OPCODE:
+			if (nmb->header.ancount == 0) {
+				DEBUG(0,("validate_nmb_response_packet: Bad RELEASE Packet. "));
+				ignore = True;
+			}
+			break;
+
+		case NMB_WACK_OPCODE:
+			/* Check WACK response here. */
+			if (nmb->header.ancount != 1) {
+				DEBUG(0,("validate_nmb_response_packet: Bad WACK Packet. "));
+				ignore = True;
+			}
+			break;
+		default:
+			DEBUG(0,("validate_nmb_response_packet: Ignoring packet with unknown opcode %d.\n",
+					nmb->header.opcode));
+			return True;
+	}
+
+	if(ignore)
+		DEBUG(0,("Ignoring response packet with opcode %d.\n", nmb->header.opcode));
+
+	return ignore;
+}
+
+/****************************************************************************
+  Validate a request nmb packet.
+****************************************************************************/
+
+static bool validate_nmb_packet( struct nmb_packet *nmb )
+{
+	bool ignore = False;
+
+	switch (nmb->header.opcode) {
+		case NMB_NAME_REG_OPCODE:
+		case NMB_NAME_REFRESH_OPCODE_8: /* ambiguity in rfc1002 about which is correct. */
+		case NMB_NAME_REFRESH_OPCODE_9: /* WinNT uses 8 by default. */
+		case NMB_NAME_MULTIHOMED_REG_OPCODE:
+			if (nmb->header.qdcount==0 || nmb->header.arcount==0) {
+				DEBUG(0,("validate_nmb_packet: Bad REG/REFRESH Packet. "));
+				ignore = True;
+			}
+			break;
+
+		case NMB_NAME_QUERY_OPCODE:
+			if ((nmb->header.qdcount == 0) || ((nmb->question.question_type != QUESTION_TYPE_NB_QUERY) &&
+					(nmb->question.question_type != QUESTION_TYPE_NB_STATUS))) {
+				DEBUG(0,("validate_nmb_packet: Bad QUERY Packet. "));
+				ignore = True;
+			}
+			break;
+
+		case NMB_NAME_RELEASE_OPCODE:
+			if (nmb->header.qdcount==0 || nmb->header.arcount==0) {
+				DEBUG(0,("validate_nmb_packet: Bad RELEASE Packet. "));
+				ignore = True;
+			}
+			break;
+		default:
+			DEBUG(0,("validate_nmb_packet: Ignoring packet with unknown opcode %d.\n",
+				nmb->header.opcode));
+			return True;
+	}
+
+	if(ignore)
+		DEBUG(0,("validate_nmb_packet: Ignoring request packet with opcode %d.\n", nmb->header.opcode));
+
+	return ignore;
+}
+
+/****************************************************************************
+  Find a subnet (and potentially a response record) for a packet.
+****************************************************************************/
+
+static struct subnet_record *find_subnet_for_nmb_packet( struct packet_struct *p,
+                                                         struct response_record **pprrec)
+{
+	struct nmb_packet *nmb = &p->packet.nmb;
+	struct response_record *rrec = NULL;
+	struct subnet_record *subrec = NULL;
+
+	if(pprrec != NULL)
+		*pprrec = NULL;
+
+	if(nmb->header.response) {
+		/* It's a response packet. Find a record for it or it's an error. */
+
+		rrec = find_response_record( &subrec, nmb->header.name_trn_id);
+		if(rrec == NULL) {
+			DEBUG(3,("find_subnet_for_nmb_packet: response record not found for response id %hu\n",
+				nmb->header.name_trn_id));
+			unexpected_packet(p);
+			return NULL;
+		}
+
+		if(subrec == NULL) {
+			DEBUG(0,("find_subnet_for_nmb_packet: subnet record not found for response id %hu\n",
+				nmb->header.name_trn_id));
+			return NULL;
+		}
+
+		if(pprrec != NULL)
+			*pprrec = rrec;
+		return subrec;
+	}
+
+	/* Try and see what subnet this packet belongs to. */
+
+	/* WINS server ? */
+	if(packet_is_for_wins_server(p))
+		return wins_server_subnet;
+
+	/* If it wasn't a broadcast packet then send to the UNICAST subnet. */
+	if(nmb->header.nm_flags.bcast == False)
+		return unicast_subnet;
+
+	/* Go through all the broadcast subnets and see if the mask matches. */
+	for (subrec = FIRST_SUBNET; subrec ; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec)) {
+		if(same_net_v4(p->ip, subrec->bcast_ip, subrec->mask_ip))
+			return subrec;
+	}
+
+	/* If none match it must have been a directed broadcast - assign the remote_broadcast_subnet. */
+	return remote_broadcast_subnet;
+}
+
+/****************************************************************************
+  Process a nmb request packet - validate the packet and route it.
+****************************************************************************/
+
+static void process_nmb_request(struct packet_struct *p)
+{
+	struct nmb_packet *nmb = &p->packet.nmb;
+	struct subnet_record *subrec = NULL;
+
+	debug_nmb_packet(p);
+
+	/* Ensure we have a good packet. */
+	if(validate_nmb_packet(nmb))
+		return;
+
+	/* Allocate a subnet to this packet - if we cannot - fail. */
+	if((subrec = find_subnet_for_nmb_packet(p, NULL))==NULL)
+		return;
+
+	switch (nmb->header.opcode) {
+		case NMB_NAME_REG_OPCODE:
+			if(subrec == wins_server_subnet)
+				wins_process_name_registration_request(subrec, p);
+			else
+				process_name_registration_request(subrec, p);
+			break;
+
+		case NMB_NAME_REFRESH_OPCODE_8: /* ambiguity in rfc1002 about which is correct. */
+		case NMB_NAME_REFRESH_OPCODE_9:
+			if(subrec == wins_server_subnet)
+				wins_process_name_refresh_request(subrec, p);
+			else
+				process_name_refresh_request(subrec, p);
+			break;
+
+		case NMB_NAME_MULTIHOMED_REG_OPCODE:
+			if(subrec == wins_server_subnet) {
+				wins_process_multihomed_name_registration_request(subrec, p);
+			} else {
+				DEBUG(0,("process_nmb_request: Multihomed registration request must be \
+directed at a WINS server.\n"));
+			}
+			break;
+
+		case NMB_NAME_QUERY_OPCODE:
+			switch (nmb->question.question_type) {
+				case QUESTION_TYPE_NB_QUERY:
+					if(subrec == wins_server_subnet)
+						wins_process_name_query_request(subrec, p);
+					else
+						process_name_query_request(subrec, p);
+					break;
+				case QUESTION_TYPE_NB_STATUS:
+					if(subrec == wins_server_subnet) {
+						DEBUG(0,("process_nmb_request: NB_STATUS request directed at WINS server is \
+not allowed.\n"));
+						break;
+					} else {
+						process_node_status_request(subrec, p);
+					}
+					break;
+			}
+			break;
+
+		case NMB_NAME_RELEASE_OPCODE:
+			if(subrec == wins_server_subnet)
+				wins_process_name_release_request(subrec, p);
+			else
+				process_name_release_request(subrec, p);
+			break;
+	}
+}
+
+/****************************************************************************
+  Process a nmb response packet - validate the packet and route it.
+  to either the WINS server or a normal response.
+****************************************************************************/
+
+static void process_nmb_response(struct packet_struct *p)
+{
+	struct nmb_packet *nmb = &p->packet.nmb;
+	struct subnet_record *subrec = NULL;
+	struct response_record *rrec = NULL;
+
+	debug_nmb_packet(p);
+
+	if(validate_nmb_response_packet(nmb))
+		return;
+
+	if((subrec = find_subnet_for_nmb_packet(p, &rrec))==NULL)
+		return;
+
+	if(rrec == NULL) {
+		DEBUG(0,("process_nmb_response: response packet received but no response record \
+found for id = %hu. Ignoring packet.\n", nmb->header.name_trn_id));
+		return;
+	}
+
+	/* Increment the number of responses received for this record. */
+	rrec->num_msgs++;
+	/* Ensure we don't re-send the request. */
+	rrec->repeat_count = 0;
+
+	/* Call the response received function for this packet. */
+	(*rrec->resp_fn)(subrec, rrec, p);
+}
+
+/*******************************************************************
+  Run elements off the packet queue till its empty
+******************************************************************/
+
+void run_packet_queue(void)
+{
+	struct packet_struct *p;
+
+	while ((p = packet_queue)) {
+		packet_queue = p->next;
+		if (packet_queue)
+			packet_queue->prev = NULL;
+		p->next = p->prev = NULL;
+
+		switch (p->packet_type) {
+			case NMB_PACKET:
+				if(p->packet.nmb.header.response)
+					process_nmb_response(p);
+				else
+					process_nmb_request(p);
+				break;
+
+			case DGRAM_PACKET:
+				process_dgram(p);
+				break;
+		}
+		free_packet(p);
+	}
+}
+
+/*******************************************************************
+ Retransmit or timeout elements from all the outgoing subnet response
+ record queues. NOTE that this code must also check the WINS server
+ subnet for response records to timeout as the WINS server code
+ can send requests to check if a client still owns a name.
+ (Patch from Andrey Alekseyev <fetch@muffin.arcadia.spb.ru>).
+******************************************************************/
+
+void retransmit_or_expire_response_records(time_t t)
+{
+	struct subnet_record *subrec;
+
+	for (subrec = FIRST_SUBNET; subrec; subrec = get_next_subnet_maybe_unicast_or_wins_server(subrec)) {
+		struct response_record *rrec, *nextrrec;
+
+  restart:
+
+		for (rrec = subrec->responselist; rrec; rrec = nextrrec) {
+			nextrrec = rrec->next;
+
+			if (rrec->repeat_time <= t) {
+				if (rrec->repeat_count > 0) {
+					/* Resend while we have a non-zero repeat_count. */
+					if(!send_packet(rrec->packet)) {
+						DEBUG(0,("retransmit_or_expire_response_records: Failed to resend packet id %hu \
+to IP %s on subnet %s\n", rrec->response_id, inet_ntoa(rrec->packet->ip), subrec->subnet_name));
+					}
+					rrec->repeat_time = t + rrec->repeat_interval;
+					rrec->repeat_count--;
+				} else {
+					DEBUG(4,("retransmit_or_expire_response_records: timeout for packet id %hu to IP %s \
+on subnet %s\n", rrec->response_id, inet_ntoa(rrec->packet->ip), subrec->subnet_name));
+
+					/*
+					 * Check the flag in this record to prevent recursion if we end
+					 * up in this function again via the timeout function call.
+					 */
+
+					if(!rrec->in_expiration_processing) {
+
+						/*
+						 * Set the recursion protection flag in this record.
+						 */
+
+						rrec->in_expiration_processing = True;
+
+						/* Call the timeout function. This will deal with removing the
+								timed out packet. */
+						if(rrec->timeout_fn) {
+							(*rrec->timeout_fn)(subrec, rrec);
+						} else {
+							/* We must remove the record ourself if there is
+									no timeout function. */
+							remove_response_record(subrec, rrec);
+						}
+						/* We have changed subrec->responselist,
+						 * restart from the beginning of this list. */
+						goto restart;
+					} /* !rrec->in_expitation_processing */
+				} /* rrec->repeat_count > 0 */
+			} /* rrec->repeat_time <= t */
+		} /* end for rrec */
+	} /* end for subnet */
+}
+
+/****************************************************************************
+  Create an fd_set containing all the sockets in the subnet structures,
+  plus the broadcast sockets.
+***************************************************************************/
+
+static bool create_listen_fdset(fd_set **ppset, int **psock_array, int *listen_number, int *maxfd)
+{
+	int *sock_array = NULL;
+	struct subnet_record *subrec = NULL;
+	int count = 0;
+	int num = 0;
+	fd_set *pset = SMB_MALLOC_P(fd_set);
+
+	if(pset == NULL) {
+		DEBUG(0,("create_listen_fdset: malloc fail !\n"));
+		return True;
+	}
+
+	/* The Client* sockets */
+	count++;
+
+	/* Check that we can add all the fd's we need. */
+	for (subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec))
+		count++;
+
+	/* each interface gets 4 sockets */
+	count *= 4;
+
+	if(count > FD_SETSIZE) {
+		DEBUG(0,("create_listen_fdset: Too many file descriptors needed (%d). We can \
+only use %d.\n", count, FD_SETSIZE));
+		SAFE_FREE(pset);
+		return True;
+	}
+
+	if((sock_array = SMB_MALLOC_ARRAY(int, count)) == NULL) {
+		DEBUG(0,("create_listen_fdset: malloc fail for socket array. size %d\n", count));
+		SAFE_FREE(pset);
+		return True;
+	}
+
+	FD_ZERO(pset);
+
+	/* Add in the lp_socket_address() interface on 137. */
+	FD_SET(ClientNMB,pset);
+	sock_array[num++] = ClientNMB;
+	*maxfd = MAX( *maxfd, ClientNMB);
+
+	/* the lp_socket_address() interface has only one socket */
+	sock_array[num++] = -1;
+
+	/* Add in the 137 sockets on all the interfaces. */
+	for (subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec)) {
+		FD_SET(subrec->nmb_sock,pset);
+		sock_array[num++] = subrec->nmb_sock;
+		*maxfd = MAX( *maxfd, subrec->nmb_sock);
+
+		sock_array[num++] = subrec->nmb_bcast;
+		if (subrec->nmb_bcast != -1) {
+			FD_SET(subrec->nmb_bcast,pset);
+			*maxfd = MAX( *maxfd, subrec->nmb_bcast);
+		}
+	}
+
+	/* Add in the lp_socket_address() interface on 138. */
+	FD_SET(ClientDGRAM,pset);
+	sock_array[num++] = ClientDGRAM;
+	*maxfd = MAX( *maxfd, ClientDGRAM);
+
+	/* the lp_socket_address() interface has only one socket */
+	sock_array[num++] = -1;
+
+	/* Add in the 138 sockets on all the interfaces. */
+	for (subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec)) {
+		FD_SET(subrec->dgram_sock,pset);
+		sock_array[num++] = subrec->dgram_sock;
+		*maxfd = MAX( *maxfd, subrec->dgram_sock);
+
+		sock_array[num++] = subrec->dgram_bcast;
+		if (subrec->dgram_bcast != -1) {
+			FD_SET(subrec->dgram_bcast,pset);
+			*maxfd = MAX( *maxfd, subrec->dgram_bcast);
+		}
+	}
+
+	*listen_number = count;
+
+	SAFE_FREE(*ppset);
+	SAFE_FREE(*psock_array);
+
+	*ppset = pset;
+	*psock_array = sock_array;
+
+	return False;
+}
+
+/****************************************************************************
+ List of packets we're processing this select.
+***************************************************************************/
+
+struct processed_packet {
+	struct processed_packet *next;
+	struct processed_packet *prev;
+	enum packet_type packet_type;
+	struct in_addr ip;
+	int packet_id;
+};
+
+/****************************************************************************
+ Have we seen this before ?
+***************************************************************************/
+
+static bool is_processed_packet(struct processed_packet *processed_packet_list,
+				struct packet_struct *packet)
+{
+	struct processed_packet *p = NULL;
+
+	for (p = processed_packet_list; p; p = p->next) {
+		if (ip_equal_v4(p->ip, packet->ip) && p->packet_type == packet->packet_type) {
+			if ((p->packet_type == NMB_PACKET) &&
+				(p->packet_id ==
+					packet->packet.nmb.header.name_trn_id)) {
+				return true;
+			} else if ((p->packet_type == DGRAM_PACKET) &&
+				(p->packet_id ==
+					packet->packet.dgram.header.dgm_id)) {
+				return true;
+			}
+		}
+	}
+	return false;
+}
+
+/****************************************************************************
+ Keep a list of what we've seen before.
+***************************************************************************/
+
+static bool store_processed_packet(struct processed_packet **pp_processed_packet_list,
+				struct packet_struct *packet)
+{
+	struct processed_packet *p = SMB_MALLOC_P(struct processed_packet);
+	if (!p) {
+		return false;
+	}
+	p->packet_type = packet->packet_type;
+	p->ip = packet->ip;
+	if (packet->packet_type == NMB_PACKET) {
+		p->packet_id = packet->packet.nmb.header.name_trn_id;
+	} else if (packet->packet_type == DGRAM_PACKET) {
+		p->packet_id = packet->packet.dgram.header.dgm_id;
+	} else {
+		return false;
+	}
+
+	DLIST_ADD(*pp_processed_packet_list, p);
+	return true;
+}
+
+/****************************************************************************
+ Throw away what we've seen before.
+***************************************************************************/
+
+static void free_processed_packet_list(struct processed_packet **pp_processed_packet_list)
+{
+	struct processed_packet *p = NULL, *next = NULL;
+
+	for (p = *pp_processed_packet_list; p; p = next) {
+		next = p->next;
+		DLIST_REMOVE(*pp_processed_packet_list, p);
+		SAFE_FREE(p);
+	}
+}
+
+/****************************************************************************
+  Listens for NMB or DGRAM packets, and queues them.
+  return True if the socket is dead
+***************************************************************************/
+
+bool listen_for_packets(bool run_election)
+{
+	static fd_set *listen_set = NULL;
+	static int listen_number = 0;
+	static int *sock_array = NULL;
+	int i;
+	static int maxfd = 0;
+
+	fd_set r_fds;
+	fd_set w_fds;
+	int selrtn;
+	struct timeval timeout;
+#ifndef SYNC_DNS
+	int dns_fd;
+#endif
+	struct processed_packet *processed_packet_list = NULL;
+
+	if(listen_set == NULL || rescan_listen_set) {
+		if(create_listen_fdset(&listen_set, &sock_array, &listen_number, &maxfd)) {
+			DEBUG(0,("listen_for_packets: Fatal error. unable to create listen set. Exiting.\n"));
+			return True;
+		}
+		rescan_listen_set = False;
+	}
+
+	memcpy((char *)&r_fds, (char *)listen_set, sizeof(fd_set));
+	FD_ZERO(&w_fds);
+
+#ifndef SYNC_DNS
+	dns_fd = asyncdns_fd();
+	if (dns_fd != -1) {
+		FD_SET(dns_fd, &r_fds);
+		maxfd = MAX( maxfd, dns_fd);
+	}
+#endif
+
+	/* Process a signal and timer events now... */
+	if (run_events(nmbd_event_context(), 0, NULL, NULL)) {
+		return False;
+	}
+
+	/*
+	 * During elections and when expecting a netbios response packet we
+	 * need to send election packets at tighter intervals.
+	 * Ideally it needs to be the interval (in ms) between time now and
+	 * the time we are expecting the next netbios packet.
+	 */
+
+	timeout.tv_sec = (run_election||num_response_packets) ? 1 : NMBD_SELECT_LOOP;
+	timeout.tv_usec = 0;
+
+	{
+		struct timeval now = timeval_current();
+		event_add_to_select_args(nmbd_event_context(), &now,
+					 &r_fds, &w_fds, &timeout, &maxfd);
+	}
+
+	selrtn = sys_select(maxfd+1,&r_fds,&w_fds,NULL,&timeout);
+
+	if (run_events(nmbd_event_context(), selrtn, &r_fds, &w_fds)) {
+		return False;
+	}
+
+	if (selrtn == -1) {
+		return False;
+	}
+
+#ifndef SYNC_DNS
+	if (dns_fd != -1 && FD_ISSET(dns_fd,&r_fds)) {
+		run_dns_queue();
+	}
+#endif
+
+	for(i = 0; i < listen_number; i++) {
+		enum packet_type packet_type;
+		struct packet_struct *packet;
+		const char *packet_name;
+		int client_fd;
+		int client_port;
+
+		if (sock_array[i] == -1) {
+			continue;
+		}
+
+		if (!FD_ISSET(sock_array[i],&r_fds)) {
+			continue;
+		}
+
+		if (i < (listen_number/2)) {
+			/* Port 137 */
+			packet_type = NMB_PACKET;
+			packet_name = "nmb";
+			client_fd = ClientNMB;
+			client_port = global_nmb_port;
+		} else {
+			/* Port 138 */
+			packet_type = DGRAM_PACKET;
+			packet_name = "dgram";
+			client_fd = ClientDGRAM;
+			client_port = DGRAM_PORT;
+		}
+
+		packet = read_packet(sock_array[i], packet_type);
+		if (!packet) {
+			continue;
+		}
+
+		/*
+		 * If we got a packet on the broadcast socket and interfaces
+		 * only is set then check it came from one of our local nets.
+		 */
+		if (lp_bind_interfaces_only() &&
+		    (sock_array[i] == client_fd) &&
+		    (!is_local_net_v4(packet->ip))) {
+			DEBUG(7,("discarding %s packet sent to broadcast socket from %s:%d\n",
+				packet_name, inet_ntoa(packet->ip), packet->port));
+			free_packet(packet);
+			continue;
+		}
+
+		if ((is_loopback_ip_v4(packet->ip) || ismyip_v4(packet->ip)) &&
+		    packet->port == client_port)
+		{
+			if (client_port == DGRAM_PORT) {
+				DEBUG(7,("discarding own dgram packet from %s:%d\n",
+					inet_ntoa(packet->ip),packet->port));
+				free_packet(packet);
+				continue;
+			}
+
+			if (packet->packet.nmb.header.nm_flags.bcast) {
+				DEBUG(7,("discarding own nmb bcast packet from %s:%d\n",
+					inet_ntoa(packet->ip),packet->port));
+				free_packet(packet);
+				continue;
+			}
+		}
+
+
+		if (is_processed_packet(processed_packet_list, packet)) {
+			DEBUG(7,("discarding duplicate packet from %s:%d\n",
+				inet_ntoa(packet->ip),packet->port));
+			free_packet(packet);
+			continue;
+		}
+
+		store_processed_packet(&processed_packet_list, packet);
+
+		/*
+		 * 0,2,4,... are unicast sockets
+		 * 1,3,5,... are broadcast sockets
+		 *
+		 * on broadcast socket we only receive packets
+		 * and send replies via the unicast socket.
+		 *
+		 * 0,1 and 2,3 and ... belong together.
+		 */
+		if ((i % 2) != 0) {
+			/* this is a broadcast socket */
+			packet->send_fd = sock_array[i-1];
+		} else {
+			/* this is already a unicast socket */
+			packet->send_fd = sock_array[i];
+		}
+
+		queue_packet(packet);
+	}
+
+	free_processed_packet_list(&processed_packet_list);
+	return False;
+}
+
+/****************************************************************************
+  Construct and send a netbios DGRAM.
+**************************************************************************/
+
+bool send_mailslot(bool unique, const char *mailslot,char *buf, size_t len,
+                   const char *srcname, int src_type,
+                   const char *dstname, int dest_type,
+                   struct in_addr dest_ip,struct in_addr src_ip,
+		   int dest_port)
+{
+	bool loopback_this_packet = False;
+	struct packet_struct p;
+	struct dgram_packet *dgram = &p.packet.dgram;
+	char *ptr,*p2;
+	char tmp[4];
+
+	memset((char *)&p,'\0',sizeof(p));
+
+	if(ismyip_v4(dest_ip) && (dest_port == DGRAM_PORT)) /* Only if to DGRAM_PORT */
+		loopback_this_packet = True;
+
+	/* generate_name_trn_id(); */ /* Not used, so gone, RJS */
+
+	/* DIRECT GROUP or UNIQUE datagram. */
+	dgram->header.msg_type = unique ? 0x10 : 0x11;
+	dgram->header.flags.node_type = M_NODE;
+	dgram->header.flags.first = True;
+	dgram->header.flags.more = False;
+	dgram->header.dgm_id = generate_name_trn_id();
+	dgram->header.source_ip = src_ip;
+	dgram->header.source_port = DGRAM_PORT;
+	dgram->header.dgm_length = 0; /* Let build_dgram() handle this. */
+	dgram->header.packet_offset = 0;
+
+	make_nmb_name(&dgram->source_name,srcname,src_type);
+	make_nmb_name(&dgram->dest_name,dstname,dest_type);
+
+	ptr = &dgram->data[0];
+
+	/* Setup the smb part. */
+	ptr -= 4; /* XXX Ugliness because of handling of tcp SMB length. */
+	memcpy(tmp,ptr,4);
+
+	if (smb_size + 17*2 + strlen(mailslot) + 1 + len > MAX_DGRAM_SIZE) {
+		DEBUG(0, ("send_mailslot: Cannot write beyond end of packet\n"));
+		return false;
+	}
+
+	cli_set_message(ptr,17,strlen(mailslot) + 1 + len,True);
+	memcpy(ptr,tmp,4);
+
+	SCVAL(ptr,smb_com,SMBtrans);
+	SSVAL(ptr,smb_vwv1,len);
+	SSVAL(ptr,smb_vwv11,len);
+	SSVAL(ptr,smb_vwv12,70 + strlen(mailslot));
+	SSVAL(ptr,smb_vwv13,3);
+	SSVAL(ptr,smb_vwv14,1);
+	SSVAL(ptr,smb_vwv15,1);
+	SSVAL(ptr,smb_vwv16,2);
+	p2 = smb_buf(ptr);
+	safe_strcpy_base(p2, mailslot, dgram->data, sizeof(dgram->data));
+	p2 = skip_string(ptr,MAX_DGRAM_SIZE,p2);
+
+	if (((p2+len) > dgram->data+sizeof(dgram->data)) || ((p2+len) < p2)) {
+		DEBUG(0, ("send_mailslot: Cannot write beyond end of packet\n"));
+		return False;
+	} else {
+		if (len) {
+			memcpy(p2,buf,len);
+		}
+		p2 += len;
+	}
+
+	dgram->datasize = PTR_DIFF(p2,ptr+4); /* +4 for tcp length. */
+
+	p.ip = dest_ip;
+	p.port = dest_port;
+	p.recv_fd = -1;
+	p.send_fd = find_subnet_mailslot_fd_for_address( src_ip );
+	p.timestamp = time(NULL);
+	p.packet_type = DGRAM_PACKET;
+
+	DEBUG(4,("send_mailslot: Sending to mailslot %s from %s IP %s ", mailslot,
+			nmb_namestr(&dgram->source_name), inet_ntoa(src_ip)));
+	DEBUG(4,("to %s IP %s\n", nmb_namestr(&dgram->dest_name), inet_ntoa(dest_ip)));
+
+	debug_browse_data(buf, len);
+
+	if(loopback_this_packet) {
+		struct packet_struct *lo_packet = NULL;
+		DEBUG(5,("send_mailslot: sending packet to ourselves.\n"));
+		if((lo_packet = copy_packet(&p)) == NULL)
+			return False;
+		queue_packet(lo_packet);
+		return True;
+	} else {
+		return(send_packet(&p));
+	}
+}

=== added directory '.pc/security-CVE-2011-0719.patch/source3/utils'
=== added file '.pc/security-CVE-2011-0719.patch/source3/utils/smbfilter.c'
--- .pc/security-CVE-2011-0719.patch/source3/utils/smbfilter.c	1970-01-01 00:00:00 +0000
+++ .pc/security-CVE-2011-0719.patch/source3/utils/smbfilter.c	2011-03-02 20:48:44 +0000
@@ -0,0 +1,295 @@
+/* 
+   Unix SMB/CIFS implementation.
+   SMB filter/socket plugin
+   Copyright (C) Andrew Tridgell 1999
+   
+   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 3 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, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+#define SECURITY_MASK 0
+#define SECURITY_SET  0
+
+/* this forces non-unicode */
+#define CAPABILITY_MASK 0
+#define CAPABILITY_SET  0
+
+/* and non-unicode for the client too */
+#define CLI_CAPABILITY_MASK 0
+#define CLI_CAPABILITY_SET  0
+
+static char *netbiosname;
+static char packet[BUFFER_SIZE];
+
+static void save_file(const char *fname, void *ppacket, size_t length)
+{
+	int fd;
+	fd = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0644);
+	if (fd == -1) {
+		perror(fname);
+		return;
+	}
+	if (write(fd, ppacket, length) != length) {
+		fprintf(stderr,"Failed to write %s\n", fname);
+		return;
+	}
+	close(fd);
+	printf("Wrote %ld bytes to %s\n", (unsigned long)length, fname);
+}
+
+static void filter_reply(char *buf)
+{
+	int msg_type = CVAL(buf,0);
+	int type = CVAL(buf,smb_com);
+	unsigned x;
+
+	if (msg_type) return;
+
+	switch (type) {
+
+	case SMBnegprot:
+		/* force the security bits */
+		x = CVAL(buf, smb_vwv1);
+		x = (x | SECURITY_SET) & ~SECURITY_MASK;
+		SCVAL(buf, smb_vwv1, x);
+
+		/* force the capabilities */
+		x = IVAL(buf,smb_vwv9+1);
+		x = (x | CAPABILITY_SET) & ~CAPABILITY_MASK;
+		SIVAL(buf, smb_vwv9+1, x);
+		break;
+
+	}
+}
+
+static void filter_request(char *buf)
+{
+	int msg_type = CVAL(buf,0);
+	int type = CVAL(buf,smb_com);
+	fstring name1,name2;
+	unsigned x;
+
+	if (msg_type) {
+		/* it's a netbios special */
+		switch (msg_type) {
+		case 0x81:
+			/* session request */
+			name_extract(buf,4,name1);
+			name_extract(buf,4 + name_len(buf + 4),name2);
+			d_printf("sesion_request: %s -> %s\n",
+				 name1, name2);
+			if (netbiosname) {
+				char *mangled = name_mangle(
+					talloc_tos(), netbiosname, 0x20);
+				if (mangled != NULL) {
+					/* replace the destination netbios
+					 * name */
+					memcpy(buf+4, mangled,
+					       name_len(mangled));
+					TALLOC_FREE(mangled);
+				}
+			}
+		}
+		return;
+	}
+
+	/* it's an ordinary SMB request */
+	switch (type) {
+	case SMBsesssetupX:
+		/* force the client capabilities */
+		x = IVAL(buf,smb_vwv11);
+		d_printf("SMBsesssetupX cap=0x%08x\n", x);
+		d_printf("pwlen=%d/%d\n", SVAL(buf, smb_vwv7), SVAL(buf, smb_vwv8));
+		system("mv sessionsetup.dat sessionsetup1.dat");
+		save_file("sessionsetup.dat", smb_buf(buf), SVAL(buf, smb_vwv7));
+		x = (x | CLI_CAPABILITY_SET) & ~CLI_CAPABILITY_MASK;
+		SIVAL(buf, smb_vwv11, x);
+		break;
+	}
+
+}
+
+/****************************************************************************
+ Send an smb to a fd.
+****************************************************************************/
+
+static bool send_smb(int fd, char *buffer)
+{
+	size_t len;
+	size_t nwritten=0;
+	ssize_t ret;
+
+        len = smb_len(buffer) + 4;
+
+	while (nwritten < len) {
+		ret = write_data(fd,buffer+nwritten,len - nwritten);
+		if (ret <= 0) {
+			DEBUG(0,("Error writing %d bytes to client. %d. (%s)\n",
+				(int)len,(int)ret, strerror(errno) ));
+			return false;
+		}
+		nwritten += ret;
+	}
+
+	return true;
+}
+
+static void filter_child(int c, struct sockaddr_storage *dest_ss)
+{
+	NTSTATUS status;
+	int s = -1;
+
+	/* we have a connection from a new client, now connect to the server */
+	status = open_socket_out(dest_ss, 445, LONG_CONNECT_TIMEOUT, &s);
+
+	if (s == -1) {
+		char addr[INET6_ADDRSTRLEN];
+		if (dest_ss) {
+			print_sockaddr(addr, sizeof(addr), dest_ss);
+		}
+
+		d_printf("Unable to connect to %s (%s)\n",
+			 dest_ss?addr:"NULL",strerror(errno));
+		exit(1);
+	}
+
+	while (c != -1 || s != -1) {
+		fd_set fds;
+		int num;
+		
+		FD_ZERO(&fds);
+		if (s != -1) FD_SET(s, &fds);
+		if (c != -1) FD_SET(c, &fds);
+
+		num = sys_select_intr(MAX(s+1, c+1),&fds,NULL,NULL,NULL);
+		if (num <= 0) continue;
+		
+		if (c != -1 && FD_ISSET(c, &fds)) {
+			size_t len;
+			if (!NT_STATUS_IS_OK(receive_smb_raw(
+							c, packet, sizeof(packet),
+							0, 0, &len))) {
+				d_printf("client closed connection\n");
+				exit(0);
+			}
+			filter_request(packet);
+			if (!send_smb(s, packet)) {
+				d_printf("server is dead\n");
+				exit(1);
+			}			
+		}
+		if (s != -1 && FD_ISSET(s, &fds)) {
+			size_t len;
+			if (!NT_STATUS_IS_OK(receive_smb_raw(
+							s, packet, sizeof(packet),
+							0, 0, &len))) {
+				d_printf("server closed connection\n");
+				exit(0);
+			}
+			filter_reply(packet);
+			if (!send_smb(c, packet)) {
+				d_printf("client is dead\n");
+				exit(1);
+			}			
+		}
+	}
+	d_printf("Connection closed\n");
+	exit(0);
+}
+
+
+static void start_filter(char *desthost)
+{
+	int s, c;
+	struct sockaddr_storage dest_ss;
+	struct sockaddr_storage my_ss;
+
+	CatchChild();
+
+	/* start listening on port 445 locally */
+
+	zero_sockaddr(&my_ss);
+	s = open_socket_in(SOCK_STREAM, 445, 0, &my_ss, True);
+	
+	if (s == -1) {
+		d_printf("bind failed\n");
+		exit(1);
+	}
+
+	if (listen(s, 5) == -1) {
+		d_printf("listen failed\n");
+	}
+
+	if (!resolve_name(desthost, &dest_ss, 0x20, false)) {
+		d_printf("Unable to resolve host %s\n", desthost);
+		exit(1);
+	}
+
+	while (1) {
+		fd_set fds;
+		int num;
+		struct sockaddr_storage ss;
+		socklen_t in_addrlen = sizeof(ss);
+		
+		FD_ZERO(&fds);
+		FD_SET(s, &fds);
+
+		num = sys_select_intr(s+1,&fds,NULL,NULL,NULL);
+		if (num > 0) {
+			c = accept(s, (struct sockaddr *)&ss, &in_addrlen);
+			if (c != -1) {
+				if (fork() == 0) {
+					close(s);
+					filter_child(c, &dest_ss);
+					exit(0);
+				} else {
+					close(c);
+				}
+			}
+		}
+	}
+}
+
+
+int main(int argc, char *argv[])
+{
+	char *desthost;
+	const char *configfile;
+	TALLOC_CTX *frame = talloc_stackframe();
+
+	load_case_tables();
+
+	setup_logging(argv[0],True);
+
+	configfile = get_dyn_CONFIGFILE();
+
+	if (argc < 2) {
+		fprintf(stderr,"smbfilter <desthost> <netbiosname>\n");
+		exit(1);
+	}
+
+	desthost = argv[1];
+	if (argc > 2) {
+		netbiosname = argv[2];
+	}
+
+	if (!lp_load(configfile,True,False,False,True)) {
+		d_printf("Unable to load config file\n");
+	}
+
+	start_filter(desthost);
+	TALLOC_FREE(frame);
+	return 0;
+}

=== added directory '.pc/security-CVE-2011-0719.patch/source3/winbindd'
=== added file '.pc/security-CVE-2011-0719.patch/source3/winbindd/winbindd_dual.c'
--- .pc/security-CVE-2011-0719.patch/source3/winbindd/winbindd_dual.c	1970-01-01 00:00:00 +0000
+++ .pc/security-CVE-2011-0719.patch/source3/winbindd/winbindd_dual.c	2011-03-02 20:48:44 +0000
@@ -0,0 +1,1550 @@
+/* 
+   Unix SMB/CIFS implementation.
+
+   Winbind child daemons
+
+   Copyright (C) Andrew Tridgell 2002
+   Copyright (C) Volker Lendecke 2004,2005
+
+   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 3 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, see <http://www.gnu.org/licenses/>.
+*/
+
+/*
+ * We fork a child per domain to be able to act non-blocking in the main
+ * winbind daemon. A domain controller thousands of miles away being being
+ * slow replying with a 10.000 user list should not hold up netlogon calls
+ * that can be handled locally.
+ */
+
+#include "includes.h"
+#include "winbindd.h"
+#include "../../nsswitch/libwbclient/wbc_async.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_WINBIND
+
+extern bool override_logfile;
+extern struct winbindd_methods cache_methods;
+
+/* Read some data from a client connection */
+
+static NTSTATUS child_read_request(struct winbindd_cli_state *state)
+{
+	NTSTATUS status;
+
+	/* Read data */
+
+	status = read_data(state->sock, (char *)state->request,
+			   sizeof(*state->request));
+
+	if (!NT_STATUS_IS_OK(status)) {
+		DEBUG(3, ("child_read_request: read_data failed: %s\n",
+			  nt_errstr(status)));
+		return status;
+	}
+
+	if (state->request->extra_len == 0) {
+		state->request->extra_data.data = NULL;
+		return NT_STATUS_OK;
+	}
+
+	DEBUG(10, ("Need to read %d extra bytes\n", (int)state->request->extra_len));
+
+	state->request->extra_data.data =
+		SMB_MALLOC_ARRAY(char, state->request->extra_len + 1);
+
+	if (state->request->extra_data.data == NULL) {
+		DEBUG(0, ("malloc failed\n"));
+		return NT_STATUS_NO_MEMORY;
+	}
+
+	/* Ensure null termination */
+	state->request->extra_data.data[state->request->extra_len] = '\0';
+
+	status= read_data(state->sock, state->request->extra_data.data,
+			  state->request->extra_len);
+
+	if (!NT_STATUS_IS_OK(status)) {
+		DEBUG(0, ("Could not read extra data: %s\n",
+			  nt_errstr(status)));
+	}
+	return status;
+}
+
+/*
+ * Do winbind child async request. This is not simply wb_simple_trans. We have
+ * to do the queueing ourselves because while a request is queued, the child
+ * might have crashed, and we have to re-fork it in the _trigger function.
+ */
+
+struct wb_child_request_state {
+	struct tevent_context *ev;
+	struct winbindd_child *child;
+	struct winbindd_request *request;
+	struct winbindd_response *response;
+};
+
+static bool fork_domain_child(struct winbindd_child *child);
+
+static void wb_child_request_trigger(struct tevent_req *req,
+					    void *private_data);
+static void wb_child_request_done(struct tevent_req *subreq);
+
+struct tevent_req *wb_child_request_send(TALLOC_CTX *mem_ctx,
+					 struct tevent_context *ev,
+					 struct winbindd_child *child,
+					 struct winbindd_request *request)
+{
+	struct tevent_req *req;
+	struct wb_child_request_state *state;
+
+	req = tevent_req_create(mem_ctx, &state,
+				struct wb_child_request_state);
+	if (req == NULL) {
+		return NULL;
+	}
+
+	state->ev = ev;
+	state->child = child;
+	state->request = request;
+
+	if (!tevent_queue_add(child->queue, ev, req,
+			      wb_child_request_trigger, NULL)) {
+		tevent_req_nomem(NULL, req);
+		return tevent_req_post(req, ev);
+	}
+	return req;
+}
+
+static void wb_child_request_trigger(struct tevent_req *req,
+				     void *private_data)
+{
+	struct wb_child_request_state *state = tevent_req_data(
+		req, struct wb_child_request_state);
+	struct tevent_req *subreq;
+
+	if ((state->child->pid == 0) && (!fork_domain_child(state->child))) {
+		tevent_req_error(req, errno);
+		return;
+	}
+
+	subreq = wb_simple_trans_send(state, winbind_event_context(), NULL,
+				      state->child->sock, state->request);
+	if (tevent_req_nomem(subreq, req)) {
+		return;
+	}
+	tevent_req_set_callback(subreq, wb_child_request_done, req);
+
+	if (!tevent_req_set_endtime(req, state->ev,
+				    timeval_current_ofs(300, 0))) {
+		tevent_req_nomem(NULL, req);
+                return;
+        }
+}
+
+static void wb_child_request_done(struct tevent_req *subreq)
+{
+	struct tevent_req *req = tevent_req_callback_data(
+		subreq, struct tevent_req);
+	struct wb_child_request_state *state = tevent_req_data(
+		req, struct wb_child_request_state);
+	int ret, err;
+
+	ret = wb_simple_trans_recv(subreq, state, &state->response, &err);
+	TALLOC_FREE(subreq);
+	if (ret == -1) {
+		tevent_req_error(req, err);
+		return;
+	}
+	tevent_req_done(req);
+}
+
+int wb_child_request_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
+			  struct winbindd_response **presponse, int *err)
+{
+	struct wb_child_request_state *state = tevent_req_data(
+		req, struct wb_child_request_state);
+
+	if (tevent_req_is_unix_error(req, err)) {
+		return -1;
+	}
+	*presponse = talloc_move(mem_ctx, &state->response);
+	return 0;
+}
+
+struct wb_domain_request_state {
+	struct tevent_context *ev;
+	struct winbindd_domain *domain;
+	struct winbindd_request *request;
+	struct winbindd_request *init_req;
+	struct winbindd_response *response;
+};
+
+static void wb_domain_request_gotdc(struct tevent_req *subreq);
+static void wb_domain_request_initialized(struct tevent_req *subreq);
+static void wb_domain_request_done(struct tevent_req *subreq);
+
+struct tevent_req *wb_domain_request_send(TALLOC_CTX *mem_ctx,
+					  struct tevent_context *ev,
+					  struct winbindd_domain *domain,
+					  struct winbindd_request *request)
+{
+	struct tevent_req *req, *subreq;
+	struct wb_domain_request_state *state;
+
+	req = tevent_req_create(mem_ctx, &state,
+				struct wb_domain_request_state);
+	if (req == NULL) {
+		return NULL;
+	}
+
+	if (domain->initialized) {
+		subreq = wb_child_request_send(state, ev, &domain->child,
+					       request);
+		if (tevent_req_nomem(subreq, req)) {
+			return tevent_req_post(req, ev);
+		}
+		tevent_req_set_callback(subreq, wb_domain_request_done, req);
+		return req;
+	}
+
+	state->domain = domain;
+	state->ev = ev;
+	state->request = request;
+
+	state->init_req = talloc_zero(state, struct winbindd_request);
+	if (tevent_req_nomem(state->init_req, req)) {
+		return tevent_req_post(req, ev);
+	}
+
+	if (IS_DC || domain->primary || domain->internal) {
+		/* The primary domain has to find the DC name itself */
+		state->init_req->cmd = WINBINDD_INIT_CONNECTION;
+		fstrcpy(state->init_req->domain_name, domain->name);
+		state->init_req->data.init_conn.is_primary =
+			domain->primary ? true : false;
+		fstrcpy(state->init_req->data.init_conn.dcname, "");
+
+		subreq = wb_child_request_send(state, ev, &domain->child,
+					       state->init_req);
+		if (tevent_req_nomem(subreq, req)) {
+			return tevent_req_post(req, ev);
+		}
+		tevent_req_set_callback(subreq, wb_domain_request_initialized,
+					req);
+		return req;
+	}
+
+	/*
+	 * Ask our DC for a DC name
+	 */
+	domain = find_our_domain();
+
+	/* This is *not* the primary domain, let's ask our DC about a DC
+	 * name */
+
+	state->init_req->cmd = WINBINDD_GETDCNAME;
+	fstrcpy(state->init_req->domain_name, domain->name);
+
+	subreq = wb_child_request_send(state, ev, &domain->child, request);
+	if (tevent_req_nomem(subreq, req)) {
+		return tevent_req_post(req, ev);
+	}
+	tevent_req_set_callback(subreq, wb_domain_request_gotdc, req);
+	return req;
+}
+
+static void wb_domain_request_gotdc(struct tevent_req *subreq)
+{
+	struct tevent_req *req = tevent_req_callback_data(
+		subreq, struct tevent_req);
+	struct wb_domain_request_state *state = tevent_req_data(
+		req, struct wb_domain_request_state);
+	struct winbindd_response *response;
+	int ret, err;
+
+	ret = wb_child_request_recv(subreq, talloc_tos(), &response, &err);
+	TALLOC_FREE(subreq);
+	if (ret == -1) {
+		tevent_req_error(req, err);
+		return;
+	}
+	state->init_req->cmd = WINBINDD_INIT_CONNECTION;
+	fstrcpy(state->init_req->domain_name, state->domain->name);
+	state->init_req->data.init_conn.is_primary = False;
+	fstrcpy(state->init_req->data.init_conn.dcname,
+		response->data.dc_name);
+
+	TALLOC_FREE(response);
+
+	subreq = wb_child_request_send(state, state->ev, &state->domain->child,
+				       state->init_req);
+	if (tevent_req_nomem(subreq, req)) {
+		return;
+	}
+	tevent_req_set_callback(subreq, wb_domain_request_initialized, req);
+}
+
+static void wb_domain_request_initialized(struct tevent_req *subreq)
+{
+	struct tevent_req *req = tevent_req_callback_data(
+		subreq, struct tevent_req);
+	struct wb_domain_request_state *state = tevent_req_data(
+		req, struct wb_domain_request_state);
+	struct winbindd_response *response;
+	int ret, err;
+
+	ret = wb_child_request_recv(subreq, talloc_tos(), &response, &err);
+	TALLOC_FREE(subreq);
+	if (ret == -1) {
+		tevent_req_error(req, err);
+		return;
+	}
+
+	if (!string_to_sid(&state->domain->sid,
+			   response->data.domain_info.sid)) {
+		DEBUG(1,("init_child_recv: Could not convert sid %s "
+			"from string\n", response->data.domain_info.sid));
+		tevent_req_error(req, EINVAL);
+		return;
+	}
+	fstrcpy(state->domain->name, response->data.domain_info.name);
+	fstrcpy(state->domain->alt_name, response->data.domain_info.alt_name);
+	state->domain->native_mode = response->data.domain_info.native_mode;
+	state->domain->active_directory =
+		response->data.domain_info.active_directory;
+	state->domain->initialized = true;
+
+	TALLOC_FREE(response);
+
+	subreq = wb_child_request_send(state, state->ev, &state->domain->child,
+				       state->request);
+	if (tevent_req_nomem(subreq, req)) {
+		return;
+	}
+	tevent_req_set_callback(subreq, wb_domain_request_done, req);
+}
+
+static void wb_domain_request_done(struct tevent_req *subreq)
+{
+	struct tevent_req *req = tevent_req_callback_data(
+		subreq, struct tevent_req);
+	struct wb_domain_request_state *state = tevent_req_data(
+		req, struct wb_domain_request_state);
+	int ret, err;
+
+	ret = wb_child_request_recv(subreq, talloc_tos(), &state->response,
+				    &err);
+	TALLOC_FREE(subreq);
+	if (ret == -1) {
+		tevent_req_error(req, err);
+		return;
+	}
+	tevent_req_done(req);
+}
+
+int wb_domain_request_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
+			   struct winbindd_response **presponse, int *err)
+{
+	struct wb_domain_request_state *state = tevent_req_data(
+		req, struct wb_domain_request_state);
+
+	if (tevent_req_is_unix_error(req, err)) {
+		return -1;
+	}
+	*presponse = talloc_move(mem_ctx, &state->response);
+	return 0;
+}
+
+struct domain_request_state {
+	struct winbindd_domain *domain;
+	struct winbindd_request *request;
+	struct winbindd_response *response;
+	void (*continuation)(void *private_data_data, bool success);
+	void *private_data_data;
+};
+
+static void async_domain_request_done(struct tevent_req *req);
+
+void async_domain_request(TALLOC_CTX *mem_ctx,
+			  struct winbindd_domain *domain,
+			  struct winbindd_request *request,
+			  struct winbindd_response *response,
+			  void (*continuation)(void *private_data_data, bool success),
+			  void *private_data_data)
+{
+	struct tevent_req *subreq;
+	struct domain_request_state *state;
+
+	state = TALLOC_P(mem_ctx, struct domain_request_state);
+	if (state == NULL) {
+		DEBUG(0, ("talloc failed\n"));
+		continuation(private_data_data, False);
+		return;
+	}
+
+	state->domain = domain;
+	state->request = request;
+	state->response = response;
+	state->continuation = continuation;
+	state->private_data_data = private_data_data;
+
+	subreq = wb_domain_request_send(state, winbind_event_context(),
+					domain, request);
+	if (subreq == NULL) {
+		DEBUG(5, ("wb_domain_request_send failed\n"));
+		continuation(private_data_data, false);
+		return;
+	}
+	tevent_req_set_callback(subreq, async_domain_request_done, state);
+}
+
+static void async_domain_request_done(struct tevent_req *req)
+{
+	struct domain_request_state *state = tevent_req_callback_data(
+		req, struct domain_request_state);
+	struct winbindd_response *response;
+	int ret, err;
+
+	ret = wb_domain_request_recv(req, state, &response, &err);
+	TALLOC_FREE(req);
+	if (ret == -1) {
+		DEBUG(5, ("wb_domain_request returned %s\n", strerror(err)));
+		state->continuation(state->private_data_data, false);
+		return;
+	}
+	*(state->response) = *response;
+	state->continuation(state->private_data_data, true);
+}
+
+static void recvfrom_child(void *private_data_data, bool success)
+{
+	struct winbindd_cli_state *state =
+		talloc_get_type_abort(private_data_data, struct winbindd_cli_state);
+	enum winbindd_result result = state->response->result;
+
+	/* This is an optimization: The child has written directly to the
+	 * response buffer. The request itself is still in pending state,
+	 * state that in the result code. */
+
+	state->response->result = WINBINDD_PENDING;
+
+	if ((!success) || (result != WINBINDD_OK)) {
+		request_error(state);
+		return;
+	}
+
+	request_ok(state);
+}
+
+void sendto_domain(struct winbindd_cli_state *state,
+		   struct winbindd_domain *domain)
+{
+	async_domain_request(state->mem_ctx, domain,
+			     state->request, state->response,
+			     recvfrom_child, state);
+}
+
+static void child_process_request(struct winbindd_child *child,
+				  struct winbindd_cli_state *state)
+{
+	struct winbindd_domain *domain = child->domain;
+	const struct winbindd_child_dispatch_table *table = child->table;
+
+	/* Free response data - we may be interrupted and receive another
+	   command before being able to send this data off. */
+
+	state->response->result = WINBINDD_ERROR;
+	state->response->length = sizeof(struct winbindd_response);
+
+	/* as all requests in the child are sync, we can use talloc_tos() */
+	state->mem_ctx = talloc_tos();
+
+	/* Process command */
+
+	for (; table->name; table++) {
+		if (state->request->cmd == table->struct_cmd) {
+			DEBUG(10,("child_process_request: request fn %s\n",
+				  table->name));
+			state->response->result = table->struct_fn(domain, state);
+			return;
+		}
+	}
+
+	DEBUG(1 ,("child_process_request: unknown request fn number %d\n",
+		  (int)state->request->cmd));
+	state->response->result = WINBINDD_ERROR;
+}
+
+void setup_child(struct winbindd_domain *domain, struct winbindd_child *child,
+		 const struct winbindd_child_dispatch_table *table,
+		 const char *logprefix,
+		 const char *logname)
+{
+	if (logprefix && logname) {
+		if (asprintf(&child->logfilename, "%s/%s-%s",
+			     get_dyn_LOGFILEBASE(), logprefix, logname) < 0) {
+			smb_panic("Internal error: asprintf failed");
+		}
+	} else {
+		smb_panic("Internal error: logprefix == NULL && "
+			  "logname == NULL");
+	}
+
+	child->domain = domain;
+	child->table = table;
+	child->queue = tevent_queue_create(NULL, "winbind_child");
+	SMB_ASSERT(child->queue != NULL);
+	child->rpccli = wbint_rpccli_create(NULL, domain, child);
+	SMB_ASSERT(child->rpccli != NULL);
+}
+
+struct winbindd_child *children = NULL;
+
+void winbind_child_died(pid_t pid)
+{
+	struct winbindd_child *child;
+
+	for (child = children; child != NULL; child = child->next) {
+		if (child->pid == pid) {
+			break;
+		}
+	}
+
+	if (child == NULL) {
+		DEBUG(5, ("Already reaped child %u died\n", (unsigned int)pid));
+		return;
+	}
+
+	/* This will be re-added in fork_domain_child() */
+
+	DLIST_REMOVE(children, child);
+
+	close(child->sock);
+	child->sock = -1;
+	child->pid = 0;
+}
+
+/* Ensure any negative cache entries with the netbios or realm names are removed. */
+
+void winbindd_flush_negative_conn_cache(struct winbindd_domain *domain)
+{
+	flush_negative_conn_cache_for_domain(domain->name);
+	if (*domain->alt_name) {
+		flush_negative_conn_cache_for_domain(domain->alt_name);
+	}
+}
+
+/* 
+ * Parent winbindd process sets its own debug level first and then
+ * sends a message to all the winbindd children to adjust their debug
+ * level to that of parents.
+ */
+
+void winbind_msg_debug(struct messaging_context *msg_ctx,
+ 			 void *private_data,
+			 uint32_t msg_type,
+			 struct server_id server_id,
+			 DATA_BLOB *data)
+{
+	struct winbindd_child *child;
+
+	DEBUG(10,("winbind_msg_debug: got debug message.\n"));
+
+	debug_message(msg_ctx, private_data, MSG_DEBUG, server_id, data);
+
+	for (child = children; child != NULL; child = child->next) {
+
+		DEBUG(10,("winbind_msg_debug: sending message to pid %u.\n",
+			(unsigned int)child->pid));
+
+		messaging_send_buf(msg_ctx, pid_to_procid(child->pid),
+			   MSG_DEBUG,
+			   data->data,
+			   strlen((char *) data->data) + 1);
+	}
+}
+
+/* Set our domains as offline and forward the offline message to our children. */
+
+void winbind_msg_offline(struct messaging_context *msg_ctx,
+			 void *private_data,
+			 uint32_t msg_type,
+			 struct server_id server_id,
+			 DATA_BLOB *data)
+{
+	struct winbindd_child *child;
+	struct winbindd_domain *domain;
+
+	DEBUG(10,("winbind_msg_offline: got offline message.\n"));
+
+	if (!lp_winbind_offline_logon()) {
+		DEBUG(10,("winbind_msg_offline: rejecting offline message.\n"));
+		return;
+	}
+
+	/* Set our global state as offline. */
+	if (!set_global_winbindd_state_offline()) {
+		DEBUG(10,("winbind_msg_offline: offline request failed.\n"));
+		return;
+	}
+
+	/* Set all our domains as offline. */
+	for (domain = domain_list(); domain; domain = domain->next) {
+		if (domain->internal) {
+			continue;
+		}
+		DEBUG(5,("winbind_msg_offline: marking %s offline.\n", domain->name));
+		set_domain_offline(domain);
+	}
+
+	for (child = children; child != NULL; child = child->next) {
+		/* Don't send message to internal childs.  We've already
+		   done so above. */
+		if (!child->domain || winbindd_internal_child(child)) {
+			continue;
+		}
+
+		/* Or internal domains (this should not be possible....) */
+		if (child->domain->internal) {
+			continue;
+		}
+
+		/* Each winbindd child should only process requests for one domain - make sure
+		   we only set it online / offline for that domain. */
+
+		DEBUG(10,("winbind_msg_offline: sending message to pid %u for domain %s.\n",
+			(unsigned int)child->pid, domain->name ));
+
+		messaging_send_buf(msg_ctx, pid_to_procid(child->pid),
+				   MSG_WINBIND_OFFLINE,
+				   (uint8 *)child->domain->name,
+				   strlen(child->domain->name)+1);
+	}
+}
+
+/* Set our domains as online and forward the online message to our children. */
+
+void winbind_msg_online(struct messaging_context *msg_ctx,
+			void *private_data,
+			uint32_t msg_type,
+			struct server_id server_id,
+			DATA_BLOB *data)
+{
+	struct winbindd_child *child;
+	struct winbindd_domain *domain;
+
+	DEBUG(10,("winbind_msg_online: got online message.\n"));
+
+	if (!lp_winbind_offline_logon()) {
+		DEBUG(10,("winbind_msg_online: rejecting online message.\n"));
+		return;
+	}
+
+	/* Set our global state as online. */
+	set_global_winbindd_state_online();
+
+	smb_nscd_flush_user_cache();
+	smb_nscd_flush_group_cache();
+
+	/* Set all our domains as online. */
+	for (domain = domain_list(); domain; domain = domain->next) {
+		if (domain->internal) {
+			continue;
+		}
+		DEBUG(5,("winbind_msg_online: requesting %s to go online.\n", domain->name));
+
+		winbindd_flush_negative_conn_cache(domain);
+		set_domain_online_request(domain);
+
+		/* Send an online message to the idmap child when our
+		   primary domain comes back online */
+
+		if ( domain->primary ) {
+			struct winbindd_child *idmap = idmap_child();
+
+			if ( idmap->pid != 0 ) {
+				messaging_send_buf(msg_ctx,
+						   pid_to_procid(idmap->pid), 
+						   MSG_WINBIND_ONLINE,
+						   (uint8 *)domain->name,
+						   strlen(domain->name)+1);
+			}
+		}
+	}
+
+	for (child = children; child != NULL; child = child->next) {
+		/* Don't send message to internal childs. */
+		if (!child->domain || winbindd_internal_child(child)) {
+			continue;
+		}
+
+		/* Or internal domains (this should not be possible....) */
+		if (child->domain->internal) {
+			continue;
+		}
+
+		/* Each winbindd child should only process requests for one domain - make sure
+		   we only set it online / offline for that domain. */
+
+		DEBUG(10,("winbind_msg_online: sending message to pid %u for domain %s.\n",
+			(unsigned int)child->pid, child->domain->name ));
+
+		messaging_send_buf(msg_ctx, pid_to_procid(child->pid),
+				   MSG_WINBIND_ONLINE,
+				   (uint8 *)child->domain->name,
+				   strlen(child->domain->name)+1);
+	}
+}
+
+static const char *collect_onlinestatus(TALLOC_CTX *mem_ctx)
+{
+	struct winbindd_domain *domain;
+	char *buf = NULL;
+
+	if ((buf = talloc_asprintf(mem_ctx, "global:%s ", 
+				   get_global_winbindd_state_offline() ? 
+				   "Offline":"Online")) == NULL) {
+		return NULL;
+	}
+
+	for (domain = domain_list(); domain; domain = domain->next) {
+		if ((buf = talloc_asprintf_append_buffer(buf, "%s:%s ", 
+						  domain->name, 
+						  domain->online ?
+						  "Online":"Offline")) == NULL) {
+			return NULL;
+		}
+	}
+
+	buf = talloc_asprintf_append_buffer(buf, "\n");
+
+	DEBUG(5,("collect_onlinestatus: %s", buf));
+
+	return buf;
+}
+
+void winbind_msg_onlinestatus(struct messaging_context *msg_ctx,
+			      void *private_data,
+			      uint32_t msg_type,
+			      struct server_id server_id,
+			      DATA_BLOB *data)
+{
+	TALLOC_CTX *mem_ctx;
+	const char *message;
+	struct server_id *sender;
+
+	DEBUG(5,("winbind_msg_onlinestatus received.\n"));
+
+	if (!data->data) {
+		return;
+	}
+
+	sender = (struct server_id *)data->data;
+
+	mem_ctx = talloc_init("winbind_msg_onlinestatus");
+	if (mem_ctx == NULL) {
+		return;
+	}
+
+	message = collect_onlinestatus(mem_ctx);
+	if (message == NULL) {
+		talloc_destroy(mem_ctx);
+		return;
+	}
+
+	messaging_send_buf(msg_ctx, *sender, MSG_WINBIND_ONLINESTATUS, 
+			   (uint8 *)message, strlen(message) + 1);
+
+	talloc_destroy(mem_ctx);
+}
+
+void winbind_msg_dump_event_list(struct messaging_context *msg_ctx,
+				 void *private_data,
+				 uint32_t msg_type,
+				 struct server_id server_id,
+				 DATA_BLOB *data)
+{
+	struct winbindd_child *child;
+
+	DEBUG(10,("winbind_msg_dump_event_list received\n"));
+
+	dump_event_list(winbind_event_context());
+
+	for (child = children; child != NULL; child = child->next) {
+
+		DEBUG(10,("winbind_msg_dump_event_list: sending message to pid %u\n",
+			(unsigned int)child->pid));
+
+		messaging_send_buf(msg_ctx, pid_to_procid(child->pid),
+				   MSG_DUMP_EVENT_LIST,
+				   NULL, 0);
+	}
+
+}
+
+void winbind_msg_dump_domain_list(struct messaging_context *msg_ctx,
+				  void *private_data,
+				  uint32_t msg_type,
+				  struct server_id server_id,
+				  DATA_BLOB *data)
+{
+	TALLOC_CTX *mem_ctx;
+	const char *message = NULL;
+	struct server_id *sender = NULL;
+	const char *domain = NULL;
+	char *s = NULL;
+	NTSTATUS status;
+	struct winbindd_domain *dom = NULL;
+
+	DEBUG(5,("winbind_msg_dump_domain_list received.\n"));
+
+	if (!data || !data->data) {
+		return;
+	}
+
+	if (data->length < sizeof(struct server_id)) {
+		return;
+	}
+
+	mem_ctx = talloc_init("winbind_msg_dump_domain_list");
+	if (!mem_ctx) {
+		return;
+	}
+
+	sender = (struct server_id *)data->data;
+	if (data->length > sizeof(struct server_id)) {
+		domain = (const char *)data->data+sizeof(struct server_id);
+	}
+
+	if (domain) {
+
+		DEBUG(5,("winbind_msg_dump_domain_list for domain: %s\n",
+			domain));
+
+		message = NDR_PRINT_STRUCT_STRING(mem_ctx, winbindd_domain,
+						  find_domain_from_name_noinit(domain));
+		if (!message) {
+			talloc_destroy(mem_ctx);
+			return;
+		}
+
+		messaging_send_buf(msg_ctx, *sender,
+				   MSG_WINBIND_DUMP_DOMAIN_LIST,
+				   (uint8_t *)message, strlen(message) + 1);
+
+		talloc_destroy(mem_ctx);
+
+		return;
+	}
+
+	DEBUG(5,("winbind_msg_dump_domain_list all domains\n"));
+
+	for (dom = domain_list(); dom; dom=dom->next) {
+		message = NDR_PRINT_STRUCT_STRING(mem_ctx, winbindd_domain, dom);
+		if (!message) {
+			talloc_destroy(mem_ctx);
+			return;
+		}
+
+		s = talloc_asprintf_append(s, "%s\n", message);
+		if (!s) {
+			talloc_destroy(mem_ctx);
+			return;
+		}
+	}
+
+	status = messaging_send_buf(msg_ctx, *sender,
+				    MSG_WINBIND_DUMP_DOMAIN_LIST,
+				    (uint8_t *)s, strlen(s) + 1);
+	if (!NT_STATUS_IS_OK(status)) {
+		DEBUG(0,("failed to send message: %s\n",
+		nt_errstr(status)));
+	}
+
+	talloc_destroy(mem_ctx);
+}
+
+static void account_lockout_policy_handler(struct event_context *ctx,
+					   struct timed_event *te,
+					   struct timeval now,
+					   void *private_data)
+{
+	struct winbindd_child *child =
+		(struct winbindd_child *)private_data;
+	TALLOC_CTX *mem_ctx = NULL;
+	struct winbindd_methods *methods;
+	struct samr_DomInfo12 lockout_policy;
+	NTSTATUS result;
+
+	DEBUG(10,("account_lockout_policy_handler called\n"));
+
+	TALLOC_FREE(child->lockout_policy_event);
+
+	if ( !winbindd_can_contact_domain( child->domain ) ) {
+		DEBUG(10,("account_lockout_policy_handler: Removing myself since I "
+			  "do not have an incoming trust to domain %s\n", 
+			  child->domain->name));
+
+		return;		
+	}
+
+	methods = child->domain->methods;
+
+	mem_ctx = talloc_init("account_lockout_policy_handler ctx");
+	if (!mem_ctx) {
+		result = NT_STATUS_NO_MEMORY;
+	} else {
+		result = methods->lockout_policy(child->domain, mem_ctx, &lockout_policy);
+	}
+	TALLOC_FREE(mem_ctx);
+
+	if (!NT_STATUS_IS_OK(result)) {
+		DEBUG(10,("account_lockout_policy_handler: lockout_policy failed error %s\n",
+			 nt_errstr(result)));
+	}
+
+	child->lockout_policy_event = event_add_timed(winbind_event_context(), NULL,
+						      timeval_current_ofs(3600, 0),
+						      account_lockout_policy_handler,
+						      child);
+}
+
+static time_t get_machine_password_timeout(void)
+{
+	/* until we have gpo support use lp setting */
+	return lp_machine_password_timeout();
+}
+
+static bool calculate_next_machine_pwd_change(const char *domain,
+					      struct timeval *t)
+{
+	time_t pass_last_set_time;
+	time_t timeout;
+	time_t next_change;
+	struct timeval tv;
+	char *pw;
+
+	pw = secrets_fetch_machine_password(domain,
+					    &pass_last_set_time,
+					    NULL);
+
+	if (pw == NULL) {
+		DEBUG(0,("cannot fetch own machine password ????"));
+		return false;
+	}
+
+	SAFE_FREE(pw);
+
+	timeout = get_machine_password_timeout();
+	if (timeout == 0) {
+		DEBUG(10,("machine password never expires\n"));
+		return false;
+	}
+
+	tv.tv_sec = pass_last_set_time;
+	DEBUG(10, ("password last changed %s\n",
+		   timeval_string(talloc_tos(), &tv, false)));
+	tv.tv_sec += timeout;
+	DEBUGADD(10, ("password valid until %s\n",
+		      timeval_string(talloc_tos(), &tv, false)));
+
+	if (time(NULL) < (pass_last_set_time + timeout)) {
+		next_change = pass_last_set_time + timeout;
+		DEBUG(10,("machine password still valid until: %s\n",
+			http_timestring(talloc_tos(), next_change)));
+		*t = timeval_set(next_change, 0);
+
+		if (lp_clustering()) {
+			uint8_t randbuf;
+			/*
+			 * When having a cluster, we have several
+			 * winbinds racing for the password change. In
+			 * the machine_password_change_handler()
+			 * function we check if someone else was
+			 * faster when the event triggers. We add a
+			 * 255-second random delay here, so that we
+			 * don't run to change the password at the
+			 * exact same moment.
+			 */
+			generate_random_buffer(&randbuf, sizeof(randbuf));
+			DEBUG(10, ("adding %d seconds randomness\n",
+				   (int)randbuf));
+			t->tv_sec += randbuf;
+		}
+		return true;
+	}
+
+	DEBUG(10,("machine password expired, needs immediate change\n"));
+
+	*t = timeval_zero();
+
+	return true;
+}
+
+static void machine_password_change_handler(struct event_context *ctx,
+					    struct timed_event *te,
+					    struct timeval now,
+					    void *private_data)
+{
+	struct winbindd_child *child =
+		(struct winbindd_child *)private_data;
+	struct rpc_pipe_client *netlogon_pipe = NULL;
+	TALLOC_CTX *frame;
+	NTSTATUS result;
+	struct timeval next_change;
+
+	DEBUG(10,("machine_password_change_handler called\n"));
+
+	TALLOC_FREE(child->machine_password_change_event);
+
+	if (!calculate_next_machine_pwd_change(child->domain->name,
+					       &next_change)) {
+		DEBUG(10, ("calculate_next_machine_pwd_change failed\n"));
+		return;
+	}
+
+	DEBUG(10, ("calculate_next_machine_pwd_change returned %s\n",
+		   timeval_string(talloc_tos(), &next_change, false)));
+
+	if (!timeval_expired(&next_change)) {
+		DEBUG(10, ("Someone else has already changed the pw\n"));
+		goto done;
+	}
+
+	if (!winbindd_can_contact_domain(child->domain)) {
+		DEBUG(10,("machine_password_change_handler: Removing myself since I "
+			  "do not have an incoming trust to domain %s\n",
+			  child->domain->name));
+		return;
+	}
+
+	result = cm_connect_netlogon(child->domain, &netlogon_pipe);
+	if (!NT_STATUS_IS_OK(result)) {
+		DEBUG(10,("machine_password_change_handler: "
+			"failed to connect netlogon pipe: %s\n",
+			 nt_errstr(result)));
+		return;
+	}
+
+	frame = talloc_stackframe();
+
+	result = trust_pw_find_change_and_store_it(netlogon_pipe,
+						   frame,
+						   child->domain->name);
+	TALLOC_FREE(frame);
+
+	DEBUG(10, ("machine_password_change_handler: "
+		   "trust_pw_find_change_and_store_it returned %s\n",
+		   nt_errstr(result)));
+
+	if (NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED) ) {
+		DEBUG(3,("machine_password_change_handler: password set returned "
+			 "ACCESS_DENIED.  Maybe the trust account "
+			 "password was changed and we didn't know it. "
+			 "Killing connections to domain %s\n",
+			 child->domain->name));
+		TALLOC_FREE(child->domain->conn.netlogon_pipe);
+	}
+
+	if (!calculate_next_machine_pwd_change(child->domain->name,
+					       &next_change)) {
+		DEBUG(10, ("calculate_next_machine_pwd_change failed\n"));
+		return;
+	}
+
+	DEBUG(10, ("calculate_next_machine_pwd_change returned %s\n",
+		   timeval_string(talloc_tos(), &next_change, false)));
+
+	if (!NT_STATUS_IS_OK(result)) {
+		struct timeval tmp;
+		/*
+		 * In case of failure, give the DC a minute to recover
+		 */
+		tmp = timeval_current_ofs(60, 0);
+		next_change = timeval_max(&next_change, &tmp);
+	}
+
+done:
+	child->machine_password_change_event = event_add_timed(winbind_event_context(), NULL,
+							      next_change,
+							      machine_password_change_handler,
+							      child);
+}
+
+/* Deal with a request to go offline. */
+
+static void child_msg_offline(struct messaging_context *msg,
+			      void *private_data,
+			      uint32_t msg_type,
+			      struct server_id server_id,
+			      DATA_BLOB *data)
+{
+	struct winbindd_domain *domain;
+	struct winbindd_domain *primary_domain = NULL;
+	const char *domainname = (const char *)data->data;
+
+	if (data->data == NULL || data->length == 0) {
+		return;
+	}
+
+	DEBUG(5,("child_msg_offline received for domain %s.\n", domainname));
+
+	if (!lp_winbind_offline_logon()) {
+		DEBUG(10,("child_msg_offline: rejecting offline message.\n"));
+		return;
+	}
+
+	primary_domain = find_our_domain();
+
+	/* Mark the requested domain offline. */
+
+	for (domain = domain_list(); domain; domain = domain->next) {
+		if (domain->internal) {
+			continue;
+		}
+		if (strequal(domain->name, domainname)) {
+			DEBUG(5,("child_msg_offline: marking %s offline.\n", domain->name));
+			set_domain_offline(domain);
+			/* we are in the trusted domain, set the primary domain 
+			 * offline too */
+			if (domain != primary_domain) {
+				set_domain_offline(primary_domain);
+			}
+		}
+	}
+}
+
+/* Deal with a request to go online. */
+
+static void child_msg_online(struct messaging_context *msg,
+			     void *private_data,
+			     uint32_t msg_type,
+			     struct server_id server_id,
+			     DATA_BLOB *data)
+{
+	struct winbindd_domain *domain;
+	struct winbindd_domain *primary_domain = NULL;
+	const char *domainname = (const char *)data->data;
+
+	if (data->data == NULL || data->length == 0) {
+		return;
+	}
+
+	DEBUG(5,("child_msg_online received for domain %s.\n", domainname));
+
+	if (!lp_winbind_offline_logon()) {
+		DEBUG(10,("child_msg_online: rejecting online message.\n"));
+		return;
+	}
+
+	primary_domain = find_our_domain();
+
+	/* Set our global state as online. */
+	set_global_winbindd_state_online();
+
+	/* Try and mark everything online - delete any negative cache entries
+	   to force a reconnect now. */
+
+	for (domain = domain_list(); domain; domain = domain->next) {
+		if (domain->internal) {
+			continue;
+		}
+		if (strequal(domain->name, domainname)) {
+			DEBUG(5,("child_msg_online: requesting %s to go online.\n", domain->name));
+			winbindd_flush_negative_conn_cache(domain);
+			set_domain_online_request(domain);
+
+			/* we can be in trusted domain, which will contact primary domain
+			 * we have to bring primary domain online in trusted domain process
+			 * see, winbindd_dual_pam_auth() --> winbindd_dual_pam_auth_samlogon()
+			 * --> contact_domain = find_our_domain()
+			 * */
+			if (domain != primary_domain) {
+				winbindd_flush_negative_conn_cache(primary_domain);
+				set_domain_online_request(primary_domain);
+			}
+		}
+	}
+}
+
+static void child_msg_dump_event_list(struct messaging_context *msg,
+				      void *private_data,
+				      uint32_t msg_type,
+				      struct server_id server_id,
+				      DATA_BLOB *data)
+{
+	DEBUG(5,("child_msg_dump_event_list received\n"));
+
+	dump_event_list(winbind_event_context());
+}
+
+bool winbindd_reinit_after_fork(const char *logfilename)
+{
+	struct winbindd_domain *domain;
+	struct winbindd_child *cl;
+
+	if (!NT_STATUS_IS_OK(reinit_after_fork(winbind_messaging_context(),
+					       winbind_event_context(),
+					       true))) {
+		DEBUG(0,("reinit_after_fork() failed\n"));
+		return false;
+	}
+
+	close_conns_after_fork();
+
+	if (!override_logfile && logfilename) {
+		lp_set_logfile(logfilename);
+		reopen_logs();
+	}
+
+	if (!winbindd_setup_sig_term_handler(false))
+		return false;
+	if (!winbindd_setup_sig_hup_handler(override_logfile ? NULL :
+					    logfilename))
+		return false;
+
+	/* Stop zombies in children */
+	CatchChild();
+
+	/* Don't handle the same messages as our parent. */
+	messaging_deregister(winbind_messaging_context(),
+			     MSG_SMB_CONF_UPDATED, NULL);
+	messaging_deregister(winbind_messaging_context(),
+			     MSG_SHUTDOWN, NULL);
+	messaging_deregister(winbind_messaging_context(),
+			     MSG_WINBIND_OFFLINE, NULL);
+	messaging_deregister(winbind_messaging_context(),
+			     MSG_WINBIND_ONLINE, NULL);
+	messaging_deregister(winbind_messaging_context(),
+			     MSG_WINBIND_ONLINESTATUS, NULL);
+	messaging_deregister(winbind_messaging_context(),
+			     MSG_DUMP_EVENT_LIST, NULL);
+	messaging_deregister(winbind_messaging_context(),
+			     MSG_WINBIND_DUMP_DOMAIN_LIST, NULL);
+	messaging_deregister(winbind_messaging_context(),
+			     MSG_DEBUG, NULL);
+
+	/* We have destroyed all events in the winbindd_event_context
+	 * in reinit_after_fork(), so clean out all possible pending
+	 * event pointers. */
+
+	/* Deal with check_online_events. */
+
+	for (domain = domain_list(); domain; domain = domain->next) {
+		TALLOC_FREE(domain->check_online_event);
+	}
+
+	/* Ensure we're not handling a credential cache event inherited
+	 * from our parent. */
+
+	ccache_remove_all_after_fork();
+
+	/* Destroy all possible events in child list. */
+	for (cl = children; cl != NULL; cl = cl->next) {
+		TALLOC_FREE(cl->lockout_policy_event);
+		TALLOC_FREE(cl->machine_password_change_event);
+
+		/* Children should never be able to send
+		 * each other messages, all messages must
+		 * go through the parent.
+		 */
+		cl->pid = (pid_t)0;
+        }
+	/*
+	 * This is a little tricky, children must not
+	 * send an MSG_WINBIND_ONLINE message to idmap_child().
+	 * If we are in a child of our primary domain or
+	 * in the process created by fork_child_dc_connect(),
+	 * and the primary domain cannot go online,
+	 * fork_child_dc_connection() sends MSG_WINBIND_ONLINE
+	 * periodically to idmap_child().
+	 *
+	 * The sequence is, fork_child_dc_connect() ---> getdcs() --->
+	 * get_dc_name_via_netlogon() ---> cm_connect_netlogon()
+	 * ---> init_dc_connection() ---> cm_open_connection --->
+	 * set_domain_online(), sends MSG_WINBIND_ONLINE to
+	 * idmap_child(). Disallow children sending messages
+	 * to each other, all messages must go through the parent.
+	 */
+	cl = idmap_child();
+	cl->pid = (pid_t)0;
+
+	return true;
+}
+
+/*
+ * In a child there will be only one domain, reference that here.
+ */
+static struct winbindd_domain *child_domain;
+
+struct winbindd_domain *wb_child_domain(void)
+{
+	return child_domain;
+}
+
+static bool fork_domain_child(struct winbindd_child *child)
+{
+	int fdpair[2];
+	struct winbindd_cli_state state;
+	struct winbindd_request request;
+	struct winbindd_response response;
+	struct winbindd_domain *primary_domain = NULL;
+
+	if (child->domain) {
+		DEBUG(10, ("fork_domain_child called for domain '%s'\n",
+			   child->domain->name));
+	} else {
+		DEBUG(10, ("fork_domain_child called without domain.\n"));
+	}
+	child_domain = child->domain;
+
+	if (socketpair(AF_UNIX, SOCK_STREAM, 0, fdpair) != 0) {
+		DEBUG(0, ("Could not open child pipe: %s\n",
+			  strerror(errno)));
+		return False;
+	}
+
+	ZERO_STRUCT(state);
+	state.pid = sys_getpid();
+	state.request = &request;
+	state.response = &response;
+
+	child->pid = sys_fork();
+
+	if (child->pid == -1) {
+		DEBUG(0, ("Could not fork: %s\n", strerror(errno)));
+		return False;
+	}
+
+	if (child->pid != 0) {
+		/* Parent */
+		close(fdpair[0]);
+		child->next = child->prev = NULL;
+		DLIST_ADD(children, child);
+		child->sock = fdpair[1];
+		return True;
+	}
+
+	/* Child */
+
+	DEBUG(10, ("Child process %d\n", (int)sys_getpid()));
+
+	state.sock = fdpair[0];
+	close(fdpair[1]);
+
+	if (!winbindd_reinit_after_fork(child->logfilename)) {
+		_exit(0);
+	}
+
+	/* Handle online/offline messages. */
+	messaging_register(winbind_messaging_context(), NULL,
+			   MSG_WINBIND_OFFLINE, child_msg_offline);
+	messaging_register(winbind_messaging_context(), NULL,
+			   MSG_WINBIND_ONLINE, child_msg_online);
+	messaging_register(winbind_messaging_context(), NULL,
+			   MSG_DUMP_EVENT_LIST, child_msg_dump_event_list);
+	messaging_register(winbind_messaging_context(), NULL,
+			   MSG_DEBUG, debug_message);
+
+	primary_domain = find_our_domain();
+
+	if (primary_domain == NULL) {
+		smb_panic("no primary domain found");
+	}
+
+	/* It doesn't matter if we allow cache login,
+	 * try to bring domain online after fork. */
+	if ( child->domain ) {
+		child->domain->startup = True;
+		child->domain->startup_time = time(NULL);
+		/* we can be in primary domain or in trusted domain
+		 * If we are in trusted domain, set the primary domain
+		 * in start-up mode */
+		if (!(child->domain->internal)) {
+			set_domain_online_request(child->domain);
+			if (!(child->domain->primary)) {
+				primary_domain->startup = True;
+				primary_domain->startup_time = time(NULL);
+				set_domain_online_request(primary_domain);
+			}
+		}
+	}
+
+	/*
+	 * We are in idmap child, make sure that we set the
+	 * check_online_event to bring primary domain online.
+	 */
+	if (child == idmap_child()) {
+		set_domain_online_request(primary_domain);
+	}
+
+	/* We might be in the idmap child...*/
+	if (child->domain && !(child->domain->internal) &&
+	    lp_winbind_offline_logon()) {
+
+		set_domain_online_request(child->domain);
+
+		if (primary_domain && (primary_domain != child->domain)) {
+			/* We need to talk to the primary
+			 * domain as well as the trusted
+			 * domain inside a trusted domain
+			 * child.
+			 * See the code in :
+			 * set_dc_type_and_flags_trustinfo()
+			 * for details.
+			 */
+			set_domain_online_request(primary_domain);
+		}
+
+		child->lockout_policy_event = event_add_timed(
+			winbind_event_context(), NULL, timeval_zero(),
+			account_lockout_policy_handler,
+			child);
+	}
+
+	if (child->domain && child->domain->primary &&
+	    !USE_KERBEROS_KEYTAB &&
+	    lp_server_role() == ROLE_DOMAIN_MEMBER) {
+
+		struct timeval next_change;
+
+		if (calculate_next_machine_pwd_change(child->domain->name,
+						       &next_change)) {
+			child->machine_password_change_event = event_add_timed(
+				winbind_event_context(), NULL, next_change,
+				machine_password_change_handler,
+				child);
+		}
+	}
+
+	while (1) {
+
+		int ret;
+		fd_set r_fds;
+		fd_set w_fds;
+		int maxfd;
+		struct timeval t;
+		struct timeval *tp;
+		struct timeval now;
+		TALLOC_CTX *frame = talloc_stackframe();
+		struct iovec iov[2];
+		int iov_count;
+		NTSTATUS status;
+
+		if (run_events(winbind_event_context(), 0, NULL, NULL)) {
+			TALLOC_FREE(frame);
+			continue;
+		}
+
+		GetTimeOfDay(&now);
+
+		if (child->domain && child->domain->startup &&
+				(now.tv_sec > child->domain->startup_time + 30)) {
+			/* No longer in "startup" mode. */
+			DEBUG(10,("fork_domain_child: domain %s no longer in 'startup' mode.\n",
+				child->domain->name ));
+			child->domain->startup = False;
+		}
+
+		FD_ZERO(&r_fds);
+		FD_ZERO(&w_fds);
+		FD_SET(state.sock, &r_fds);
+		maxfd = state.sock;
+
+		/*
+		 * Initialize this high as event_add_to_select_args()
+		 * uses a timeval_min() on this and next_event. Fix
+		 * from Roel van Meer <rolek@alt001.com>.
+		 */
+		t.tv_sec = 999999;
+		t.tv_usec = 0;
+
+		event_add_to_select_args(winbind_event_context(), &now,
+					 &r_fds, &w_fds, &t, &maxfd);
+		tp = get_timed_events_timeout(winbind_event_context(), &t);
+		if (tp) {
+			DEBUG(11,("select will use timeout of %u.%u seconds\n",
+				(unsigned int)tp->tv_sec, (unsigned int)tp->tv_usec ));
+		}
+
+		ret = sys_select(maxfd + 1, &r_fds, &w_fds, NULL, tp);
+
+		if (run_events(winbind_event_context(), ret, &r_fds, &w_fds)) {
+			/* We got a signal - continue. */
+			TALLOC_FREE(frame);
+			continue;
+		}
+
+		if (ret == 0) {
+			DEBUG(11,("nothing is ready yet, continue\n"));
+			TALLOC_FREE(frame);
+			continue;
+		}
+
+		if (ret == -1 && errno == EINTR) {
+			/* We got a signal - continue. */
+			TALLOC_FREE(frame);
+			continue;
+		}
+
+		if (ret == -1 && errno != EINTR) {
+			DEBUG(0,("select error occured\n"));
+			TALLOC_FREE(frame);
+			perror("select");
+			_exit(1);
+		}
+
+		/* fetch a request from the main daemon */
+		status = child_read_request(&state);
+
+		if (!NT_STATUS_IS_OK(status)) {
+			/* we lost contact with our parent */
+			_exit(0);
+		}
+
+		DEBUG(4,("child daemon request %d\n", (int)state.request->cmd));
+
+		ZERO_STRUCTP(state.response);
+		state.request->null_term = '\0';
+		state.mem_ctx = frame;
+		child_process_request(child, &state);
+
+		DEBUG(4, ("Finished processing child request %d\n",
+			  (int)state.request->cmd));
+
+		SAFE_FREE(state.request->extra_data.data);
+
+		iov[0].iov_base = (void *)state.response;
+		iov[0].iov_len = sizeof(struct winbindd_response);
+		iov_count = 1;
+
+		if (state.response->length > sizeof(struct winbindd_response)) {
+			iov[1].iov_base =
+				(void *)state.response->extra_data.data;
+			iov[1].iov_len = state.response->length-iov[0].iov_len;
+			iov_count = 2;
+		}
+
+		DEBUG(10, ("Writing %d bytes to parent\n",
+			   (int)state.response->length));
+
+		if (write_data_iov(state.sock, iov, iov_count) !=
+		    state.response->length) {
+			DEBUG(0, ("Could not write result\n"));
+			exit(1);
+		}
+		TALLOC_FREE(frame);
+	}
+}

=== modified file 'debian/changelog'
--- debian/changelog	2010-12-17 10:40:10 +0000
+++ debian/changelog	2011-03-02 20:48:44 +0000
@@ -1,3 +1,21 @@
+samba (2:3.5.4~dfsg-1ubuntu8.4) maverick-proposed; urgency=low
+
+  * debian/patches/ntlm-auth-lp623342.patch: ntlm_auth returns an invalid
+    response key. (LP: #623342) Patch taken from upstream
+    (https://bugzilla.samba.org/show_bug.cgi?id=7568)
+
+ -- Stefano Rivera <stefanor@ubuntu.com>  Wed, 02 Mar 2011 22:35:59 +0200
+
+samba (2:3.5.4~dfsg-1ubuntu8.3) maverick-security; urgency=low
+
+  * SECURITY UPDATE: denial of service via missing range checks on file
+    descriptors
+    - debian/patches/security-CVE-2011-0719.patch: validate miscellaneous
+      file descriptors.
+    - CVE-2011-0719
+
+ -- Marc Deslauriers <marc.deslauriers@ubuntu.com>  Wed, 23 Feb 2011 13:12:33 -0500
+
 samba (2:3.5.4~dfsg-1ubuntu8.2) maverick-proposed; urgency=low
 
   * debian/patches/spnego-auth-win7.patch: SPNEGO auth fails when contacting
@@ -228,6 +246,53 @@
 
  -- Christian Perrier <bubulle@debian.org>  Tue, 04 May 2010 17:13:47 +0200
 
+samba (2:3.5.2~dfsg-1) experimental; urgency=low
+
+  * New upstream release
+  * Bugs fixed upstream:
+    - Fix parsing of the gecos field
+      Closes: #460494
+
+ -- Christian Perrier <bubulle@debian.org>  Thu, 08 Apr 2010 19:48:07 +0200
+
+samba (2:3.5.1~dfsg-1) experimental; urgency=low
+
+  * New upstream release. Security fix: all smbd processes inherited
+    CAP_DAC_OVERRIDE capabilities, allowing all file system access to be
+    allowed even when permissions should have denied access.
+
+ -- Christian Perrier <bubulle@debian.org>  Tue, 09 Mar 2010 10:54:01 +0100
+
+samba (2:3.5.0dfsg-1) experimental; urgency=low
+
+  * New upstream release. Not using "3.5.0~dfsg" as version number
+    because we used a "higher" version number in previous versions.
+
+ -- Christian Perrier <bubulle@debian.org>  Tue, 02 Mar 2010 22:03:15 +0100
+
+samba (2:3.5.0~rc3~dfsg-1) experimental; urgency=low
+
+  * New upstream release candidate
+
+ -- Christian Perrier <bubulle@debian.org>  Sat, 20 Feb 2010 08:36:57 +0100
+
+samba (2:3.5.0~rc2~dfsg-1) experimental; urgency=low
+
+  * New upstream pre-release
+  * Use new --with-codepagedir option. Consequently drop
+    codepages-location.patch
+  * Drop "Using Samba" from the samba-doc file list as it was
+    removed upstream.
+
+ -- Christian Perrier <bubulle@debian.org>  Sun, 31 Jan 2010 11:53:48 +0100
+
+samba (2:3.5.0~rc1~dfsg-1) experimental; urgency=low
+
+  [ Christian Perrier ]
+  * New upstream pre-release
+
+ -- Christian Perrier <bubulle@debian.org>  Fri, 15 Jan 2010 23:31:01 +0100
+
 samba (2:3.4.7~dfsg-2ubuntu1) maverick; urgency=low
 
   * Merge from Debian unstable.  Remaining changes:
@@ -573,53 +638,6 @@
 
  -- Christian Perrier <bubulle@debian.org>  Sat, 23 Jan 2010 12:16:42 +0100
 
-samba (2:3.5.2~dfsg-1) experimental; urgency=low
-
-  * New upstream release
-  * Bugs fixed upstream:
-    - Fix parsing of the gecos field
-      Closes: #460494
-
- -- Christian Perrier <bubulle@debian.org>  Thu, 08 Apr 2010 19:48:07 +0200
-
-samba (2:3.5.1~dfsg-1) experimental; urgency=low
-
-  * New upstream release. Security fix: all smbd processes inherited
-    CAP_DAC_OVERRIDE capabilities, allowing all file system access to be
-    allowed even when permissions should have denied access.
-
- -- Christian Perrier <bubulle@debian.org>  Tue, 09 Mar 2010 10:54:01 +0100
-
-samba (2:3.5.0dfsg-1) experimental; urgency=low
-
-  * New upstream release. Not using "3.5.0~dfsg" as version number
-    because we used a "higher" version number in previous versions.
-
- -- Christian Perrier <bubulle@debian.org>  Tue, 02 Mar 2010 22:03:15 +0100
-
-samba (2:3.5.0~rc3~dfsg-1) experimental; urgency=low
-
-  * New upstream release candidate
-
- -- Christian Perrier <bubulle@debian.org>  Sat, 20 Feb 2010 08:36:57 +0100
-
-samba (2:3.5.0~rc2~dfsg-1) experimental; urgency=low
-
-  * New upstream pre-release
-  * Use new --with-codepagedir option. Consequently drop
-    codepages-location.patch
-  * Drop "Using Samba" from the samba-doc file list as it was
-    removed upstream.
-
- -- Christian Perrier <bubulle@debian.org>  Sun, 31 Jan 2010 11:53:48 +0100
-
-samba (2:3.5.0~rc1~dfsg-1) experimental; urgency=low
-
-  [ Christian Perrier ]
-  * New upstream pre-release
-
- -- Christian Perrier <bubulle@debian.org>  Fri, 15 Jan 2010 23:31:01 +0100
-
 samba (2:3.4.4~dfsg-1) unstable; urgency=low
 
   * New upstream version.
@@ -1568,6 +1586,137 @@
 
  -- Christian Perrier <bubulle@debian.org>  Sat, 14 Feb 2009 13:38:14 +0100
 
+samba (2:3.3.0-1) experimental; urgency=low
+
+  * New upstream release. Fixes the following bugs:
+    - smb file deletion gvfs. Closes: #510564
+    - smbclient du command does not recuse properly. Closes: #509258
+    - mention possible workgroup field in credential files in mount.cifs(8)
+      Closes: #400734
+    - bashism in /usr/share/doc/samba-doc/examples/perfcounter/perfcountd.init
+      Closes: #489656
+    - describe '-g' option in smbclient man page. Closes: #510812
+    - fix swat status table layout. Closes: #511275
+
+  [ Jelmer Vernooij ]
+  * Use alternatives for the smbstatus, nmblookup, net and 
+    testparm binaries and various data files in samba-common 
+    to allow installation of Samba 3 together with Samba 4. 
+  * Add myself to uploaders.
+
+  [ Christian Perrier ]
+  * Add mbc_getOptionCaseSensitive@Base, smbc_setOptionCaseSensitive@Base,
+    smbc_set_credentials@Base, smbc_urldecode@Base and smbc_urlencode@Base to
+    libsmbclient's symbols file with 3.3.0 as version number
+  * Also add 18 symbols to libwbclient0's symbols file with 3.3.0 as
+    version number
+
+ -- Christian Perrier <bubulle@debian.org>  Fri, 30 Jan 2009 21:41:49 +0100
+
+samba (2:3.3.0~rc2-4) experimental; urgency=low
+
+  [ Steve Langasek ]
+  * Revert one of the template depersonalization changes from the -2 upload,
+    because it loses important context
+
+  [ Christian Perrier ]
+  * Use double quotation marks in debconf templates
+  * Add 'status" option to init scripts. Thansk to Dustin Kirkland for
+    providing the patch. Closes: #488275
+  * Move WHATSNEW.txt, README, Roadmap to samba-common. Closes: #491997
+  * [Lintian] Add ${misc:Depends} to dependencies of binary packages
+    that didn't have it already as we're using debhelper in the source
+    package
+  * [Lintian] Don't ignore errors in swat.postrm
+  * [Lintian] Fix "local foo=bar" bashisms in samba-common.dhcp, samba.config
+    and samba-common.config
+  * smb.conf.5-undefined-configure.patch: fix syntax error in smb.conf(5)
+    Closes: #512843
+
+  [ Debconf translations ]
+  * Asturian added. Closes: #511730
+
+ -- Christian Perrier <bubulle@debian.org>  Sat, 24 Jan 2009 16:04:57 +0100
+
+samba (2:3.3.0~rc2-3) experimental; urgency=low
+
+  * Fix around the libsmbclient/libsmbclient-dev descriptions, which got
+    swapped in the last upload.
+  * Drop a boilerplate sentence from the samba-common, smbclient, swat, 
+    samba-doc, samba-doc-pdf, samba-dbg, and libwbclient0 descriptions
+    that's not relevant for these packages.
+  * Hyphenate "command-line" in the smbclient short description.
+  * Fix up the smbclient description, which got crossed with the smbfs one.
+  * Fix the smbfs description, which was not actually fixed in the previous
+    upload.  Really closes: #496206.
+  * Further minor adjustments to the description of the swat package.
+  * Fix various inaccuracies in the winbind package description.
+  * Clarify in the description that samba-tools are extra, only useful for
+    testing.
+
+ -- Steve Langasek <vorlon@debian.org>  Tue, 30 Dec 2008 18:42:05 -0800
+
+samba (2:3.3.0~rc2-2) experimental; urgency=low
+
+  [ Steve Langasek ]
+  * Handle clearing out netbios settings whenever the DHCP server has gone
+    away.  Closes: #299618.
+
+  [ Christian Perrier ]
+  * Point the correct document about password encryption in debconf templates
+    Corrected in translations as well. Closes: #502838
+  * Reword debconf templates to avoid mentioning the local host as a "server".
+    Closes: #171177
+  * Use this opportunity for other minor rewording:
+    - replace "SMB" by "SMB/CIFS"
+    - more strongly discouraging the use of plain text passwords
+    - unpersonnalization
+  * Reword the libpam-smbpass package description
+    Thanks to Justin B. Rye for the very useful suggestions
+    Closes: #496196
+  * Improve the package descriptions by rewording the description overhaul
+    Also improve the specific information for samba and samba-dbg
+    Thanks again to Justin B. Rye for the invaluable help
+    Closes: #496200
+  * Improve libsmbclient package description. Closes: #496197
+  * Improve libwbclient0 package description. Closes: #496199
+  * Improve samba-doc package description. Closes: #496202
+  * Improve samba-tools package description. Closes: #496203
+  * Improve samba-common package description. Closes: #496204
+  * Improve smbclient package description. Closes: #496205
+  * Improve smbfs package description. Closes: #496206
+  * Improve swat package description. Closes: #496207
+  * Improve winbind package description. Closes: #496208
+  * Improve samba-doc-pdf package description. Closes: #496211
+  * Update French debconf translation
+
+ -- Christian Perrier <bubulle@debian.org>  Mon, 29 Dec 2008 11:50:04 +0100
+
+samba (2:3.3.0~rc2-1) experimental; urgency=low
+
+  * New upstream release
+
+ -- Christian Perrier <bubulle@debian.org>  Wed, 17 Dec 2008 08:22:18 +0100
+
+samba (2:3.3.0~rc1-2) experimental; urgency=low
+
+  * Provide idmap_adex and idmap_hash in winbind.
+    Thanks to Jelmer Jaarsma for reporting and providing a patch
+
+ -- Christian Perrier <bubulle@debian.org>  Thu, 04 Dec 2008 19:59:23 +0100
+
+samba (2:3.3.0~rc1-1) experimental; urgency=low
+
+  * New upstream release
+
+ -- Christian Perrier <bubulle@debian.org>  Fri, 28 Nov 2008 10:51:32 +0100
+
+samba (2:3.3.0~pre2-1) experimental; urgency=low
+
+  * New upstream release.
+
+ -- Christian Perrier <bubulle@debian.org>  Fri, 07 Nov 2008 20:52:36 +0100
+
 samba (2:3.2.5-4ubuntu1) jaunty; urgency=low
 
   * Merge from Debian unstable, remaining changes:
@@ -1812,137 +1961,6 @@
 
  -- Christian Perrier <bubulle@debian.org>  Thu, 27 Nov 2008 11:36:35 +0100
 
-samba (2:3.3.0-1) experimental; urgency=low
-
-  * New upstream release. Fixes the following bugs:
-    - smb file deletion gvfs. Closes: #510564
-    - smbclient du command does not recuse properly. Closes: #509258
-    - mention possible workgroup field in credential files in mount.cifs(8)
-      Closes: #400734
-    - bashism in /usr/share/doc/samba-doc/examples/perfcounter/perfcountd.init
-      Closes: #489656
-    - describe '-g' option in smbclient man page. Closes: #510812
-    - fix swat status table layout. Closes: #511275
-
-  [ Jelmer Vernooij ]
-  * Use alternatives for the smbstatus, nmblookup, net and 
-    testparm binaries and various data files in samba-common 
-    to allow installation of Samba 3 together with Samba 4. 
-  * Add myself to uploaders.
-
-  [ Christian Perrier ]
-  * Add mbc_getOptionCaseSensitive@Base, smbc_setOptionCaseSensitive@Base,
-    smbc_set_credentials@Base, smbc_urldecode@Base and smbc_urlencode@Base to
-    libsmbclient's symbols file with 3.3.0 as version number
-  * Also add 18 symbols to libwbclient0's symbols file with 3.3.0 as
-    version number
-
- -- Christian Perrier <bubulle@debian.org>  Fri, 30 Jan 2009 21:41:49 +0100
-
-samba (2:3.3.0~rc2-4) experimental; urgency=low
-
-  [ Steve Langasek ]
-  * Revert one of the template depersonalization changes from the -2 upload,
-    because it loses important context
-
-  [ Christian Perrier ]
-  * Use double quotation marks in debconf templates
-  * Add 'status" option to init scripts. Thansk to Dustin Kirkland for
-    providing the patch. Closes: #488275
-  * Move WHATSNEW.txt, README, Roadmap to samba-common. Closes: #491997
-  * [Lintian] Add ${misc:Depends} to dependencies of binary packages
-    that didn't have it already as we're using debhelper in the source
-    package
-  * [Lintian] Don't ignore errors in swat.postrm
-  * [Lintian] Fix "local foo=bar" bashisms in samba-common.dhcp, samba.config
-    and samba-common.config
-  * smb.conf.5-undefined-configure.patch: fix syntax error in smb.conf(5)
-    Closes: #512843
-
-  [ Debconf translations ]
-  * Asturian added. Closes: #511730
-
- -- Christian Perrier <bubulle@debian.org>  Sat, 24 Jan 2009 16:04:57 +0100
-
-samba (2:3.3.0~rc2-3) experimental; urgency=low
-
-  * Fix around the libsmbclient/libsmbclient-dev descriptions, which got
-    swapped in the last upload.
-  * Drop a boilerplate sentence from the samba-common, smbclient, swat, 
-    samba-doc, samba-doc-pdf, samba-dbg, and libwbclient0 descriptions
-    that's not relevant for these packages.
-  * Hyphenate "command-line" in the smbclient short description.
-  * Fix up the smbclient description, which got crossed with the smbfs one.
-  * Fix the smbfs description, which was not actually fixed in the previous
-    upload.  Really closes: #496206.
-  * Further minor adjustments to the description of the swat package.
-  * Fix various inaccuracies in the winbind package description.
-  * Clarify in the description that samba-tools are extra, only useful for
-    testing.
-
- -- Steve Langasek <vorlon@debian.org>  Tue, 30 Dec 2008 18:42:05 -0800
-
-samba (2:3.3.0~rc2-2) experimental; urgency=low
-
-  [ Steve Langasek ]
-  * Handle clearing out netbios settings whenever the DHCP server has gone
-    away.  Closes: #299618.
-
-  [ Christian Perrier ]
-  * Point the correct document about password encryption in debconf templates
-    Corrected in translations as well. Closes: #502838
-  * Reword debconf templates to avoid mentioning the local host as a "server".
-    Closes: #171177
-  * Use this opportunity for other minor rewording:
-    - replace "SMB" by "SMB/CIFS"
-    - more strongly discouraging the use of plain text passwords
-    - unpersonnalization
-  * Reword the libpam-smbpass package description
-    Thanks to Justin B. Rye for the very useful suggestions
-    Closes: #496196
-  * Improve the package descriptions by rewording the description overhaul
-    Also improve the specific information for samba and samba-dbg
-    Thanks again to Justin B. Rye for the invaluable help
-    Closes: #496200
-  * Improve libsmbclient package description. Closes: #496197
-  * Improve libwbclient0 package description. Closes: #496199
-  * Improve samba-doc package description. Closes: #496202
-  * Improve samba-tools package description. Closes: #496203
-  * Improve samba-common package description. Closes: #496204
-  * Improve smbclient package description. Closes: #496205
-  * Improve smbfs package description. Closes: #496206
-  * Improve swat package description. Closes: #496207
-  * Improve winbind package description. Closes: #496208
-  * Improve samba-doc-pdf package description. Closes: #496211
-  * Update French debconf translation
-
- -- Christian Perrier <bubulle@debian.org>  Mon, 29 Dec 2008 11:50:04 +0100
-
-samba (2:3.3.0~rc2-1) experimental; urgency=low
-
-  * New upstream release
-
- -- Christian Perrier <bubulle@debian.org>  Wed, 17 Dec 2008 08:22:18 +0100
-
-samba (2:3.3.0~rc1-2) experimental; urgency=low
-
-  * Provide idmap_adex and idmap_hash in winbind.
-    Thanks to Jelmer Jaarsma for reporting and providing a patch
-
- -- Christian Perrier <bubulle@debian.org>  Thu, 04 Dec 2008 19:59:23 +0100
-
-samba (2:3.3.0~rc1-1) experimental; urgency=low
-
-  * New upstream release
-
- -- Christian Perrier <bubulle@debian.org>  Fri, 28 Nov 2008 10:51:32 +0100
-
-samba (2:3.3.0~pre2-1) experimental; urgency=low
-
-  * New upstream release.
-
- -- Christian Perrier <bubulle@debian.org>  Fri, 07 Nov 2008 20:52:36 +0100
-
 samba (2:3.2.4-1ubuntu3) jaunty; urgency=low
 
   * SECURITY UPDATE: potential arbitrary memory leak and crash via secondary
@@ -2396,6 +2414,45 @@
 
  -- Christian Perrier <bubulle@debian.org>  Sat, 31 May 2008 11:08:14 +0200
 
+samba (2:3.0.31-1) unstable; urgency=medium
+
+  * New upstream release
+
+ -- Christian Perrier <bubulle@debian.org>  Sat, 12 Jul 2008 16:57:09 +0200
+
+samba (2:3.0.30-4) unstable; urgency=low
+
+  [ Christian Perrier ]
+  * Rename libcupsys2-dev to libcups2-dev in build dependencies
+  * Localize SWAT in German. Closes: #487681
+  
+  [ Jelmer Vernooij ]
+  * Fix bashism in smbtar. (Closes: #486056)
+
+  [ Jamie Strandboge ]
+  * debian/patches/upstream_bug5517.patch: adjust cli_negprot() to properly
+    calculate buffer sizes. This bug was introduced in the fix for
+    CVE-2008-1105. Closes: #488688
+
+  [ Debconf translations ]
+  * Romanian updated. Closes: #488709.
+
+ -- Christian Perrier <bubulle@debian.org>  Sun, 06 Jul 2008 11:43:53 +0200
+
+samba (2:3.0.30-3) unstable; urgency=low
+
+  [ Christian Perrier ]
+  * add a soft dependency on slapd in init script to allow
+    proper operation when dependency-based boot sequence is enabled.
+    Thanks to Petter Reinholdtsen for reporting and providing a patch
+    Closes: #478800
+
+  [ Steve Langasek ]
+  * debian/patches/no-unnecessary-cups.patch: don't try to connect to a cups
+    server when we know that no printers are configured.  Closes: #479512.
+
+ -- Christian Perrier <bubulle@debian.org>  Tue, 10 Jun 2008 21:03:51 +0200
+
 samba (2:3.0.30-2ubuntu3) intrepid; urgency=low
 
   * debian/patches/upstream_bug5517.patch: adjust cli_negprot() to properly
@@ -2592,112 +2649,33 @@
 
  -- Christian Perrier <bubulle@debian.org>  Wed, 05 Mar 2008 22:45:28 +0100
 
-samba (2:3.0.31-1) unstable; urgency=medium
-
-  * New upstream release
-
- -- Christian Perrier <bubulle@debian.org>  Sat, 12 Jul 2008 16:57:09 +0200
-
-samba (2:3.0.30-4) unstable; urgency=low
-
-  [ Christian Perrier ]
-  * Rename libcupsys2-dev to libcups2-dev in build dependencies
-  * Localize SWAT in German. Closes: #487681
-  
-  [ Jelmer Vernooij ]
-  * Fix bashism in smbtar. (Closes: #486056)
-
-  [ Jamie Strandboge ]
-  * debian/patches/upstream_bug5517.patch: adjust cli_negprot() to properly
-    calculate buffer sizes. This bug was introduced in the fix for
-    CVE-2008-1105. Closes: #488688
+samba (3.2.0~pre1-1) experimental; urgency=low
+
+  * New upstream (pre-)release
+
+  [ Steve Langasek ]
+  * fhs.patch: net usershares should also be stored under /var/lib, not under
+    /var/run.  No transition handling in maintainer scripts, since this
+    feature is not activated by default.
+  * Update smbstatus-locking.patch to use db_open() instead of
+    tdb_open(), per upstream recommendation.
+  * Use talloc_strdup() and talloc_asprintf() instead of static strings in
+    data_path(), state_path(), and cache_path(), as suggested by Volker
+    Lendecke.
 
   [ Debconf translations ]
-  * Romanian updated. Closes: #488709.
-
- -- Christian Perrier <bubulle@debian.org>  Sun, 06 Jul 2008 11:43:53 +0200
-
-samba (2:3.0.30-3) unstable; urgency=low
-
-  [ Christian Perrier ]
-  * add a soft dependency on slapd in init script to allow
-    proper operation when dependency-based boot sequence is enabled.
-    Thanks to Petter Reinholdtsen for reporting and providing a patch
-    Closes: #478800
-
-  [ Steve Langasek ]
-  * debian/patches/no-unnecessary-cups.patch: don't try to connect to a cups
-    server when we know that no printers are configured.  Closes: #479512.
-
- -- Christian Perrier <bubulle@debian.org>  Tue, 10 Jun 2008 21:03:51 +0200
-
-samba (2:3.0.30-2) unstable; urgency=high
-
-  * Brown paper bag releae with epoch increased after yet another
-    accidental upload of 3.2.0 to unstable. Sigh and apologies to
-    autobuilders.
-
- -- Christian Perrier <bubulle@debian.org>  Sat, 31 May 2008 12:08:50 +0200
-
-samba (1:3.0.30-1) unstable; urgency=high
-
-  * New upstream release: fix a heap overflow when parsing SMB responses in
-    client code. (CVE-2008-1105). Closes: #483410
-
- -- Christian Perrier <bubulle@debian.org>  Wed, 28 May 2008 22:38:44 +0200
-
-samba (1:3.0.29-1) unstable; urgency=low
-
-  * New upstream release
-
- -- Christian Perrier <bubulle@debian.org>  Thu, 22 May 2008 07:31:55 +0200
-
-samba (1:3.0.28a-3) unstable; urgency=low
-
-  * The "bug hunting at SambaXP" release
-  * Drop "invalid users = root" from the default smb.conf file
-    as it differs from upstream's behaviour and upstream is fairly
-    noisy about this choice of ours. Closes: #462046
-  * Drop commented "guest account = nobody". This is already upstream's
-    default
-  * Remove versioned Build-Depends when satisfied in etch (actually all
-    versioning in Build-Depends)
-  * Remove Conflicts with non-existing packages
-  * Drop dpkg-dev and binutils from Build-Depends, since the versioned
-    build-dep is no longer needed and these are both Build-Essential
-  * Mini-policy for settings in smb.conf:
-    - don't explicitly set settings to their default value
-    - commented settings with the default value are commented with "#"
-    - commented settings with a non-default value are commented with ";"
-  * Apply this policy to "socket options". Closes: #476104
-  * No longer gratuitously use /usr/lib/libsmbclient.so.0.1 but a more logical
-    libsmbclient.so.0 as upstream doesn't assign versions
-  * Add idmap_*(8) man pages (idea taken from SerNet packages)
-  * Create the entire set of directories needed by clients for
-    Point-and-Click printing (including old clients!) in
-    /var/lib/samba/printers (idea taken from SerNet packages)
-  * Update copyright and README.debian information for current and past
-    maintainers. Remove redundant mention of Tridge (the copyright is enough)
-  * Add doc-base files for samba-doc-pdf. Closes: #451685
-  * Kurdish debconf translation. Closes: #480151
-
- -- Christian Perrier <bubulle@debian.org>  Wed, 16 Apr 2008 23:14:46 +0200
-
-samba (1:3.0.28a-2) unstable; urgency=low
-
-  [ Peter Eisentraut ]
-  * Removed myself from Uploaders
-
-  [ Steve Langasek ]
-  * debian/patches/manpage-encoding.patch: fix up the manpage synopses to
-    not use embedded iso8859-1 non-break spaces, there is a roff escape
-    sequence that we should use instead.  Closes: #470844.
-
-  [ Christian Perrier ]
-  * Reupload with an epoch to supersede an accidental upload of 3.2.0
-    in unstable
-
- -- Christian Perrier <bubulle@debian.org>  Sat, 05 Apr 2008 11:59:23 +0200
+  * Hebrew added. Closes: #444054
+
+  [ Christian Perrier ]
+  * Split fhs.patch into 4 separate patches to make upstream integration
+    easier:
+    - fhs-newpaths.patch: introduce new paths
+    - fhs-filespaths.patch: assign files to new paths
+    - fhs-filespaths-debatable.patch: assign files to new paths (part that
+      seems more difficult to be integrated upstream)
+    - fhs-assignpaths.patch: assign paths to FHS-compatible locations
+
+ -- Christian Perrier <bubulle@debian.org>  Sun, 21 Oct 2007 09:14:42 +0200
 
 samba (3.0.28a-1ubuntu4) hardy; urgency=low
 
@@ -3135,34 +3113,6 @@
 
  -- Steve Langasek <vorlon@debian.org>  Thu, 15 Nov 2007 11:46:17 -0800
 
-samba (3.2.0~pre1-1) experimental; urgency=low
-
-  * New upstream (pre-)release
-
-  [ Steve Langasek ]
-  * fhs.patch: net usershares should also be stored under /var/lib, not under
-    /var/run.  No transition handling in maintainer scripts, since this
-    feature is not activated by default.
-  * Update smbstatus-locking.patch to use db_open() instead of
-    tdb_open(), per upstream recommendation.
-  * Use talloc_strdup() and talloc_asprintf() instead of static strings in
-    data_path(), state_path(), and cache_path(), as suggested by Volker
-    Lendecke.
-
-  [ Debconf translations ]
-  * Hebrew added. Closes: #444054
-
-  [ Christian Perrier ]
-  * Split fhs.patch into 4 separate patches to make upstream integration
-    easier:
-    - fhs-newpaths.patch: introduce new paths
-    - fhs-filespaths.patch: assign files to new paths
-    - fhs-filespaths-debatable.patch: assign files to new paths (part that
-      seems more difficult to be integrated upstream)
-    - fhs-assignpaths.patch: assign paths to FHS-compatible locations
-
- -- Christian Perrier <bubulle@debian.org>  Sun, 21 Oct 2007 09:14:42 +0200
-
 samba (3.0.26a-1ubuntu2) gutsy; urgency=low
 
   * debian/patches/chgpasswd.patch:
@@ -7188,6 +7138,12 @@
 
  -- Eloy A. Paris <debian.org>  Wed, 10 Sep 1997 22:09:18 -0400
 
+samba (1.9.17alpha5-1) unstable; urgency=low
+
+  * New upstream version.
+
+ -- Eloy A. Paris <peloy@debian.org>  Thu, 14 Aug 1997 18:05:02 -0400
+
 samba (1.9.17-1) unstable; urgency=low
 
   * New upstream version (called the "Browse Fix Release")
@@ -7205,12 +7161,6 @@
 
  -- Eloy A. Paris <peloy@debian.org>  Wed, 27 Aug 1997 08:39:32 -0400
 
-samba (1.9.17alpha5-1) unstable; urgency=low
-
-  * New upstream version.
-
- -- Eloy A. Paris <peloy@debian.org>  Thu, 14 Aug 1997 18:05:02 -0400
-
 samba (1.9.16p11-3) unstable; urgency=low
 
   * Fixed accidental omission of /etc/pam.d/samba.

=== modified file 'debian/control'
--- debian/control	2010-09-16 12:19:11 +0000
+++ debian/control	2011-03-02 20:48:44 +0000
@@ -1,7 +1,7 @@
 Source: samba
 Section: net
 Priority: optional
-Maintainer: Ubuntu Core Developers <ubuntu-devel-discuss@lists.ubuntu.com>
+Maintainer: Ubuntu Developers <ubuntu-devel-discuss@lists.ubuntu.com>
 XSBC-Original-Maintainer: Debian Samba Maintainers <pkg-samba-maint@lists.alioth.debian.org>
 Uploaders: Steve Langasek <vorlon@debian.org>, Christian Perrier <bubulle@debian.org>, Noèl Köthe <noel@debian.org>, Jelmer Vernooij <jelmer@debian.org>
 Build-Depends: debhelper (>= 6.0.7~), libpam0g-dev, libreadline-dev,

=== added file 'debian/patches/ntlm-auth-lp623342.patch'
--- debian/patches/ntlm-auth-lp623342.patch	1970-01-01 00:00:00 +0000
+++ debian/patches/ntlm-auth-lp623342.patch	2011-03-02 20:48:44 +0000
@@ -0,0 +1,64 @@
+From a4603b32f7ca11c37f5a48d541ef76b08cda6415 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?G=C3=BCnther=20Deschner?= <gd@samba.org>
+Date: Mon, 9 Aug 2010 14:31:24 +0200
+Subject: [PATCH] s3-winbind: Fix Bug #7568: Make sure cm_connect_lsa_tcp does not reset the secure channel.
+
+This is an important fix as the following could and is happening:
+
+* winbind authenticates a user via schannel secured netlogon samlogonex call,
+current secure channel cred state is stored in winbind state, winbind
+sucessfully decrypts session key from the info3
+
+* winbind sets up a new schannel ncacn_ip_tcp lsa pipe (and thereby resets the
+secure channel on the dc)
+
+* subsequent samlogonex calls use the new secure channel creds on the dc to
+encrypt info3 session key, while winbind tries to use old schannel creds for
+decryption
+
+Guenther
+(cherry picked from commit be396411a4e1f3a174f8a44b6c062d834135e70a)
+(cherry picked from commit afe0e73b7bb640428396c9f40dbbcba5c311fcd9)
+
+Origin: upstream, https://bugzilla.samba.org/attachment.cgi?id=5893
+Bug-Samba: https://bugzilla.samba.org/show_bug.cgi?id=7568
+Bug-Ubuntu: https://bugs.launchpad.net/samba/+bug/623342
+Last-Update: 2011-02-26
+
+--- a/source3/winbindd/winbindd_cm.c
++++ b/source3/winbindd/winbindd_cm.c
+@@ -2231,6 +2231,7 @@
+ 			    struct rpc_pipe_client **cli)
+ {
+ 	struct winbindd_cm_conn *conn;
++	struct netlogon_creds_CredentialState *creds;
+ 	NTSTATUS status;
+ 
+ 	DEBUG(10,("cm_connect_lsa_tcp\n"));
+@@ -2251,14 +2252,19 @@
+ 
+ 	TALLOC_FREE(conn->lsa_pipe_tcp);
+ 
+-	status = cli_rpc_pipe_open_schannel(conn->cli,
+-					    &ndr_table_lsarpc.syntax_id,
+-					    NCACN_IP_TCP,
+-					    DCERPC_AUTH_LEVEL_PRIVACY,
+-					    domain->name,
+-					    &conn->lsa_pipe_tcp);
++	if (!cm_get_schannel_creds(domain, &creds)) {
++		goto done;
++	}
++
++	status = cli_rpc_pipe_open_schannel_with_key(conn->cli,
++						     &ndr_table_lsarpc.syntax_id,
++						     NCACN_IP_TCP,
++						     DCERPC_AUTH_LEVEL_PRIVACY,
++						     domain->name,
++						     &creds,
++						     &conn->lsa_pipe_tcp);
+ 	if (!NT_STATUS_IS_OK(status)) {
+-		DEBUG(10,("cli_rpc_pipe_open_schannel failed: %s\n",
++		DEBUG(10,("cli_rpc_pipe_open_schannel_with_key failed: %s\n",
+ 			nt_errstr(status)));
+ 		goto done;
+ 	}

=== added file 'debian/patches/security-CVE-2011-0719.patch'
--- debian/patches/security-CVE-2011-0719.patch	1970-01-01 00:00:00 +0000
+++ debian/patches/security-CVE-2011-0719.patch	2011-03-02 20:48:44 +0000
@@ -0,0 +1,436 @@
+Description: fix denial of service via missing range checks on file descriptors
+Origin: upstream, https://bugzilla.samba.org/show_bug.cgi?id=7949
+Bug: https://bugzilla.samba.org/show_bug.cgi?id=7949
+
+diff -Nur samba-3.5.4~dfsg/lib/tevent/tevent_select.c samba-3.5.4~dfsg.new/lib/tevent/tevent_select.c
+--- samba-3.5.4~dfsg/lib/tevent/tevent_select.c	2010-06-18 08:01:04.000000000 -0400
++++ samba-3.5.4~dfsg.new/lib/tevent/tevent_select.c	2011-02-23 13:12:19.000000000 -0500
+@@ -111,6 +111,11 @@
+ 							   struct select_event_context);
+ 	struct tevent_fd *fde;
+ 
++	if (fd < 0 || fd >= FD_SETSIZE) {
++		errno = EBADF;
++		return NULL;
++	}
++
+ 	fde = tevent_common_add_fd(ev, mem_ctx, fd, flags,
+ 				   handler, private_data,
+ 				   handler_name, location);
+@@ -143,6 +148,11 @@
+ 
+ 	/* setup any fd events */
+ 	for (fde = select_ev->ev->fd_events; fde; fde = fde->next) {
++		if (fde->fd < 0 || fde->fd >= FD_SETSIZE) {
++			errno = EBADF;
++			return -1;
++		}
++
+ 		if (fde->flags & TEVENT_FD_READ) {
+ 			FD_SET(fde->fd, &r_fds);
+ 		}
+diff -Nur samba-3.5.4~dfsg/lib/tevent/tevent_standard.c samba-3.5.4~dfsg.new/lib/tevent/tevent_standard.c
+--- samba-3.5.4~dfsg/lib/tevent/tevent_standard.c	2010-06-18 08:01:04.000000000 -0400
++++ samba-3.5.4~dfsg.new/lib/tevent/tevent_standard.c	2011-02-23 13:12:19.000000000 -0500
+@@ -457,6 +457,11 @@
+ 
+ 	/* setup any fd events */
+ 	for (fde = std_ev->ev->fd_events; fde; fde = fde->next) {
++		if (fde->fd < 0 || fde->fd >= FD_SETSIZE) {
++			std_ev->exit_code = EBADF;
++			return -1;
++		}
++
+ 		if (fde->flags & TEVENT_FD_READ) {
+ 			FD_SET(fde->fd, &r_fds);
+ 		}
+diff -Nur samba-3.5.4~dfsg/nsswitch/libwbclient/wbc_async.c samba-3.5.4~dfsg.new/nsswitch/libwbclient/wbc_async.c
+--- samba-3.5.4~dfsg/nsswitch/libwbclient/wbc_async.c	2010-06-18 08:01:04.000000000 -0400
++++ samba-3.5.4~dfsg.new/nsswitch/libwbclient/wbc_async.c	2011-02-23 13:12:19.000000000 -0500
+@@ -509,7 +509,7 @@
+ 	fd_set r_fds;
+ 	int selret;
+ 
+-	if (fd == -1) {
++	if (fd < 0 || fd >= FD_SETSIZE) {
+ 		return true;
+ 	}
+ 
+diff -Nur samba-3.5.4~dfsg/nsswitch/wb_common.c samba-3.5.4~dfsg.new/nsswitch/wb_common.c
+--- samba-3.5.4~dfsg/nsswitch/wb_common.c	2010-06-18 08:01:04.000000000 -0400
++++ samba-3.5.4~dfsg.new/nsswitch/wb_common.c	2011-02-23 13:12:19.000000000 -0500
+@@ -241,6 +241,10 @@
+ 		switch (errno) {
+ 			case EINPROGRESS:
+ 				FD_ZERO(&w_fds);
++				if (fd < 0 || fd >= FD_SETSIZE) {
++					errno = EBADF;
++					goto error_out;
++				}
+ 				FD_SET(fd, &w_fds);
+ 				tv.tv_sec = CONNECT_TIMEOUT - wait_time;
+ 				tv.tv_usec = 0;
+@@ -388,6 +392,11 @@
+ 		   call would not block by calling select(). */
+ 
+ 		FD_ZERO(&r_fds);
++		if (winbindd_fd < 0 || winbindd_fd >= FD_SETSIZE) {
++			errno = EBADF;
++			winbind_close_sock();
++			return -1;
++		}
+ 		FD_SET(winbindd_fd, &r_fds);
+ 		ZERO_STRUCT(tv);
+ 
+@@ -448,6 +457,11 @@
+ 		   call would not block by calling select(). */
+ 
+ 		FD_ZERO(&r_fds);
++		if (winbindd_fd < 0 || winbindd_fd >= FD_SETSIZE) {
++			errno = EBADF;
++			winbind_close_sock();
++			return -1;
++		}
+ 		FD_SET(winbindd_fd, &r_fds);
+ 		ZERO_STRUCT(tv);
+ 		/* Wait for 5 seconds for a reply. May need to parameterise this... */
+diff -Nur samba-3.5.4~dfsg/source3/client/client.c samba-3.5.4~dfsg.new/source3/client/client.c
+--- samba-3.5.4~dfsg/source3/client/client.c	2010-06-18 08:01:04.000000000 -0400
++++ samba-3.5.4~dfsg.new/source3/client/client.c	2011-02-23 13:12:19.000000000 -0500
+@@ -4420,8 +4420,10 @@
+ 
+  again:
+ 
+-	if (cli->fd == -1)
++	if (cli->fd < 0 || cli->fd >= FD_SETSIZE) {
++		errno = EBADF;
+ 		return;
++	}
+ 
+ 	FD_ZERO(&fds);
+ 	FD_SET(cli->fd,&fds);
+diff -Nur samba-3.5.4~dfsg/source3/client/dnsbrowse.c samba-3.5.4~dfsg.new/source3/client/dnsbrowse.c
+--- samba-3.5.4~dfsg/source3/client/dnsbrowse.c	2010-06-18 08:01:04.000000000 -0400
++++ samba-3.5.4~dfsg.new/source3/client/dnsbrowse.c	2011-02-23 13:12:19.000000000 -0500
+@@ -81,6 +81,11 @@
+ 			TALLOC_FREE(fdset);
+ 		}
+ 
++		if (mdnsfd < 0 || mdnsfd >= FD_SETSIZE) {
++			errno = EBADF;
++			break;
++		}
++
+ 		fdsetsz = howmany(mdnsfd + 1, NFDBITS) * sizeof(fd_mask);
+ 		fdset = TALLOC_ZERO(ctx, fdsetsz);
+ 		FD_SET(mdnsfd, fdset);
+@@ -181,6 +186,12 @@
+ 			TALLOC_FREE(fdset);
+ 		}
+ 
++		if (mdnsfd < 0 || mdnsfd >= FD_SETSIZE) {
++			errno = EBADF;
++			TALLOC_FREE(ctx);
++			return 1;
++		}
++
+ 		fdsetsz = howmany(mdnsfd + 1, NFDBITS) * sizeof(fd_mask);
+ 		fdset = TALLOC_ZERO(ctx, fdsetsz);
+ 		FD_SET(mdnsfd, fdset);
+diff -Nur samba-3.5.4~dfsg/source3/lib/events.c samba-3.5.4~dfsg.new/source3/lib/events.c
+--- samba-3.5.4~dfsg/source3/lib/events.c	2010-06-18 08:01:04.000000000 -0400
++++ samba-3.5.4~dfsg.new/source3/lib/events.c	2011-02-23 13:12:19.000000000 -0500
+@@ -55,6 +55,14 @@
+ 	bool ret = false;
+ 
+ 	for (fde = ev->fd_events; fde; fde = fde->next) {
++		if (fde->fd < 0 || fde->fd >= FD_SETSIZE) {
++			/* We ignore here, as it shouldn't be
++			   possible to add an invalid fde->fd
++			   but we don't want FD_SET to see an
++			   invalid fd. */
++			continue;
++		}
++
+ 		if (fde->flags & EVENT_FD_READ) {
+ 			FD_SET(fde->fd, read_fds);
+ 			ret = true;
+diff -Nur samba-3.5.4~dfsg/source3/lib/g_lock.c samba-3.5.4~dfsg.new/source3/lib/g_lock.c
+--- samba-3.5.4~dfsg/source3/lib/g_lock.c	2010-06-18 08:01:04.000000000 -0400
++++ samba-3.5.4~dfsg.new/source3/lib/g_lock.c	2011-02-23 13:12:19.000000000 -0500
+@@ -391,7 +391,9 @@
+ 			r_fds = &_r_fds;
+ 			FD_ZERO(r_fds);
+ 			max_fd = ctdbd_conn_get_fd(conn);
+-			FD_SET(max_fd, r_fds);
++			if (max_fd >= 0 && max_fd < FD_SETSIZE) {
++				FD_SET(max_fd, r_fds);
++			}
+ 		}
+ #endif
+ 
+diff -Nur samba-3.5.4~dfsg/source3/lib/packet.c samba-3.5.4~dfsg.new/source3/lib/packet.c
+--- samba-3.5.4~dfsg/source3/lib/packet.c	2010-06-18 08:01:04.000000000 -0400
++++ samba-3.5.4~dfsg.new/source3/lib/packet.c	2011-02-23 13:12:19.000000000 -0500
+@@ -107,6 +107,11 @@
+ 	int res;
+ 	fd_set r_fds;
+ 
++	if (ctx->fd < 0 || ctx->fd >= FD_SETSIZE) {
++		errno = EBADF;
++		return map_nt_error_from_unix(errno);
++	}
++
+ 	FD_ZERO(&r_fds);
+ 	FD_SET(ctx->fd, &r_fds);
+ 
+diff -Nur samba-3.5.4~dfsg/source3/lib/readline.c samba-3.5.4~dfsg.new/source3/lib/readline.c
+--- samba-3.5.4~dfsg/source3/lib/readline.c	2010-06-18 08:01:04.000000000 -0400
++++ samba-3.5.4~dfsg.new/source3/lib/readline.c	2011-02-23 13:12:19.000000000 -0500
+@@ -91,6 +91,11 @@
+ 		timeout.tv_sec = 5;
+ 		timeout.tv_usec = 0;
+ 
++		if (fd < 0 || fd >= FD_SETSIZE) {
++			errno = EBADF;
++			break;
++		}
++
+ 		FD_ZERO(&fds);
+ 		FD_SET(fd,&fds);
+ 
+diff -Nur samba-3.5.4~dfsg/source3/lib/select.c samba-3.5.4~dfsg.new/source3/lib/select.c
+--- samba-3.5.4~dfsg/source3/lib/select.c	2010-06-18 08:01:04.000000000 -0400
++++ samba-3.5.4~dfsg.new/source3/lib/select.c	2011-02-23 13:12:19.000000000 -0500
+@@ -75,6 +75,17 @@
+ 			return -1;
+ 		}
+ 
++		if (select_pipe[0] < 0 || select_pipe[0] >= FD_SETSIZE) {
++			DEBUG(0, ("sys_select: bad fd\n"));
++			if (readfds != NULL)
++				FD_ZERO(readfds);
++			if (writefds != NULL)
++				FD_ZERO(writefds);
++			if (errorfds != NULL)
++				FD_ZERO(errorfds);
++			errno = EBADF;
++			return -1;
++		}
+ 		/*
+ 		 * These next two lines seem to fix a bug with the Linux
+ 		 * 2.0.x kernel (and probably other UNIXes as well) where
+@@ -101,6 +112,7 @@
+ 		readfds2 = &readfds_buf;
+ 		FD_ZERO(readfds2);
+ 	}
++
+ 	FD_SET(select_pipe[0], readfds2);
+ 
+ 	errno = 0;
+diff -Nur samba-3.5.4~dfsg/source3/lib/util_sock.c samba-3.5.4~dfsg.new/source3/lib/util_sock.c
+--- samba-3.5.4~dfsg/source3/lib/util_sock.c	2010-06-18 08:01:04.000000000 -0400
++++ samba-3.5.4~dfsg.new/source3/lib/util_sock.c	2011-02-23 13:12:19.000000000 -0500
+@@ -495,6 +495,11 @@
+ 	timeout.tv_usec = (long)(1000 * (time_out % 1000));
+ 
+ 	for (nread=0; nread < mincnt; ) {
++		if (fd < 0 || fd >= FD_SETSIZE) {
++			errno = EBADF;
++			return map_nt_error_from_unix(EBADF);
++		}
++
+ 		FD_ZERO(&fds);
+ 		FD_SET(fd,&fds);
+ 
+@@ -1235,7 +1240,7 @@
+ 
+ 	for (i=0; i<num_addrs; i++) {
+ 		sockets[i] = socket(addrs[i].ss_family, SOCK_STREAM, 0);
+-		if (sockets[i] < 0)
++		if (sockets[i] < 0 || sockets[i] >= FD_SETSIZE)
+ 			goto done;
+ 		set_blocking(sockets[i], false);
+ 	}
+@@ -1284,8 +1289,10 @@
+ 	FD_ZERO(&r_fds);
+ 
+ 	for (i=0; i<num_addrs; i++) {
+-		if (sockets[i] == -1)
++		if (sockets[i] < 0 || sockets[i] >= FD_SETSIZE) {
++			/* This cannot happen - ignore if so. */
+ 			continue;
++		}
+ 		FD_SET(sockets[i], &wr_fds);
+ 		FD_SET(sockets[i], &r_fds);
+ 		if (sockets[i]>maxfd)
+@@ -1305,8 +1312,10 @@
+ 
+ 	for (i=0; i<num_addrs; i++) {
+ 
+-		if (sockets[i] == -1)
++		if (sockets[i] < 0 || sockets[i] >= FD_SETSIZE) {
++			/* This cannot happen - ignore if so. */
+ 			continue;
++		}
+ 
+ 		/* Stevens, Network Programming says that if there's a
+ 		 * successful connect, the socket is only writable. Upon an
+diff -Nur samba-3.5.4~dfsg/source3/libaddns/dnssock.c samba-3.5.4~dfsg.new/source3/libaddns/dnssock.c
+--- samba-3.5.4~dfsg/source3/libaddns/dnssock.c	2010-06-18 08:01:04.000000000 -0400
++++ samba-3.5.4~dfsg.new/source3/libaddns/dnssock.c	2011-02-23 13:12:19.000000000 -0500
+@@ -219,6 +219,11 @@
+ 		ssize_t ret;
+ 		int fd_ready;
+ 		
++		if (fd < 0 || fd >= FD_SETSIZE) {
++			/* read timeout */
++			return ERROR_DNS_SOCKET_ERROR;
++		}
++
+ 		FD_ZERO( &rfds );
+ 		FD_SET( fd, &rfds );
+ 
+diff -Nur samba-3.5.4~dfsg/source3/libsmb/nmblib.c samba-3.5.4~dfsg.new/source3/libsmb/nmblib.c
+--- samba-3.5.4~dfsg/source3/libsmb/nmblib.c	2010-06-18 08:01:04.000000000 -0400
++++ samba-3.5.4~dfsg.new/source3/libsmb/nmblib.c	2011-02-23 13:12:19.000000000 -0500
+@@ -1094,6 +1094,11 @@
+ 	struct timeval timeout;
+ 	int ret;
+ 
++	if (fd < 0 || fd >= FD_SETSIZE) {
++		errno = EBADF;
++		return NULL;
++	}
++
+ 	FD_ZERO(&fds);
+ 	FD_SET(fd,&fds);
+ 	timeout.tv_sec = t/1000;
+diff -Nur samba-3.5.4~dfsg/source3/nmbd/nmbd_packets.c samba-3.5.4~dfsg.new/source3/nmbd/nmbd_packets.c
+--- samba-3.5.4~dfsg/source3/nmbd/nmbd_packets.c	2010-06-18 08:01:04.000000000 -0400
++++ samba-3.5.4~dfsg.new/source3/nmbd/nmbd_packets.c	2011-02-23 13:12:19.000000000 -0500
+@@ -1696,7 +1696,7 @@
+ 	/* each interface gets 4 sockets */
+ 	count *= 4;
+ 
+-	if(count > FD_SETSIZE) {
++	if(count >= FD_SETSIZE) {
+ 		DEBUG(0,("create_listen_fdset: Too many file descriptors needed (%d). We can \
+ only use %d.\n", count, FD_SETSIZE));
+ 		SAFE_FREE(pset);
+@@ -1712,6 +1712,12 @@
+ 	FD_ZERO(pset);
+ 
+ 	/* Add in the lp_socket_address() interface on 137. */
++	if (ClientNMB < 0 || ClientNMB >= FD_SETSIZE) {
++		errno = EBADF;
++		SAFE_FREE(pset);
++		return True;
++	}
++
+ 	FD_SET(ClientNMB,pset);
+ 	sock_array[num++] = ClientNMB;
+ 	*maxfd = MAX( *maxfd, ClientNMB);
+@@ -1721,18 +1727,29 @@
+ 
+ 	/* Add in the 137 sockets on all the interfaces. */
+ 	for (subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec)) {
++		if (subrec->nmb_sock < 0 || subrec->nmb_sock >= FD_SETSIZE) {
++			/* We have to ignore sockets outside FD_SETSIZE. */
++			continue;
++		}
+ 		FD_SET(subrec->nmb_sock,pset);
+ 		sock_array[num++] = subrec->nmb_sock;
+ 		*maxfd = MAX( *maxfd, subrec->nmb_sock);
+ 
+-		sock_array[num++] = subrec->nmb_bcast;
+-		if (subrec->nmb_bcast != -1) {
+-			FD_SET(subrec->nmb_bcast,pset);
+-			*maxfd = MAX( *maxfd, subrec->nmb_bcast);
++		if (subrec->nmb_bcast < 0 || subrec->nmb_bcast >= FD_SETSIZE) {
++			/* We have to ignore sockets outside FD_SETSIZE. */
++			continue;
+ 		}
++		sock_array[num++] = subrec->nmb_bcast;
++		FD_SET(subrec->nmb_bcast,pset);
++		*maxfd = MAX( *maxfd, subrec->nmb_bcast);
+ 	}
+ 
+ 	/* Add in the lp_socket_address() interface on 138. */
++	if (ClientDGRAM < 0 || ClientDGRAM >= FD_SETSIZE) {
++		errno = EBADF;
++		SAFE_FREE(pset);
++		return True;
++	}
+ 	FD_SET(ClientDGRAM,pset);
+ 	sock_array[num++] = ClientDGRAM;
+ 	*maxfd = MAX( *maxfd, ClientDGRAM);
+@@ -1742,10 +1759,18 @@
+ 
+ 	/* Add in the 138 sockets on all the interfaces. */
+ 	for (subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec)) {
++		if (subrec->dgram_sock < 0 || subrec->dgram_sock >= FD_SETSIZE) {
++			/* We have to ignore sockets outside FD_SETSIZE. */
++			continue;
++		}
+ 		FD_SET(subrec->dgram_sock,pset);
+ 		sock_array[num++] = subrec->dgram_sock;
+ 		*maxfd = MAX( *maxfd, subrec->dgram_sock);
+ 
++		if (subrec->dgram_bcast < 0 || subrec->dgram_bcast >= FD_SETSIZE) {
++			/* We have to ignore sockets outside FD_SETSIZE. */
++			continue;
++		}
+ 		sock_array[num++] = subrec->dgram_bcast;
+ 		if (subrec->dgram_bcast != -1) {
+ 			FD_SET(subrec->dgram_bcast,pset);
+@@ -1876,7 +1901,7 @@
+ 
+ #ifndef SYNC_DNS
+ 	dns_fd = asyncdns_fd();
+-	if (dns_fd != -1) {
++	if (dns_fd >= 0 && dns_fd < FD_SETSIZE) {
+ 		FD_SET(dns_fd, &r_fds);
+ 		maxfd = MAX( maxfd, dns_fd);
+ 	}
+diff -Nur samba-3.5.4~dfsg/source3/utils/smbfilter.c samba-3.5.4~dfsg.new/source3/utils/smbfilter.c
+--- samba-3.5.4~dfsg/source3/utils/smbfilter.c	2010-06-18 08:01:04.000000000 -0400
++++ samba-3.5.4~dfsg.new/source3/utils/smbfilter.c	2011-02-23 13:12:19.000000000 -0500
+@@ -170,8 +170,8 @@
+ 		int num;
+ 		
+ 		FD_ZERO(&fds);
+-		if (s != -1) FD_SET(s, &fds);
+-		if (c != -1) FD_SET(c, &fds);
++		if (s >= 0 && s < FD_SETSIZE) FD_SET(s, &fds);
++		if (c >= 0 && c < FD_SETSIZE) FD_SET(c, &fds);
+ 
+ 		num = sys_select_intr(MAX(s+1, c+1),&fds,NULL,NULL,NULL);
+ 		if (num <= 0) continue;
+@@ -244,6 +244,9 @@
+ 		socklen_t in_addrlen = sizeof(ss);
+ 		
+ 		FD_ZERO(&fds);
++		if (s < 0 || s >= FD_SETSIZE) {
++			break;
++		}
+ 		FD_SET(s, &fds);
+ 
+ 		num = sys_select_intr(s+1,&fds,NULL,NULL,NULL);
+diff -Nur samba-3.5.4~dfsg/source3/winbindd/winbindd_dual.c samba-3.5.4~dfsg.new/source3/winbindd/winbindd_dual.c
+--- samba-3.5.4~dfsg/source3/winbindd/winbindd_dual.c	2010-06-18 08:01:04.000000000 -0400
++++ samba-3.5.4~dfsg.new/source3/winbindd/winbindd_dual.c	2011-02-23 13:12:19.000000000 -0500
+@@ -1460,6 +1460,13 @@
+ 
+ 		FD_ZERO(&r_fds);
+ 		FD_ZERO(&w_fds);
++
++		if (state.sock < 0 || state.sock >= FD_SETSIZE) {
++			TALLOC_FREE(frame);
++			perror("EBADF");
++			_exit(1);
++		}
++
+ 		FD_SET(state.sock, &r_fds);
+ 		maxfd = state.sock;
+ 

=== modified file 'debian/patches/series'
--- debian/patches/series	2010-12-17 10:40:10 +0000
+++ debian/patches/series	2011-03-02 20:48:44 +0000
@@ -14,3 +14,5 @@
 security-CVE-2010-3069.patch
 fix-lpbug-393012.patch
 spnego-auth-win7.patch
+security-CVE-2011-0719.patch
+ntlm-auth-lp623342.patch

=== modified file 'lib/tevent/tevent_select.c'
--- lib/tevent/tevent_select.c	2009-05-20 18:50:35 +0000
+++ lib/tevent/tevent_select.c	2011-03-02 20:48:44 +0000
@@ -111,6 +111,11 @@
 							   struct select_event_context);
 	struct tevent_fd *fde;
 
+	if (fd < 0 || fd >= FD_SETSIZE) {
+		errno = EBADF;
+		return NULL;
+	}
+
 	fde = tevent_common_add_fd(ev, mem_ctx, fd, flags,
 				   handler, private_data,
 				   handler_name, location);
@@ -143,6 +148,11 @@
 
 	/* setup any fd events */
 	for (fde = select_ev->ev->fd_events; fde; fde = fde->next) {
+		if (fde->fd < 0 || fde->fd >= FD_SETSIZE) {
+			errno = EBADF;
+			return -1;
+		}
+
 		if (fde->flags & TEVENT_FD_READ) {
 			FD_SET(fde->fd, &r_fds);
 		}

=== modified file 'lib/tevent/tevent_standard.c'
--- lib/tevent/tevent_standard.c	2009-05-20 18:50:35 +0000
+++ lib/tevent/tevent_standard.c	2011-03-02 20:48:44 +0000
@@ -457,6 +457,11 @@
 
 	/* setup any fd events */
 	for (fde = std_ev->ev->fd_events; fde; fde = fde->next) {
+		if (fde->fd < 0 || fde->fd >= FD_SETSIZE) {
+			std_ev->exit_code = EBADF;
+			return -1;
+		}
+
 		if (fde->flags & TEVENT_FD_READ) {
 			FD_SET(fde->fd, &r_fds);
 		}

=== modified file 'nsswitch/libwbclient/wbc_async.c'
--- nsswitch/libwbclient/wbc_async.c	2010-07-11 19:01:01 +0000
+++ nsswitch/libwbclient/wbc_async.c	2011-03-02 20:48:44 +0000
@@ -509,7 +509,7 @@
 	fd_set r_fds;
 	int selret;
 
-	if (fd == -1) {
+	if (fd < 0 || fd >= FD_SETSIZE) {
 		return true;
 	}
 

=== modified file 'nsswitch/wb_common.c'
--- nsswitch/wb_common.c	2009-05-20 18:50:35 +0000
+++ nsswitch/wb_common.c	2011-03-02 20:48:44 +0000
@@ -241,6 +241,10 @@
 		switch (errno) {
 			case EINPROGRESS:
 				FD_ZERO(&w_fds);
+				if (fd < 0 || fd >= FD_SETSIZE) {
+					errno = EBADF;
+					goto error_out;
+				}
 				FD_SET(fd, &w_fds);
 				tv.tv_sec = CONNECT_TIMEOUT - wait_time;
 				tv.tv_usec = 0;
@@ -388,6 +392,11 @@
 		   call would not block by calling select(). */
 
 		FD_ZERO(&r_fds);
+		if (winbindd_fd < 0 || winbindd_fd >= FD_SETSIZE) {
+			errno = EBADF;
+			winbind_close_sock();
+			return -1;
+		}
 		FD_SET(winbindd_fd, &r_fds);
 		ZERO_STRUCT(tv);
 
@@ -448,6 +457,11 @@
 		   call would not block by calling select(). */
 
 		FD_ZERO(&r_fds);
+		if (winbindd_fd < 0 || winbindd_fd >= FD_SETSIZE) {
+			errno = EBADF;
+			winbind_close_sock();
+			return -1;
+		}
 		FD_SET(winbindd_fd, &r_fds);
 		ZERO_STRUCT(tv);
 		/* Wait for 5 seconds for a reply. May need to parameterise this... */

=== modified file 'source3/client/client.c'
--- source3/client/client.c	2010-07-11 19:01:01 +0000
+++ source3/client/client.c	2011-03-02 20:48:44 +0000
@@ -4420,8 +4420,10 @@
 
  again:
 
-	if (cli->fd == -1)
+	if (cli->fd < 0 || cli->fd >= FD_SETSIZE) {
+		errno = EBADF;
 		return;
+	}
 
 	FD_ZERO(&fds);
 	FD_SET(cli->fd,&fds);

=== modified file 'source3/client/dnsbrowse.c'
--- source3/client/dnsbrowse.c	2009-05-20 18:50:35 +0000
+++ source3/client/dnsbrowse.c	2011-03-02 20:48:44 +0000
@@ -81,6 +81,11 @@
 			TALLOC_FREE(fdset);
 		}
 
+		if (mdnsfd < 0 || mdnsfd >= FD_SETSIZE) {
+			errno = EBADF;
+			break;
+		}
+
 		fdsetsz = howmany(mdnsfd + 1, NFDBITS) * sizeof(fd_mask);
 		fdset = TALLOC_ZERO(ctx, fdsetsz);
 		FD_SET(mdnsfd, fdset);
@@ -181,6 +186,12 @@
 			TALLOC_FREE(fdset);
 		}
 
+		if (mdnsfd < 0 || mdnsfd >= FD_SETSIZE) {
+			errno = EBADF;
+			TALLOC_FREE(ctx);
+			return 1;
+		}
+
 		fdsetsz = howmany(mdnsfd + 1, NFDBITS) * sizeof(fd_mask);
 		fdset = TALLOC_ZERO(ctx, fdsetsz);
 		FD_SET(mdnsfd, fdset);

=== modified file 'source3/lib/events.c'
--- source3/lib/events.c	2010-07-11 19:01:01 +0000
+++ source3/lib/events.c	2011-03-02 20:48:44 +0000
@@ -55,6 +55,14 @@
 	bool ret = false;
 
 	for (fde = ev->fd_events; fde; fde = fde->next) {
+		if (fde->fd < 0 || fde->fd >= FD_SETSIZE) {
+			/* We ignore here, as it shouldn't be
+			   possible to add an invalid fde->fd
+			   but we don't want FD_SET to see an
+			   invalid fd. */
+			continue;
+		}
+
 		if (fde->flags & EVENT_FD_READ) {
 			FD_SET(fde->fd, read_fds);
 			ret = true;

=== modified file 'source3/lib/g_lock.c'
--- source3/lib/g_lock.c	2010-07-11 19:01:01 +0000
+++ source3/lib/g_lock.c	2011-03-02 20:48:44 +0000
@@ -391,7 +391,9 @@
 			r_fds = &_r_fds;
 			FD_ZERO(r_fds);
 			max_fd = ctdbd_conn_get_fd(conn);
-			FD_SET(max_fd, r_fds);
+			if (max_fd >= 0 && max_fd < FD_SETSIZE) {
+				FD_SET(max_fd, r_fds);
+			}
 		}
 #endif
 

=== modified file 'source3/lib/packet.c'
--- source3/lib/packet.c	2010-07-11 19:01:01 +0000
+++ source3/lib/packet.c	2011-03-02 20:48:44 +0000
@@ -107,6 +107,11 @@
 	int res;
 	fd_set r_fds;
 
+	if (ctx->fd < 0 || ctx->fd >= FD_SETSIZE) {
+		errno = EBADF;
+		return map_nt_error_from_unix(errno);
+	}
+
 	FD_ZERO(&r_fds);
 	FD_SET(ctx->fd, &r_fds);
 

=== modified file 'source3/lib/readline.c'
--- source3/lib/readline.c	2009-05-20 18:50:35 +0000
+++ source3/lib/readline.c	2011-03-02 20:48:44 +0000
@@ -91,6 +91,11 @@
 		timeout.tv_sec = 5;
 		timeout.tv_usec = 0;
 
+		if (fd < 0 || fd >= FD_SETSIZE) {
+			errno = EBADF;
+			break;
+		}
+
 		FD_ZERO(&fds);
 		FD_SET(fd,&fds);
 

=== modified file 'source3/lib/select.c'
--- source3/lib/select.c	2009-10-31 14:32:07 +0000
+++ source3/lib/select.c	2011-03-02 20:48:44 +0000
@@ -75,6 +75,17 @@
 			return -1;
 		}
 
+		if (select_pipe[0] < 0 || select_pipe[0] >= FD_SETSIZE) {
+			DEBUG(0, ("sys_select: bad fd\n"));
+			if (readfds != NULL)
+				FD_ZERO(readfds);
+			if (writefds != NULL)
+				FD_ZERO(writefds);
+			if (errorfds != NULL)
+				FD_ZERO(errorfds);
+			errno = EBADF;
+			return -1;
+		}
 		/*
 		 * These next two lines seem to fix a bug with the Linux
 		 * 2.0.x kernel (and probably other UNIXes as well) where
@@ -101,6 +112,7 @@
 		readfds2 = &readfds_buf;
 		FD_ZERO(readfds2);
 	}
+
 	FD_SET(select_pipe[0], readfds2);
 
 	errno = 0;

=== modified file 'source3/lib/util_sock.c'
--- source3/lib/util_sock.c	2010-07-11 19:01:01 +0000
+++ source3/lib/util_sock.c	2011-03-02 20:48:44 +0000
@@ -495,6 +495,11 @@
 	timeout.tv_usec = (long)(1000 * (time_out % 1000));
 
 	for (nread=0; nread < mincnt; ) {
+		if (fd < 0 || fd >= FD_SETSIZE) {
+			errno = EBADF;
+			return map_nt_error_from_unix(EBADF);
+		}
+
 		FD_ZERO(&fds);
 		FD_SET(fd,&fds);
 
@@ -1235,7 +1240,7 @@
 
 	for (i=0; i<num_addrs; i++) {
 		sockets[i] = socket(addrs[i].ss_family, SOCK_STREAM, 0);
-		if (sockets[i] < 0)
+		if (sockets[i] < 0 || sockets[i] >= FD_SETSIZE)
 			goto done;
 		set_blocking(sockets[i], false);
 	}
@@ -1284,8 +1289,10 @@
 	FD_ZERO(&r_fds);
 
 	for (i=0; i<num_addrs; i++) {
-		if (sockets[i] == -1)
+		if (sockets[i] < 0 || sockets[i] >= FD_SETSIZE) {
+			/* This cannot happen - ignore if so. */
 			continue;
+		}
 		FD_SET(sockets[i], &wr_fds);
 		FD_SET(sockets[i], &r_fds);
 		if (sockets[i]>maxfd)
@@ -1305,8 +1312,10 @@
 
 	for (i=0; i<num_addrs; i++) {
 
-		if (sockets[i] == -1)
+		if (sockets[i] < 0 || sockets[i] >= FD_SETSIZE) {
+			/* This cannot happen - ignore if so. */
 			continue;
+		}
 
 		/* Stevens, Network Programming says that if there's a
 		 * successful connect, the socket is only writable. Upon an

=== modified file 'source3/libaddns/dnssock.c'
--- source3/libaddns/dnssock.c	2009-05-20 18:50:35 +0000
+++ source3/libaddns/dnssock.c	2011-03-02 20:48:44 +0000
@@ -219,6 +219,11 @@
 		ssize_t ret;
 		int fd_ready;
 		
+		if (fd < 0 || fd >= FD_SETSIZE) {
+			/* read timeout */
+			return ERROR_DNS_SOCKET_ERROR;
+		}
+
 		FD_ZERO( &rfds );
 		FD_SET( fd, &rfds );
 

=== modified file 'source3/libsmb/nmblib.c'
--- source3/libsmb/nmblib.c	2010-07-11 19:01:01 +0000
+++ source3/libsmb/nmblib.c	2011-03-02 20:48:44 +0000
@@ -1094,6 +1094,11 @@
 	struct timeval timeout;
 	int ret;
 
+	if (fd < 0 || fd >= FD_SETSIZE) {
+		errno = EBADF;
+		return NULL;
+	}
+
 	FD_ZERO(&fds);
 	FD_SET(fd,&fds);
 	timeout.tv_sec = t/1000;

=== modified file 'source3/nmbd/nmbd_packets.c'
--- source3/nmbd/nmbd_packets.c	2010-07-11 19:01:01 +0000
+++ source3/nmbd/nmbd_packets.c	2011-03-02 20:48:44 +0000
@@ -1696,7 +1696,7 @@
 	/* each interface gets 4 sockets */
 	count *= 4;
 
-	if(count > FD_SETSIZE) {
+	if(count >= FD_SETSIZE) {
 		DEBUG(0,("create_listen_fdset: Too many file descriptors needed (%d). We can \
 only use %d.\n", count, FD_SETSIZE));
 		SAFE_FREE(pset);
@@ -1712,6 +1712,12 @@
 	FD_ZERO(pset);
 
 	/* Add in the lp_socket_address() interface on 137. */
+	if (ClientNMB < 0 || ClientNMB >= FD_SETSIZE) {
+		errno = EBADF;
+		SAFE_FREE(pset);
+		return True;
+	}
+
 	FD_SET(ClientNMB,pset);
 	sock_array[num++] = ClientNMB;
 	*maxfd = MAX( *maxfd, ClientNMB);
@@ -1721,18 +1727,29 @@
 
 	/* Add in the 137 sockets on all the interfaces. */
 	for (subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec)) {
+		if (subrec->nmb_sock < 0 || subrec->nmb_sock >= FD_SETSIZE) {
+			/* We have to ignore sockets outside FD_SETSIZE. */
+			continue;
+		}
 		FD_SET(subrec->nmb_sock,pset);
 		sock_array[num++] = subrec->nmb_sock;
 		*maxfd = MAX( *maxfd, subrec->nmb_sock);
 
+		if (subrec->nmb_bcast < 0 || subrec->nmb_bcast >= FD_SETSIZE) {
+			/* We have to ignore sockets outside FD_SETSIZE. */
+			continue;
+		}
 		sock_array[num++] = subrec->nmb_bcast;
-		if (subrec->nmb_bcast != -1) {
-			FD_SET(subrec->nmb_bcast,pset);
-			*maxfd = MAX( *maxfd, subrec->nmb_bcast);
-		}
+		FD_SET(subrec->nmb_bcast,pset);
+		*maxfd = MAX( *maxfd, subrec->nmb_bcast);
 	}
 
 	/* Add in the lp_socket_address() interface on 138. */
+	if (ClientDGRAM < 0 || ClientDGRAM >= FD_SETSIZE) {
+		errno = EBADF;
+		SAFE_FREE(pset);
+		return True;
+	}
 	FD_SET(ClientDGRAM,pset);
 	sock_array[num++] = ClientDGRAM;
 	*maxfd = MAX( *maxfd, ClientDGRAM);
@@ -1742,10 +1759,18 @@
 
 	/* Add in the 138 sockets on all the interfaces. */
 	for (subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec)) {
+		if (subrec->dgram_sock < 0 || subrec->dgram_sock >= FD_SETSIZE) {
+			/* We have to ignore sockets outside FD_SETSIZE. */
+			continue;
+		}
 		FD_SET(subrec->dgram_sock,pset);
 		sock_array[num++] = subrec->dgram_sock;
 		*maxfd = MAX( *maxfd, subrec->dgram_sock);
 
+		if (subrec->dgram_bcast < 0 || subrec->dgram_bcast >= FD_SETSIZE) {
+			/* We have to ignore sockets outside FD_SETSIZE. */
+			continue;
+		}
 		sock_array[num++] = subrec->dgram_bcast;
 		if (subrec->dgram_bcast != -1) {
 			FD_SET(subrec->dgram_bcast,pset);
@@ -1876,7 +1901,7 @@
 
 #ifndef SYNC_DNS
 	dns_fd = asyncdns_fd();
-	if (dns_fd != -1) {
+	if (dns_fd >= 0 && dns_fd < FD_SETSIZE) {
 		FD_SET(dns_fd, &r_fds);
 		maxfd = MAX( maxfd, dns_fd);
 	}

=== modified file 'source3/utils/smbfilter.c'
--- source3/utils/smbfilter.c	2010-07-11 19:01:01 +0000
+++ source3/utils/smbfilter.c	2011-03-02 20:48:44 +0000
@@ -170,8 +170,8 @@
 		int num;
 		
 		FD_ZERO(&fds);
-		if (s != -1) FD_SET(s, &fds);
-		if (c != -1) FD_SET(c, &fds);
+		if (s >= 0 && s < FD_SETSIZE) FD_SET(s, &fds);
+		if (c >= 0 && c < FD_SETSIZE) FD_SET(c, &fds);
 
 		num = sys_select_intr(MAX(s+1, c+1),&fds,NULL,NULL,NULL);
 		if (num <= 0) continue;
@@ -244,6 +244,9 @@
 		socklen_t in_addrlen = sizeof(ss);
 		
 		FD_ZERO(&fds);
+		if (s < 0 || s >= FD_SETSIZE) {
+			break;
+		}
 		FD_SET(s, &fds);
 
 		num = sys_select_intr(s+1,&fds,NULL,NULL,NULL);

=== modified file 'source3/winbindd/winbindd_cm.c'
--- source3/winbindd/winbindd_cm.c	2010-07-11 19:01:01 +0000
+++ source3/winbindd/winbindd_cm.c	2011-03-02 20:48:44 +0000
@@ -2231,6 +2231,7 @@
 			    struct rpc_pipe_client **cli)
 {
 	struct winbindd_cm_conn *conn;
+	struct netlogon_creds_CredentialState *creds;
 	NTSTATUS status;
 
 	DEBUG(10,("cm_connect_lsa_tcp\n"));
@@ -2251,14 +2252,19 @@
 
 	TALLOC_FREE(conn->lsa_pipe_tcp);
 
-	status = cli_rpc_pipe_open_schannel(conn->cli,
-					    &ndr_table_lsarpc.syntax_id,
-					    NCACN_IP_TCP,
-					    DCERPC_AUTH_LEVEL_PRIVACY,
-					    domain->name,
-					    &conn->lsa_pipe_tcp);
+	if (!cm_get_schannel_creds(domain, &creds)) {
+		goto done;
+	}
+
+	status = cli_rpc_pipe_open_schannel_with_key(conn->cli,
+						     &ndr_table_lsarpc.syntax_id,
+						     NCACN_IP_TCP,
+						     DCERPC_AUTH_LEVEL_PRIVACY,
+						     domain->name,
+						     &creds,
+						     &conn->lsa_pipe_tcp);
 	if (!NT_STATUS_IS_OK(status)) {
-		DEBUG(10,("cli_rpc_pipe_open_schannel failed: %s\n",
+		DEBUG(10,("cli_rpc_pipe_open_schannel_with_key failed: %s\n",
 			nt_errstr(status)));
 		goto done;
 	}

=== modified file 'source3/winbindd/winbindd_dual.c'
--- source3/winbindd/winbindd_dual.c	2010-07-11 19:01:01 +0000
+++ source3/winbindd/winbindd_dual.c	2011-03-02 20:48:44 +0000
@@ -1460,6 +1460,13 @@
 
 		FD_ZERO(&r_fds);
 		FD_ZERO(&w_fds);
+
+		if (state.sock < 0 || state.sock >= FD_SETSIZE) {
+			TALLOC_FREE(frame);
+			perror("EBADF");
+			_exit(1);
+		}
+
 		FD_SET(state.sock, &r_fds);
 		maxfd = state.sock;
 

