[PATCH] Updated Add detailed authentication logging for NTLM authentication.

Gary Lockyer gary at catalyst.net.nz
Mon Mar 13 03:39:41 UTC 2017


Review/comments apreciated.

Updated to use jansson for the JSON generation, removing the glib
dependencies. We're planning to get the tests written tomorrow, which
will finish this piece of work off.

Samples of the new log lines below, line breaks and indent added for
clarity.

Authorization

Human Readable
	Successful AuthZ: [DCE/RPC,ncacn_np]
	user [NT AUTHORITY]\[SYSTEM] [S-1-5-18]
	at [Mon, 13 Mar 2017 16:17:57 NZDT]
	Remote host [ipv6::::0] local host [ipv6::::0]

JSON
	JSON Authorization: {
		"timestamp": "2017-03-13T16:17:57.446508+1300",
		"Authorization": {
			"version": {"major": 1, "minor": 0},
			"remoteAddress": "ipv6::::0",
			"authType": "ncacn_np",
			"transportProtection": "SMB",
			"localAddress": "ipv6::::0",
			"sid": "S-1-5-18",
			"serviceDescription": "DCE/RPC",
			"domain": "NT AUTHORITY",
			"account": "SYSTEM",
			"logonServer": null,
			"accountFlags": "0x00000000"
		},
		"type": "Authorization"
	}

Authentication

Human Readable
	Auth: [SamLogon,network] user [ADDOMAIN]\[Administrator]
	at [Mon, 13 Mar 2017 16:18:39 NZDT]
	with [ntlmv2] status [NT_STATUS_OK]
	workstation [schannel0] remote host [ipv4:127.0.0.11:15408]
 	became [ADDOMAIN]\[Administrator]
 	S-1-5-21-2041978683-1917359319-4010618550-500.
	local host [ipv4:127.0.0.30:445]
	  NETLOGON computer [schannel0] trust account [schannel0]

JSON

	JSON Authentication: {
		"timestamp": "2017-03-13T16:18:39.477569+1300",
 		"type": "Authentication",
		"Authentication": {
			"version": {"major": 1, "minor": 0},
 			"clientAccount": "Administrator",
			"status": "NT_STATUS_OK",
			"mappedDomain": "ADDOMAIN",
			"remoteAddress": "ipv4:127.0.0.11:15408",
			"passwordType": "ntlmv2",
			"netlogonComputer": "schannel0",
			"becameAccount": "Administrator",
			"localAddress": "ipv4:127.0.0.30:445",
			"authDescription": "network",
			"becameDomain": "ADDOMAIN",
			"serviceDescription": "SamLogon",
			"clientDomain": "ADDOMAIN",
			"workstation": "schannel0",
			"mappedAccount": "Administrator",
			"trustAccount": "schannel0"
		}
	}

On 10/03/17 15:41, Gary Lockyer wrote:
> Another revision, got the rebase slightly wrong.
> 
> On 10/03/17 14:42, Gary Lockyer wrote:
>> Revised patch with work to date, rebased on the current master.
>>
>> We're aiming to add tests and wrap things up early next week. Any
>> review/comments greatly appreciated.
>>
>> Gary.
>>
-------------- next part --------------
From 3affe568b77dde6ef2760350f7db918f2771cf57 Mon Sep 17 00:00:00 2001
From: Andrew Bartlett <abartlet at samba.org>
Date: Tue, 7 Mar 2017 15:09:38 +1300
Subject: [PATCH 01/43] messaging.idl: Register a message type for
 authentication log messages

Signed-off-by: Andrew Bartlett <abartlet at samba.org>
Pair-Programmed: Gary Lockyer <gary at catalyst.net.nz>
---
 librpc/idl/messaging.idl | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/librpc/idl/messaging.idl b/librpc/idl/messaging.idl
index 032f95e..2a94eee 100644
--- a/librpc/idl/messaging.idl
+++ b/librpc/idl/messaging.idl
@@ -139,6 +139,9 @@ interface messaging
 		MSG_NTVFS_OPLOCK_BREAK          = 0x0703,
 		MSG_DREPL_ALLOCATE_RID          = 0x0704,
 
+		/* Called during authentication and authorization to allow out-of- */
+		MSG_AUTH_LOG                    = 0x0800,
+
 		/* dbwrap messages 4001-4999 (0x0FA0 - 0x1387) */
 		/* MSG_DBWRAP_TDB2_CHANGES		= 4001, */
 		/* MSG_DBWRAP_G_LOCK_RETRY		= 4002, */
-- 
2.7.4


From f66fd91a748362c2eef635153291bdb7ed86f965 Mon Sep 17 00:00:00 2001
From: Andrew Bartlett <abartlet at samba.org>
Date: Wed, 8 Mar 2017 11:03:44 +1300
Subject: [PATCH 02/43] pytevent: Allow other parts of Samba to consume tevent
 python bindings

This will make it possible for pymessaging to consume a pytevent created context, and so
make pymessaging practical

Signed-off-by: Andrew Bartlett <abartlet at samba.org>
Pair-Programmed: Gary Lockyer <gary at catalyst.net.nz>
---
 lib/tevent/pytevent.c |  9 +--------
 lib/tevent/pytevent.h | 34 ++++++++++++++++++++++++++++++++++
 2 files changed, 35 insertions(+), 8 deletions(-)
 create mode 100644 lib/tevent/pytevent.h

diff --git a/lib/tevent/pytevent.c b/lib/tevent/pytevent.c
index 10d8a22..eb76c2b 100644
--- a/lib/tevent/pytevent.c
+++ b/lib/tevent/pytevent.c
@@ -22,9 +22,7 @@
    License along with this library; if not, see <http://www.gnu.org/licenses/>.
 */
 
-#include <Python.h>
-#include "replace.h"
-#include <tevent.h>
+#include "pytevent.h"
 
 #if PY_MAJOR_VERSION >= 3
 #define PyStr_Check PyUnicode_Check
@@ -41,11 +39,6 @@ void init_tevent(void);
 
 typedef struct {
 	PyObject_HEAD
-	struct tevent_context *ev;
-} TeventContext_Object;
-
-typedef struct {
-	PyObject_HEAD
 	struct tevent_queue *queue;
 } TeventQueue_Object;
 
diff --git a/lib/tevent/pytevent.h b/lib/tevent/pytevent.h
new file mode 100644
index 0000000..625ea02
--- /dev/null
+++ b/lib/tevent/pytevent.h
@@ -0,0 +1,34 @@
+/*
+   Unix SMB/CIFS implementation.
+   Python bindings for tevent
+
+   Copyright (C) Jelmer Vernooij 2010
+
+     ** 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 <Python.h>
+#include "replace.h"
+#include <tevent.h>
+
+typedef struct {
+	PyObject_HEAD
+	struct tevent_context *ev;
+} TeventContext_Object;
+
+#define pytevent_Context_AsTeventContext(pyobj) ((TeventContext_Object *)pyobj)->ev
-- 
2.7.4


From 210b5e5a3623c7cc0847c1e38b9d6302e6545c9f Mon Sep 17 00:00:00 2001
From: Andrew Bartlett <abartlet at samba.org>
Date: Wed, 8 Mar 2017 15:25:04 +1300
Subject: [PATCH 03/43] pymessaging: Allow the event context to be specified

This allows actual servers to be implemented

Signed-off-by: Andrew Bartlett <abartlet at samba.org>
Pair-Programmed: Gary Lockyer <gary at catalyst.net.nz>
---
 source4/lib/messaging/pymessaging.c | 27 +++++++++++++++++++++++----
 1 file changed, 23 insertions(+), 4 deletions(-)

diff --git a/source4/lib/messaging/pymessaging.c b/source4/lib/messaging/pymessaging.c
index f62354b..9f463c0 100644
--- a/source4/lib/messaging/pymessaging.c
+++ b/source4/lib/messaging/pymessaging.c
@@ -34,6 +34,7 @@
 #include "librpc/rpc/dcerpc.h"
 #include "librpc/gen_ndr/server_id.h"
 #include <pytalloc.h>
+#include <pytevent.h>
 
 void initmessaging(void);
 
@@ -75,19 +76,21 @@ typedef struct {
 	PyObject_HEAD
 	TALLOC_CTX *mem_ctx;
 	struct imessaging_context *msg_ctx;
+	PyObject *py_ev;
 } imessaging_Object;
 
 static PyObject *py_imessaging_connect(PyTypeObject *self, PyObject *args, PyObject *kwargs)
 {
 	struct tevent_context *ev;
-	const char *kwnames[] = { "own_id", "lp_ctx", NULL };
+	const char *kwnames[] = { "own_id", "lp_ctx", "ev", NULL };
 	PyObject *own_id = Py_None;
 	PyObject *py_lp_ctx = Py_None;
+	PyObject *py_ev = Py_None;
 	imessaging_Object *ret;
 	struct loadparm_context *lp_ctx;
 
-	if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|OO:connect", 
-		discard_const_p(char *, kwnames), &own_id, &py_lp_ctx)) {
+	if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|OOO:connect",
+					 discard_const_p(char *, kwnames), &own_id, &py_lp_ctx, &py_ev)) {
 		return NULL;
 	}
 
@@ -104,7 +107,22 @@ static PyObject *py_imessaging_connect(PyTypeObject *self, PyObject *args, PyObj
 		return NULL;
 	}
 
-	ev = s4_event_context_init(ret->mem_ctx);
+	if (py_ev == Py_None) {
+		ev = s4_event_context_init(ret->mem_ctx);
+		ret->py_ev = Py_None;
+	} else {
+		if (!py_check_dcerpc_type(py_ev, "tevent", "Context")) {
+			PyErr_SetString(PyExc_TypeError, "tevent Context object required");
+			return NULL;
+		}
+		ret->py_ev = py_ev;
+		ev = pytevent_Context_AsTeventContext(py_ev);
+		if (ev == NULL) {
+			PyErr_NoMemory();
+			return NULL;
+		}
+	}
+	Py_INCREF(ret->py_ev);
 
 	if (own_id != Py_None) {
 		struct server_id server_id;
@@ -135,6 +153,7 @@ static void py_imessaging_dealloc(PyObject *self)
 {
 	imessaging_Object *iface = (imessaging_Object *)self;
 	talloc_free(iface->msg_ctx);
+	Py_DECREF(iface->py_ev);
 	self->ob_type->tp_free(self);
 }
 
-- 
2.7.4


From ad0fad70a08627f6e87007fc45166bb349d49481 Mon Sep 17 00:00:00 2001
From: Andrew Bartlett <abartlet at samba.org>
Date: Wed, 8 Mar 2017 14:53:26 +1300
Subject: [PATCH 04/43] pymessaging: Add support for irpc_add_name

Signed-off-by: Andrew Bartlett <abartlet at samba.org>
Pair-Programmed: Gary Lockyer <gary at catalyst.net.nz>
---
 python/samba/tests/messaging.py     |  4 ++++
 source4/lib/messaging/pymessaging.c | 23 ++++++++++++++++++++++-
 2 files changed, 26 insertions(+), 1 deletion(-)

diff --git a/python/samba/tests/messaging.py b/python/samba/tests/messaging.py
index 5d32d60..1c5dfe5 100644
--- a/python/samba/tests/messaging.py
+++ b/python/samba/tests/messaging.py
@@ -49,6 +49,10 @@ class MessagingTests(TestCase):
         x = self.get_context()
         self.assertTrue(isinstance(x.server_id, server_id))
 
+    def test_add_name(self):
+        x = self.get_context()
+        x.irpc_add_name("samba.messaging test")
+
     def test_ping_speed(self):
         server_ctx = self.get_context((0, 1))
         def ping_callback(src, data):
diff --git a/source4/lib/messaging/pymessaging.c b/source4/lib/messaging/pymessaging.c
index 9f463c0..a493b22 100644
--- a/source4/lib/messaging/pymessaging.c
+++ b/source4/lib/messaging/pymessaging.c
@@ -260,6 +260,25 @@ static PyObject *py_imessaging_deregister(PyObject *self, PyObject *args, PyObje
 	Py_RETURN_NONE;
 }
 
+static PyObject *py_irpc_add_name(PyObject *self, PyObject *args, PyObject *kwargs)
+{
+	imessaging_Object *iface = (imessaging_Object *)self;
+	char *server_name;
+	NTSTATUS status;
+
+	if (!PyArg_ParseTuple(args, "s", &server_name)) {
+		return NULL;
+	}
+
+	status = irpc_add_name(iface->msg_ctx, server_name);
+	if (!NT_STATUS_IS_OK(status)) {
+		PyErr_SetNTSTATUS(status);
+		return NULL;
+	}
+
+	Py_RETURN_NONE;
+}
+
 static PyObject *py_irpc_servers_byname(PyObject *self, PyObject *args, PyObject *kwargs)
 {
 	imessaging_Object *iface = (imessaging_Object *)self;
@@ -360,10 +379,12 @@ static PyMethodDef py_imessaging_methods[] = {
 		"S.register(callback, msg_type=None) -> msg_type\nRegister a message handler" },
 	{ "deregister", (PyCFunction)py_imessaging_deregister, METH_VARARGS|METH_KEYWORDS,
 		"S.deregister(callback, msg_type) -> None\nDeregister a message handler" },
+	{ "irpc_add_name", (PyCFunction)py_irpc_add_name, METH_VARARGS,
+		"S.irpc_add_name(name) -> None\nAdd this context to the list of server_id values that are registered for a particular name" },
 	{ "irpc_servers_byname", (PyCFunction)py_irpc_servers_byname, METH_VARARGS,
 		"S.irpc_servers_byname(name) -> list\nGet list of server_id values that are registered for a particular name" },
 	{ "irpc_all_servers", (PyCFunction)py_irpc_all_servers, METH_NOARGS,
-		"S.irpc_servers_byname() -> list\nGet list of all registered names and the associated server_id values" },
+		"S.irpc_all_servers() -> list\nGet list of all registered names and the associated server_id values" },
 	{ NULL, NULL, 0, NULL }
 };
 
-- 
2.7.4


From c93d7236e167fd1a9faadc94e712ec72a7a11531 Mon Sep 17 00:00:00 2001
From: Andrew Bartlett <abartlet at samba.org>
Date: Mon, 20 Feb 2017 11:39:17 +1300
Subject: [PATCH 05/43] debug: Add debug class for auth_audit

This will be an audit stream of authentication and connection-level authorization

Signed-off-by: Andrew Bartlett <abartlet at samba.org>
Pair-Programmed: Gary Lockyer <gary at catalyst.net.nz>
---
 lib/util/debug.c | 1 +
 lib/util/debug.h | 1 +
 2 files changed, 2 insertions(+)

diff --git a/lib/util/debug.c b/lib/util/debug.c
index 8a04c25..009f362 100644
--- a/lib/util/debug.c
+++ b/lib/util/debug.c
@@ -537,6 +537,7 @@ static const char *default_classname_table[] = {
 	[DBGC_DNS] =		"dns",
 	[DBGC_LDB] =		"ldb",
 	[DBGC_TEVENT] =		"tevent",
+	[DBGC_AUTH_AUDIT] =	"auth_audit",
 };
 
 /*
diff --git a/lib/util/debug.h b/lib/util/debug.h
index 43c6aa0..786c809 100644
--- a/lib/util/debug.h
+++ b/lib/util/debug.h
@@ -89,6 +89,7 @@ bool dbghdr( int level, const char *location, const char *func);
 #define DBGC_DNS		21
 #define DBGC_LDB		22
 #define DBGC_TEVENT		23
+#define DBGC_AUTH_AUDIT		24
 
 /* So you can define DBGC_CLASS before including debug.h */
 #ifndef DBGC_CLASS
-- 
2.7.4


From 901faf174834409594f8e9a13fd39820cde7916f Mon Sep 17 00:00:00 2001
From: Andrew Bartlett <abartlet at samba.org>
Date: Mon, 20 Feb 2017 12:01:37 +1300
Subject: [PATCH 06/43] s4-smbd: Remember the original client and server IPs
 from the SMB connection

We need to know in the RPC server the original address the client came from
so that we can log this with the authentication audit information

Signed-off-by: Andrew Bartlett <abartlet at samba.org>
Pair-Programmed: Gary Lockyer <gary at catalyst.net.nz>
---
 source4/smbd/service_named_pipe.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/source4/smbd/service_named_pipe.c b/source4/smbd/service_named_pipe.c
index b75a9fa..02758b9 100644
--- a/source4/smbd/service_named_pipe.c
+++ b/source4/smbd/service_named_pipe.c
@@ -119,6 +119,9 @@ static void named_pipe_accept_done(struct tevent_req *subreq)
 		goto out;
 	}
 
+	conn->local_address = talloc_move(conn, &server);
+	conn->remote_address = talloc_move(conn, &client);
+
 	DEBUG(10, ("Accepted npa connection from %s. "
 		   "Client: %s (%s). Server: %s (%s)\n",
 		   tsocket_address_string(conn->remote_address, tmp_ctx),
-- 
2.7.4


From 8f376667835474ee513cb97e479efac9f5694886 Mon Sep 17 00:00:00 2001
From: Andrew Bartlett <abartlet at samba.org>
Date: Mon, 20 Feb 2017 12:04:52 +1300
Subject: [PATCH 07/43] s4-netlogon: Remember many more details in the
 auth_usersupplied info for future logs

This will allow a very verbose JSON line to be logged that others can audit from in the future

Signed-off-by: Andrew Bartlett <abartlet at samba.org>
Pair-Programmed: Gary Lockyer <gary at catalyst.net.nz>
---
 auth/common_auth.h                            |  9 ++++
 source4/rpc_server/netlogon/dcerpc_netlogon.c | 70 ++++++++++++++++++++-------
 2 files changed, 62 insertions(+), 17 deletions(-)

diff --git a/auth/common_auth.h b/auth/common_auth.h
index d1a775d..28b9bd7 100644
--- a/auth/common_auth.h
+++ b/auth/common_auth.h
@@ -44,6 +44,7 @@ struct auth_usersupplied_info
 {
 	const char *workstation_name;
 	const struct tsocket_address *remote_host;
+	const struct tsocket_address *local_host;
 
 	uint32_t logon_parameters;
 
@@ -70,6 +71,14 @@ struct auth_usersupplied_info
 		char *plaintext;
 	} password;
 	uint32_t flags;
+
+	struct {
+		uint32_t negotiate_flags;
+		enum netr_SchannelType secure_channel_type;
+		const char *computer_name;/* [charset(UTF8)] */
+		const char *account_name;/* [charset(UTF8)] */
+		struct dom_sid *sid;/* [unique] */
+	} netlogon_trust_account;
 };
 
 struct auth_method_context;
diff --git a/source4/rpc_server/netlogon/dcerpc_netlogon.c b/source4/rpc_server/netlogon/dcerpc_netlogon.c
index afa9b1c..60421f5 100644
--- a/source4/rpc_server/netlogon/dcerpc_netlogon.c
+++ b/source4/rpc_server/netlogon/dcerpc_netlogon.c
@@ -867,6 +867,8 @@ static NTSTATUS dcesrv_netr_LogonSamLogon_base(struct dcesrv_call_state *dce_cal
 	case NetlogonServiceInformation:
 	case NetlogonInteractiveTransitiveInformation:
 	case NetlogonServiceTransitiveInformation:
+	case NetlogonNetworkInformation:
+	case NetlogonNetworkTransitiveInformation:
 
 		/* TODO: we need to deny anonymous access here */
 		nt_status = auth_context_create(mem_ctx,
@@ -875,11 +877,46 @@ static NTSTATUS dcesrv_netr_LogonSamLogon_base(struct dcesrv_call_state *dce_cal
 						&auth_context);
 		NT_STATUS_NOT_OK_RETURN(nt_status);
 
-		user_info->logon_parameters = r->in.logon->password->identity_info.parameter_control;
-		user_info->client.account_name = r->in.logon->password->identity_info.account_name.string;
-		user_info->client.domain_name = r->in.logon->password->identity_info.domain_name.string;
-		user_info->workstation_name = r->in.logon->password->identity_info.workstation.string;
+		user_info->remote_host = dce_call->conn->remote_address;
+		user_info->local_host = dce_call->conn->local_address;
+
+		user_info->netlogon_trust_account.secure_channel_type
+			= creds->secure_channel_type;
+		user_info->netlogon_trust_account.negotiate_flags
+			= creds->negotiate_flags;
+
+		/*
+		 * These two can be unrelated when the account is
+		 * actually that of a trusted domain, so we want to
+		 * know which DC in that trusted domain contacted
+		 * us
+		 */
+		user_info->netlogon_trust_account.computer_name
+			= creds->computer_name;
+		user_info->netlogon_trust_account.account_name
+			= creds->computer_name;
+		user_info->netlogon_trust_account.sid
+			= creds->sid;
+
+	default:
+		/* We do not need to set up the user_info in this case */
+		break;
+	}
+
+	switch (r->in.logon_level) {
+	case NetlogonInteractiveInformation:
+	case NetlogonServiceInformation:
+	case NetlogonInteractiveTransitiveInformation:
+	case NetlogonServiceTransitiveInformation:
 
+		user_info->logon_parameters
+			= r->in.logon->password->identity_info.parameter_control;
+		user_info->client.account_name
+			= r->in.logon->password->identity_info.account_name.string;
+		user_info->client.domain_name
+			= r->in.logon->password->identity_info.domain_name.string;
+		user_info->workstation_name
+			= r->in.logon->password->identity_info.workstation.string;
 		user_info->flags |= USER_INFO_INTERACTIVE_LOGON;
 		user_info->password_state = AUTH_PASSWORD_HASH;
 
@@ -894,21 +931,20 @@ static NTSTATUS dcesrv_netr_LogonSamLogon_base(struct dcesrv_call_state *dce_cal
 		break;
 	case NetlogonNetworkInformation:
 	case NetlogonNetworkTransitiveInformation:
-
-		/* TODO: we need to deny anonymous access here */
-		nt_status = auth_context_create(mem_ctx,
-						dce_call->event_ctx, dce_call->msg_ctx,
-						dce_call->conn->dce_ctx->lp_ctx,
-						&auth_context);
-		NT_STATUS_NOT_OK_RETURN(nt_status);
-
-		nt_status = auth_context_set_challenge(auth_context, r->in.logon->network->challenge, "netr_LogonSamLogonWithFlags");
+		nt_status = auth_context_set_challenge(
+			auth_context,
+			r->in.logon->network->challenge,
+			"netr_LogonSamLogonWithFlags");
 		NT_STATUS_NOT_OK_RETURN(nt_status);
 
-		user_info->logon_parameters = r->in.logon->network->identity_info.parameter_control;
-		user_info->client.account_name = r->in.logon->network->identity_info.account_name.string;
-		user_info->client.domain_name = r->in.logon->network->identity_info.domain_name.string;
-		user_info->workstation_name = r->in.logon->network->identity_info.workstation.string;
+		user_info->logon_parameters
+			= r->in.logon->network->identity_info.parameter_control;
+		user_info->client.account_name
+			= r->in.logon->network->identity_info.account_name.string;
+		user_info->client.domain_name
+			= r->in.logon->network->identity_info.domain_name.string;
+		user_info->workstation_name
+			= r->in.logon->network->identity_info.workstation.string;
 
 		user_info->password_state = AUTH_PASSWORD_RESPONSE;
 		user_info->password.response.lanman = data_blob_talloc(mem_ctx, r->in.logon->network->lm.data, r->in.logon->network->lm.length);
-- 
2.7.4


From 5db5869932a7c5101ed0860122180d2ad61dd3cf Mon Sep 17 00:00:00 2001
From: Andrew Bartlett <abartlet at samba.org>
Date: Mon, 20 Feb 2017 13:32:47 +1300
Subject: [PATCH 08/43] gensec: Add
 gensec_{get,set}_target_service_description()

This allows a free text description of what the server-side service is for logging
purposes where the various services may be using the same Kerberos service or not
use Kerberos.

Signed-off-by: Andrew Bartlett <abartlet at samba.org>
Pair-Programmed: Gary Lockyer <gary at catalyst.net.nz>
---
 auth/gensec/gensec.c             | 29 +++++++++++++++++++++++++++++
 auth/gensec/gensec.h             | 17 +++++++++++++++++
 source4/auth/gensec/pygensec.c   | 25 +++++++++++++++++++++++--
 source4/rpc_server/dcesrv_auth.c | 14 ++++++++++++++
 4 files changed, 83 insertions(+), 2 deletions(-)

diff --git a/auth/gensec/gensec.c b/auth/gensec/gensec.c
index d623613..e413fbd 100644
--- a/auth/gensec/gensec.c
+++ b/auth/gensec/gensec.c
@@ -574,6 +574,7 @@ _PUBLIC_ struct cli_credentials *gensec_get_credentials(struct gensec_security *
 /**
  * Set the target service (such as 'http' or 'host') on a GENSEC context - ensures it is talloc()ed
  *
+ * This is used for Kerberos service principal name resolution.
  */
 
 _PUBLIC_ NTSTATUS gensec_set_target_service(struct gensec_security *gensec_security, const char *service)
@@ -595,6 +596,34 @@ _PUBLIC_ const char *gensec_get_target_service(struct gensec_security *gensec_se
 }
 
 /**
+ * Set the target service (such as 'samr') on an GENSEC context - ensures it is talloc()ed.
+ *
+ * This is not the Kerberos service principal, instead this is a
+ * constant value that can be logged as part of authentication and
+ * authorization logging
+ */
+_PUBLIC_ NTSTATUS gensec_set_target_service_description(struct gensec_security *gensec_security,
+							const char *service)
+{
+	gensec_security->target.service_description = talloc_strdup(gensec_security, service);
+	if (!gensec_security->target.service_description) {
+		return NT_STATUS_NO_MEMORY;
+	}
+	return NT_STATUS_OK;
+}
+
+_PUBLIC_ const char *gensec_get_target_service_description(struct gensec_security *gensec_security)
+{
+	if (gensec_security->target.service_description) {
+		return gensec_security->target.service_description;
+	} else if (gensec_security->target.service) {
+		return gensec_security->target.service;
+	}
+
+	return NULL;
+}
+
+/**
  * Set the target hostname (suitable for kerberos resolutation) on a GENSEC context - ensures it is talloc()ed
  *
  */
diff --git a/auth/gensec/gensec.h b/auth/gensec/gensec.h
index e8bd7b1..0c9fa26 100644
--- a/auth/gensec/gensec.h
+++ b/auth/gensec/gensec.h
@@ -50,6 +50,7 @@ struct gensec_target {
 	const char *principal;
 	const char *hostname;
 	const char *service;
+	const char *service_description;
 };
 
 #define GENSEC_FEATURE_SESSION_KEY	0x00000001
@@ -145,10 +146,26 @@ bool gensec_have_feature(struct gensec_security *gensec_security,
 			 uint32_t feature);
 NTTIME gensec_expire_time(struct gensec_security *gensec_security);
 NTSTATUS gensec_set_credentials(struct gensec_security *gensec_security, struct cli_credentials *credentials);
+/**
+ * Set the target service (such as 'http' or 'host') on a GENSEC context - ensures it is talloc()ed
+ *
+ * This is used for Kerberos service principal name resolution.
+ */
+
 NTSTATUS gensec_set_target_service(struct gensec_security *gensec_security, const char *service);
 const char *gensec_get_target_service(struct gensec_security *gensec_security);
 NTSTATUS gensec_set_target_hostname(struct gensec_security *gensec_security, const char *hostname);
 const char *gensec_get_target_hostname(struct gensec_security *gensec_security);
+/**
+ * Set the target service (such as 'samr') on an GENSEC context - ensures it is talloc()ed.
+ *
+ * This is not the Kerberos service principal, instead this is a
+ * constant value that can be logged as part of authentication and
+ * authorization logging
+ */
+const char *gensec_get_target_service_description(struct gensec_security *gensec_security);
+NTSTATUS gensec_set_target_service_description(struct gensec_security *gensec_security,
+					       const char *service);
 NTSTATUS gensec_session_key(struct gensec_security *gensec_security,
 			    TALLOC_CTX *mem_ctx,
 			    DATA_BLOB *session_key);
diff --git a/source4/auth/gensec/pygensec.c b/source4/auth/gensec/pygensec.c
index 946a082..d27fe28 100644
--- a/source4/auth/gensec/pygensec.c
+++ b/source4/auth/gensec/pygensec.c
@@ -241,6 +241,25 @@ static PyObject *py_gensec_set_target_service(PyObject *self, PyObject *args)
 	Py_RETURN_NONE;
 }
 
+static PyObject *py_gensec_set_target_service_description(PyObject *self, PyObject *args)
+{
+	struct gensec_security *security = pytalloc_get_type(self, struct gensec_security);
+	char *target_service_description;
+	NTSTATUS status;
+
+	if (!PyArg_ParseTuple(args, "s", &target_service_description))
+		return NULL;
+
+	status = gensec_set_target_service_description(security,
+						       target_service_description);
+	if (!NT_STATUS_IS_OK(status)) {
+		PyErr_SetNTSTATUS(status);
+		return NULL;
+	}
+
+	Py_RETURN_NONE;
+}
+
 static PyObject *py_gensec_set_credentials(PyObject *self, PyObject *args)
 {
 	PyObject *py_creds = Py_None;
@@ -617,9 +636,11 @@ static PyMethodDef py_gensec_security_methods[] = {
 	{ "set_credentials", (PyCFunction)py_gensec_set_credentials, METH_VARARGS, 
 		"S.start_client(credentials)" },
 	{ "set_target_hostname", (PyCFunction)py_gensec_set_target_hostname, METH_VARARGS, 
-		"S.start_target_hostname(target_hostname)" },
+		"S.start_target_hostname(target_hostname) \n This sets the Kerberos target hostname to obtain a ticket for." },
 	{ "set_target_service", (PyCFunction)py_gensec_set_target_service, METH_VARARGS, 
-		"S.start_target_service(target_service)" },
+		"S.start_target_service(target_service) \n This sets the Kerberos target service to obtain a ticket for.  The default value is 'host'" },
+	{ "set_target_service_description", (PyCFunction)py_gensec_set_target_service_description, METH_VARARGS,
+		"S.start_target_service_description(target_service_description) \n This description is set server-side and used in authentication and authorization logs.  The default value is that provided to set_target_service() or None."},
 	{ "session_info", (PyCFunction)py_gensec_session_info, METH_NOARGS,
 		"S.session_info() -> info" },
 	{ "session_key", (PyCFunction)py_gensec_session_key, METH_NOARGS,
diff --git a/source4/rpc_server/dcesrv_auth.c b/source4/rpc_server/dcesrv_auth.c
index af0079b..769b52b 100644
--- a/source4/rpc_server/dcesrv_auth.c
+++ b/source4/rpc_server/dcesrv_auth.c
@@ -125,6 +125,20 @@ bool dcesrv_auth_bind(struct dcesrv_call_state *call)
 		return false;
 	}
 
+	/*
+	 * We have to call this because we set the target_service for
+	 * Kerberos to NULL above, and in any case we wish to log a
+	 * more specific service target.
+	 *
+	 */
+	status = gensec_set_target_service_description(auth->gensec_security,
+						       "DCE/RPC");
+	if (!NT_STATUS_IS_OK(status)) {
+		DEBUG(1, ("Failed to call gensec_set_target_service_description %s\n",
+			  nt_errstr(status)));
+		return false;
+	}
+
 	if (call->conn->remote_address != NULL) {
 		status = gensec_set_remote_address(auth->gensec_security,
 						call->conn->remote_address);
-- 
2.7.4


From 3bce4f73bc0ff112a40410d831230a077f8d1c1e Mon Sep 17 00:00:00 2001
From: Andrew Bartlett <abartlet at samba.org>
Date: Mon, 20 Feb 2017 14:15:46 +1300
Subject: [PATCH 09/43] gensec: Pass service_description into
 auth_usersuppliedinfo during NTLMSSP

This allows the GENSEC service description to be read at authentication time
for logging, eg that the user authenticated to the SAMR server

Signed-off-by: Andrew Bartlett <abartlet at samba.org>
Pair-Programmed: Gary Lockyer <gary at catalyst.net.nz>
---
 auth/common_auth.h            | 2 ++
 auth/ntlmssp/ntlmssp_server.c | 2 ++
 2 files changed, 4 insertions(+)

diff --git a/auth/common_auth.h b/auth/common_auth.h
index 28b9bd7..1e9ca29 100644
--- a/auth/common_auth.h
+++ b/auth/common_auth.h
@@ -79,6 +79,8 @@ struct auth_usersupplied_info
 		const char *account_name;/* [charset(UTF8)] */
 		struct dom_sid *sid;/* [unique] */
 	} netlogon_trust_account;
+
+	const char *service_description;
 };
 
 struct auth_method_context;
diff --git a/auth/ntlmssp/ntlmssp_server.c b/auth/ntlmssp/ntlmssp_server.c
index ddee875..6d7cc2b 100644
--- a/auth/ntlmssp/ntlmssp_server.c
+++ b/auth/ntlmssp/ntlmssp_server.c
@@ -718,6 +718,8 @@ static NTSTATUS ntlmssp_server_check_password(struct gensec_security *gensec_sec
 	user_info->client.domain_name = ntlmssp_state->domain;
 	user_info->workstation_name = ntlmssp_state->client.netbios_name;
 	user_info->remote_host = gensec_get_remote_address(gensec_security);
+	user_info->service_description
+		= gensec_get_target_service_description(gensec_security);
 
 	user_info->password_state = AUTH_PASSWORD_RESPONSE;
 	user_info->password.response.lanman = ntlmssp_state->lm_resp;
-- 
2.7.4


From 1c8b2219e3179a3daea9e602c381ac9471a8b04a Mon Sep 17 00:00:00 2001
From: Andrew Bartlett <abartlet at samba.org>
Date: Mon, 20 Feb 2017 14:17:34 +1300
Subject: [PATCH 10/43] s3-auth: Pass service_description into gensec via
 auth_generic_prepare()

This allows the GENSEC service description to be set from the various callers
that go via this function.

The RPC service description is the name of the interface from the IDL.

Signed-off-by: Andrew Bartlett <abartlet at samba.org>
Pair-Programmed: Gary Lockyer <gary at catalyst.net.nz>
---
 source3/auth/auth_generic.c              | 9 +++++++++
 source3/auth/proto.h                     | 1 +
 source3/rpc_server/dcesrv_auth_generic.c | 7 ++++++-
 source3/rpc_server/dcesrv_auth_generic.h | 1 +
 source3/rpc_server/srv_pipe.c            | 6 +++++-
 source3/smbd/negprot.c                   | 8 ++++++++
 source3/smbd/seal.c                      | 1 +
 source3/smbd/sesssetup.c                 | 1 +
 source3/smbd/smb2_sesssetup.c            | 1 +
 9 files changed, 33 insertions(+), 2 deletions(-)

diff --git a/source3/auth/auth_generic.c b/source3/auth/auth_generic.c
index f9b9184..55555e8 100644
--- a/source3/auth/auth_generic.c
+++ b/source3/auth/auth_generic.c
@@ -233,6 +233,7 @@ NTSTATUS make_auth4_context(TALLOC_CTX *mem_ctx, struct auth4_context **auth4_co
 
 NTSTATUS auth_generic_prepare(TALLOC_CTX *mem_ctx,
 			      const struct tsocket_address *remote_address,
+			      const char *service_description,
 			      struct gensec_security **gensec_security_out)
 {
 	struct gensec_security *gensec_security;
@@ -377,6 +378,14 @@ NTSTATUS auth_generic_prepare(TALLOC_CTX *mem_ctx,
 		return nt_status;
 	}
 
+	nt_status = gensec_set_target_service_description(gensec_security,
+							  service_description);
+
+	if (!NT_STATUS_IS_OK(nt_status)) {
+		TALLOC_FREE(tmp_ctx);
+		return nt_status;
+	}
+
 	*gensec_security_out = talloc_steal(mem_ctx, gensec_security);
 	TALLOC_FREE(tmp_ctx);
 	return NT_STATUS_OK;
diff --git a/source3/auth/proto.h b/source3/auth/proto.h
index 5fd3158..3697211 100644
--- a/source3/auth/proto.h
+++ b/source3/auth/proto.h
@@ -99,6 +99,7 @@ NTSTATUS auth_domain_init(void);
 
 NTSTATUS make_auth4_context(TALLOC_CTX *mem_ctx, struct auth4_context **auth4_context_out);
 NTSTATUS auth_generic_prepare(TALLOC_CTX *mem_ctx, const struct tsocket_address *remote_address,
+			      const char *service_description,
 			      struct gensec_security **gensec_security_out);
 
 NTSTATUS auth_check_password_session_info(struct auth4_context *auth_context,
diff --git a/source3/rpc_server/dcesrv_auth_generic.c b/source3/rpc_server/dcesrv_auth_generic.c
index a338108..7bdfdee 100644
--- a/source3/rpc_server/dcesrv_auth_generic.c
+++ b/source3/rpc_server/dcesrv_auth_generic.c
@@ -29,12 +29,15 @@ static NTSTATUS auth_generic_server_authtype_start_as_root(TALLOC_CTX *mem_ctx,
 							   DATA_BLOB *token_in,
 							   DATA_BLOB *token_out,
 							   const struct tsocket_address *remote_address,
+							   const char *service_description,
 							   struct gensec_security **ctx)
 {
 	struct gensec_security *gensec_security = NULL;
 	NTSTATUS status;
 
-	status = auth_generic_prepare(talloc_tos(), remote_address, &gensec_security);
+	status = auth_generic_prepare(talloc_tos(), remote_address,
+				      service_description,
+				      &gensec_security);
 	if (!NT_STATUS_IS_OK(status)) {
 		DEBUG(0, (__location__ ": auth_generic_prepare failed: %s\n",
 			  nt_errstr(status)));
@@ -67,6 +70,7 @@ NTSTATUS auth_generic_server_authtype_start(TALLOC_CTX *mem_ctx,
 					    DATA_BLOB *token_in,
 					    DATA_BLOB *token_out,
 					    const struct tsocket_address *remote_address,
+					    const char *service_description,
 					    struct gensec_security **ctx)
 {
 	NTSTATUS status;
@@ -78,6 +82,7 @@ NTSTATUS auth_generic_server_authtype_start(TALLOC_CTX *mem_ctx,
 							    token_in,
 							    token_out,
 							    remote_address,
+							    service_description,
 							    ctx);
 	unbecome_root();
 	return status;
diff --git a/source3/rpc_server/dcesrv_auth_generic.h b/source3/rpc_server/dcesrv_auth_generic.h
index f288c94..36e1a83 100644
--- a/source3/rpc_server/dcesrv_auth_generic.h
+++ b/source3/rpc_server/dcesrv_auth_generic.h
@@ -27,6 +27,7 @@ NTSTATUS auth_generic_server_authtype_start(TALLOC_CTX *mem_ctx,
 					    DATA_BLOB *token_in,
 					    DATA_BLOB *token_out,
 					    const struct tsocket_address *remote_address,
+					    const char *service_description,
 					    struct gensec_security **ctx);
 
 NTSTATUS auth_generic_server_step(struct gensec_security *ctx,
diff --git a/source3/rpc_server/srv_pipe.c b/source3/rpc_server/srv_pipe.c
index 407d8d7..4a63dd7 100644
--- a/source3/rpc_server/srv_pipe.c
+++ b/source3/rpc_server/srv_pipe.c
@@ -517,6 +517,7 @@ bool is_known_pipename(const char *pipename, struct ndr_syntax_id *syntax)
 static bool pipe_auth_generic_bind(struct pipes_struct *p,
 				   struct ncacn_packet *pkt,
 				   struct dcerpc_auth *auth_info,
+				   const char *service_description,
 				   DATA_BLOB *response)
 {
 	TALLOC_CTX *mem_ctx = pkt;
@@ -529,6 +530,7 @@ static bool pipe_auth_generic_bind(struct pipes_struct *p,
 						    &auth_info->credentials,
 						    response,
 						    p->remote_address,
+						    service_description,
 						    &gensec_security);
 	if (!NT_STATUS_IS_OK(status) &&
 	    !NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED))
@@ -813,7 +815,9 @@ static bool api_pipe_bind_req(struct pipes_struct *p,
 		}
 
 		if (!pipe_auth_generic_bind(p, pkt,
-					    &auth_info, &auth_resp)) {
+					    &auth_info,
+					    table->name,
+					    &auth_resp)) {
 			goto err_exit;
 		}
 	} else {
diff --git a/source3/smbd/negprot.c b/source3/smbd/negprot.c
index 838ff45..119f2a9 100644
--- a/source3/smbd/negprot.c
+++ b/source3/smbd/negprot.c
@@ -171,7 +171,15 @@ DATA_BLOB negprot_spnego(TALLOC_CTX *ctx, struct smbXsrv_connection *xconn)
 	/* See if we can get an SPNEGO blob */
 	status = auth_generic_prepare(talloc_tos(),
 				      xconn->remote_address,
+				      "smb",
 				      &gensec_security);
+
+	/*
+	 * There is no need to set a remote address or similar as we
+	 * are just interested in the SPNEGO blob, we never keep this
+	 * context.
+	 */
+
 	if (NT_STATUS_IS_OK(status)) {
 		status = gensec_start_mech_by_oid(gensec_security, GENSEC_OID_SPNEGO);
 		if (NT_STATUS_IS_OK(status)) {
diff --git a/source3/smbd/seal.c b/source3/smbd/seal.c
index d2c8951..f406c43 100644
--- a/source3/smbd/seal.c
+++ b/source3/smbd/seal.c
@@ -77,6 +77,7 @@ static NTSTATUS make_auth_gensec(const struct tsocket_address *remote_address,
 	NTSTATUS status;
 
 	status = auth_generic_prepare(es, remote_address,
+				      "SMB encryption",
 				      &es->gensec_security);
 	if (!NT_STATUS_IS_OK(status)) {
 		return nt_status_squash(status);
diff --git a/source3/smbd/sesssetup.c b/source3/smbd/sesssetup.c
index 8ec6093..5196e4f 100644
--- a/source3/smbd/sesssetup.c
+++ b/source3/smbd/sesssetup.c
@@ -247,6 +247,7 @@ static void reply_sesssetup_and_X_spnego(struct smb_request *req)
 
 	if (auth->gensec == NULL) {
 		status = auth_generic_prepare(session, xconn->remote_address,
+					      "SMB",
 					      &auth->gensec);
 		if (!NT_STATUS_IS_OK(status)) {
 			TALLOC_FREE(session);
diff --git a/source3/smbd/smb2_sesssetup.c b/source3/smbd/smb2_sesssetup.c
index 6a0caac..7e3102b 100644
--- a/source3/smbd/smb2_sesssetup.c
+++ b/source3/smbd/smb2_sesssetup.c
@@ -855,6 +855,7 @@ auth:
 	if (state->auth->gensec == NULL) {
 		status = auth_generic_prepare(state->auth,
 					      state->smb2req->xconn->remote_address,
+					      "SMB2",
 					      &state->auth->gensec);
 		if (tevent_req_nterror(req, status)) {
 			return tevent_req_post(req, ev);
-- 
2.7.4


From 002ba253d101dbcc5d8354e33436d4a878d39d0e Mon Sep 17 00:00:00 2001
From: Andrew Bartlett <abartlet at samba.org>
Date: Mon, 20 Feb 2017 14:18:57 +1300
Subject: [PATCH 11/43] ntlm_auth: Set ntlm_auth as the service_description
 into gensec

This allows this use case to be clearly found when logged.

Signed-off-by: Andrew Bartlett <abartlet at samba.org>
Pair-Programmed: Gary Lockyer <gary at catalyst.net.nz>
---
 source3/utils/ntlm_auth.c | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/source3/utils/ntlm_auth.c b/source3/utils/ntlm_auth.c
index 829eb8f..516b485 100644
--- a/source3/utils/ntlm_auth.c
+++ b/source3/utils/ntlm_auth.c
@@ -1214,6 +1214,17 @@ static NTSTATUS ntlm_auth_prepare_gensec_server(TALLOC_CTX *mem_ctx,
 	
 	gensec_set_credentials(gensec_security, server_credentials);
 
+	/*
+	 * TODO: Allow the caller to pass their own description here
+	 * via a command-line option
+	 */
+	nt_status = gensec_set_target_service_description(gensec_security,
+							  "ntlm_auth");
+	if (!NT_STATUS_IS_OK(nt_status)) {
+		TALLOC_FREE(tmp_ctx);
+		return nt_status;
+	}
+
 	talloc_unlink(tmp_ctx, lp_ctx);
 	talloc_unlink(tmp_ctx, server_credentials);
 	talloc_unlink(tmp_ctx, gensec_settings);
-- 
2.7.4


From 2035ab1a326b3c72a4729791ddf257c5895f3df8 Mon Sep 17 00:00:00 2001
From: Andrew Bartlett <abartlet at samba.org>
Date: Mon, 20 Feb 2017 14:52:07 +1300
Subject: [PATCH 12/43] auth: Fill in user_info->service_description from all
 callers

This will allow the logging code to make clear which protocol an authentication was for.

Signed-off-by: Andrew Bartlett <abartlet at samba.org>
Pair-Programmed: Gary Lockyer <gary at catalyst.net.nz>
---
 source3/auth/auth_ntlmssp.c                   |  1 +
 source3/auth/auth_util.c                      | 20 +++++++++++++++-----
 source3/auth/proto.h                          |  5 +++++
 source3/auth/user_info.c                      |  7 +++++++
 source3/smbd/sesssetup.c                      |  5 ++++-
 source3/torture/pdbtest.c                     |  3 ++-
 source3/winbindd/winbindd_pam.c               | 10 +++++++++-
 source4/rpc_server/netlogon/dcerpc_netlogon.c |  2 ++
 source4/smb_server/smb/sesssetup.c            |  4 ++++
 9 files changed, 49 insertions(+), 8 deletions(-)

diff --git a/source3/auth/auth_ntlmssp.c b/source3/auth/auth_ntlmssp.c
index a0e4902..71b8183 100644
--- a/source3/auth/auth_ntlmssp.c
+++ b/source3/auth/auth_ntlmssp.c
@@ -163,6 +163,7 @@ NTSTATUS auth3_check_password(struct auth4_context *auth4_context,
 				       user_info->client.domain_name,
 				       user_info->workstation_name,
 				       user_info->remote_host,
+				       user_info->service_description,
 	                               user_info->password.response.lanman.data ? &user_info->password.response.lanman : NULL,
 	                               user_info->password.response.nt.data ? &user_info->password.response.nt : NULL,
 				       NULL, NULL, NULL,
diff --git a/source3/auth/auth_util.c b/source3/auth/auth_util.c
index 5d9f0e0..d015165 100644
--- a/source3/auth/auth_util.c
+++ b/source3/auth/auth_util.c
@@ -97,6 +97,7 @@ NTSTATUS make_user_info_map(TALLOC_CTX *mem_ctx,
 			    const char *client_domain,
 			    const char *workstation_name,
 			    const struct tsocket_address *remote_address,
+			    const char *service_description,
 			    const DATA_BLOB *lm_pwd,
 			    const DATA_BLOB *nt_pwd,
 			    const struct samr_Password *lm_interactive_pwd,
@@ -149,10 +150,11 @@ NTSTATUS make_user_info_map(TALLOC_CTX *mem_ctx,
 	 * primary domain name */
 
 	result = make_user_info(mem_ctx, user_info, smb_name, internal_username,
-			      client_domain, domain, workstation_name,
-			      remote_address, lm_pwd, nt_pwd,
-			      lm_interactive_pwd, nt_interactive_pwd,
-			      plaintext, password_state);
+				client_domain, domain, workstation_name,
+				remote_address, service_description,
+				lm_pwd, nt_pwd,
+				lm_interactive_pwd, nt_interactive_pwd,
+				plaintext, password_state);
 	if (NT_STATUS_IS_OK(result)) {
 		/* We have tried mapping */
 		(*user_info)->mapped_state = true;
@@ -188,6 +190,7 @@ bool make_user_info_netlogon_network(TALLOC_CTX *mem_ctx,
 				    smb_name, client_domain, 
 				    workstation_name,
 				    remote_address,
+				    "SamLogon",
 				    lm_pwd_len ? &lm_blob : NULL, 
 				    nt_pwd_len ? &nt_blob : NULL,
 				    NULL, NULL, NULL,
@@ -259,6 +262,7 @@ bool make_user_info_netlogon_interactive(TALLOC_CTX *mem_ctx,
 			user_info, 
 			smb_name, client_domain, workstation_name,
 			remote_address,
+			"SamLogon",
 			lm_interactive_pwd ? &local_lm_blob : NULL,
 			nt_interactive_pwd ? &local_nt_blob : NULL,
 			lm_interactive_pwd ? &lm_pwd : NULL,
@@ -286,6 +290,7 @@ bool make_user_info_for_reply(TALLOC_CTX *mem_ctx,
 			      const char *smb_name, 
 			      const char *client_domain,
 			      const struct tsocket_address *remote_address,
+			      const char *service_description,
 			      const uint8_t chal[8],
 			      DATA_BLOB plaintext_password)
 {
@@ -333,6 +338,7 @@ bool make_user_info_for_reply(TALLOC_CTX *mem_ctx,
 		user_info, smb_name, smb_name, client_domain, client_domain, 
 		get_remote_machine_name(),
 		remote_address,
+	        service_description,
 		local_lm_blob.data ? &local_lm_blob : NULL,
 		local_nt_blob.data ? &local_nt_blob : NULL,
 		NULL, NULL,
@@ -357,7 +363,8 @@ NTSTATUS make_user_info_for_reply_enc(TALLOC_CTX *mem_ctx,
                                       const char *smb_name,
                                       const char *client_domain,
 				      const struct tsocket_address *remote_address,
-                                      DATA_BLOB lm_resp, DATA_BLOB nt_resp)
+				      const char *service_description,
+				      DATA_BLOB lm_resp, DATA_BLOB nt_resp)
 {
 	bool allow_raw = lp_raw_ntlmv2_auth();
 
@@ -378,6 +385,7 @@ NTSTATUS make_user_info_for_reply_enc(TALLOC_CTX *mem_ctx,
 			      client_domain, client_domain, 
 			      get_remote_machine_name(),
 			      remote_address,
+			      service_description,
 			      lm_resp.data && (lm_resp.length > 0) ? &lm_resp : NULL,
 			      nt_resp.data && (nt_resp.length > 0) ? &nt_resp : NULL,
 			      NULL, NULL, NULL,
@@ -390,6 +398,7 @@ NTSTATUS make_user_info_for_reply_enc(TALLOC_CTX *mem_ctx,
 
 bool make_user_info_guest(TALLOC_CTX *mem_ctx,
 			  const struct tsocket_address *remote_address,
+			  const char *service_description,
 			  struct auth_usersupplied_info **user_info)
 {
 	NTSTATUS nt_status;
@@ -400,6 +409,7 @@ bool make_user_info_guest(TALLOC_CTX *mem_ctx,
 				   "","", 
 				   "", 
 				   remote_address,
+				   service_description,
 				   NULL, NULL, 
 				   NULL, NULL, 
 				   NULL,
diff --git a/source3/auth/proto.h b/source3/auth/proto.h
index 3697211..69fa20c 100644
--- a/source3/auth/proto.h
+++ b/source3/auth/proto.h
@@ -154,6 +154,7 @@ NTSTATUS make_user_info_map(TALLOC_CTX *mem_ctx,
 			    const char *client_domain,
 			    const char *workstation_name,
 			    const struct tsocket_address *remote_address,
+			    const char *service_description,
 			    const DATA_BLOB *lm_pwd,
 			    const DATA_BLOB *nt_pwd,
 			    const struct samr_Password *lm_interactive_pwd,
@@ -186,6 +187,7 @@ bool make_user_info_for_reply(TALLOC_CTX *mem_ctx,
 			      const char *smb_name,
 			      const char *client_domain,
 			      const struct tsocket_address *remote_address,
+			      const char *service_description,
 			      const uint8_t chal[8],
 			      DATA_BLOB plaintext_password);
 NTSTATUS make_user_info_for_reply_enc(TALLOC_CTX *mem_ctx,
@@ -193,9 +195,11 @@ NTSTATUS make_user_info_for_reply_enc(TALLOC_CTX *mem_ctx,
                                       const char *smb_name,
                                       const char *client_domain,
 				      const struct tsocket_address *remote_address,
+				      const char *service_description,
                                       DATA_BLOB lm_resp, DATA_BLOB nt_resp);
 bool make_user_info_guest(TALLOC_CTX *mem_ctx,
 			  const struct tsocket_address *remote_address,
+			  const char *service_description,
 			  struct auth_usersupplied_info **user_info);
 
 struct samu;
@@ -264,6 +268,7 @@ NTSTATUS make_user_info(TALLOC_CTX *mem_ctx,
 			const char *domain,
 			const char *workstation_name,
 			const struct tsocket_address *remote_address,
+			const char *service_description,
 			const DATA_BLOB *lm_pwd,
 			const DATA_BLOB *nt_pwd,
 			const struct samr_Password *lm_interactive_pwd,
diff --git a/source3/auth/user_info.c b/source3/auth/user_info.c
index 0d5176d..c410d22 100644
--- a/source3/auth/user_info.c
+++ b/source3/auth/user_info.c
@@ -49,6 +49,7 @@ NTSTATUS make_user_info(TALLOC_CTX *mem_ctx,
 			const char *domain,
 			const char *workstation_name,
 			const struct tsocket_address *remote_address,
+			const char *service_description,
 			const DATA_BLOB *lm_pwd,
 			const DATA_BLOB *nt_pwd,
 			const struct samr_Password *lm_interactive_pwd,
@@ -105,6 +106,12 @@ NTSTATUS make_user_info(TALLOC_CTX *mem_ctx,
 		return NT_STATUS_NO_MEMORY;
 	}
 
+	user_info->service_description = talloc_strdup(user_info, service_description);
+	if (user_info->service_description == NULL) {
+		TALLOC_FREE(user_info);
+		return NT_STATUS_NO_MEMORY;
+	}
+
 	DEBUG(5,("making blobs for %s's user_info struct\n", internal_username));
 
 	if (lm_pwd && lm_pwd->data) {
diff --git a/source3/smbd/sesssetup.c b/source3/smbd/sesssetup.c
index 5196e4f..3157dfd 100644
--- a/source3/smbd/sesssetup.c
+++ b/source3/smbd/sesssetup.c
@@ -97,7 +97,8 @@ static NTSTATUS check_guest_password(const struct tsocket_address *remote_addres
 	auth_context->get_ntlm_challenge(auth_context,
 					 chal);
 
-	if (!make_user_info_guest(talloc_tos(), remote_address, &user_info)) {
+	if (!make_user_info_guest(talloc_tos(), remote_address, "smb",
+				  &user_info)) {
 		TALLOC_FREE(auth_context);
 		return NT_STATUS_NO_MEMORY;
 	}
@@ -896,6 +897,7 @@ void reply_sesssetup_and_X(struct smb_request *req)
 							 &user_info, user,
 							 domain,
 							 sconn->remote_address,
+							 "smb",
 							 lm_resp, nt_resp);
 		if (NT_STATUS_IS_OK(nt_status)) {
 			nt_status = auth_check_password_session_info(negprot_auth_context, 
@@ -917,6 +919,7 @@ void reply_sesssetup_and_X(struct smb_request *req)
 						      &user_info,
 						      user, domain,
 						      sconn->remote_address,
+						      "smb",
 						      chal,
 						      plaintext_password)) {
 				nt_status = NT_STATUS_NO_MEMORY;
diff --git a/source3/torture/pdbtest.c b/source3/torture/pdbtest.c
index fe51a76..56bacd5 100644
--- a/source3/torture/pdbtest.c
+++ b/source3/torture/pdbtest.c
@@ -280,7 +280,8 @@ static bool test_auth(TALLOC_CTX *mem_ctx, struct samu *pdb_entry)
 	status = make_user_info(mem_ctx,
 				&user_info, pdb_get_username(pdb_entry), pdb_get_username(pdb_entry),
 				pdb_get_domain(pdb_entry), pdb_get_domain(pdb_entry), lp_netbios_name(), 
-				tsocket_address, NULL, &nt_resp, NULL, NULL, NULL, 
+				tsocket_address, "pdbtest",
+				NULL, &nt_resp, NULL, NULL, NULL,
 				AUTH_PASSWORD_RESPONSE);
 	if (!NT_STATUS_IS_OK(status)) {
 		DEBUG(0, ("Failed to test authentication with check_sam_security_info3: %s\n", nt_errstr(status)));
diff --git a/source3/winbindd/winbindd_pam.c b/source3/winbindd/winbindd_pam.c
index 782b28a..816991d 100644
--- a/source3/winbindd/winbindd_pam.c
+++ b/source3/winbindd/winbindd_pam.c
@@ -1247,8 +1247,16 @@ static NTSTATUS winbindd_dual_auth_passdb(TALLOC_CTX *mem_ctx,
 		TALLOC_FREE(frame);
 		return NT_STATUS_NO_MEMORY;
 	}
+
+	/*
+	 * TODO: We should get the service description passed in from
+	 * the winbind client, so we can have "smb2", "squid" or "samr" logged
+	 * here.
+	 */
 	status = make_user_info(frame, &user_info, user, user, domain, domain,
-				lp_netbios_name(), local, lm_resp, nt_resp, NULL, NULL,
+				lp_netbios_name(), local,
+				"winbind",
+				lm_resp, nt_resp, NULL, NULL,
 				NULL, AUTH_PASSWORD_RESPONSE);
 	if (!NT_STATUS_IS_OK(status)) {
 		DEBUG(10, ("make_user_info failed: %s\n", nt_errstr(status)));
diff --git a/source4/rpc_server/netlogon/dcerpc_netlogon.c b/source4/rpc_server/netlogon/dcerpc_netlogon.c
index 60421f5..c10ce09 100644
--- a/source4/rpc_server/netlogon/dcerpc_netlogon.c
+++ b/source4/rpc_server/netlogon/dcerpc_netlogon.c
@@ -858,6 +858,8 @@ static NTSTATUS dcesrv_netr_LogonSamLogon_base(struct dcesrv_call_state *dce_cal
 	user_info = talloc_zero(mem_ctx, struct auth_usersupplied_info);
 	NT_STATUS_HAVE_NO_MEMORY(user_info);
 
+	user_info->service_description = "SamLogon";
+
 	netlogon_creds_decrypt_samlogon_logon(creds,
 					      r->in.logon_level,
 					      r->in.logon);
diff --git a/source4/smb_server/smb/sesssetup.c b/source4/smb_server/smb/sesssetup.c
index e06853a..94f8bbc 100644
--- a/source4/smb_server/smb/sesssetup.c
+++ b/source4/smb_server/smb/sesssetup.c
@@ -148,6 +148,8 @@ static void sesssetup_old(struct smbsrv_request *req, union smb_sesssetup *sess)
 
 	user_info = talloc_zero(req, struct auth_usersupplied_info);
 	if (!user_info) goto nomem;
+
+	user_info->service_description = "smb";
 	
 	user_info->mapped_state = false;
 	user_info->logon_parameters = 0;
@@ -325,6 +327,8 @@ static void sesssetup_nt1(struct smbsrv_request *req, union smb_sesssetup *sess)
 	user_info = talloc_zero(req, struct auth_usersupplied_info);
 	if (!user_info) goto nomem;
 
+	user_info->service_description = "smb";
+
 	user_info->mapped_state = false;
 	user_info->logon_parameters = 0;
 	user_info->flags = 0;
-- 
2.7.4


From 99982c2d134c84dbbe50b460c98b53f92b313fa9 Mon Sep 17 00:00:00 2001
From: Andrew Bartlett <abartlet at samba.org>
Date: Mon, 20 Feb 2017 15:54:47 +1300
Subject: [PATCH 13/43] s4-ldap_server: Split gensec setup into a helper
 function

This makes the error handling simpler when we set more
details onto the gensec context.

Signed-off-by: Andrew Bartlett <abartlet at samba.org>
Pair-Programmed: Gary Lockyer <gary at catalyst.net.nz>
---
 source4/ldap_server/ldap_bind.c | 59 ++++++++++++++++++++++++++---------------
 1 file changed, 37 insertions(+), 22 deletions(-)

diff --git a/source4/ldap_server/ldap_bind.c b/source4/ldap_server/ldap_bind.c
index aad8931..8362315 100644
--- a/source4/ldap_server/ldap_bind.c
+++ b/source4/ldap_server/ldap_bind.c
@@ -180,6 +180,38 @@ static NTSTATUS ldapsrv_sasl_postprocess_recv(struct tevent_req *req)
 	return tevent_req_simple_recv_ntstatus(req);
 }
 
+static NTSTATUS ldapsrv_setup_gensec(struct ldapsrv_connection *conn,
+				     const char *sasl_mech,
+				     struct gensec_security **_gensec_security)
+{
+	NTSTATUS status;
+
+	struct gensec_security *gensec_security;
+
+	status = samba_server_gensec_start(conn,
+					   conn->connection->event.ctx,
+					   conn->connection->msg_ctx,
+					   conn->lp_ctx,
+					   conn->server_credentials,
+					   "ldap",
+					   &gensec_security);
+	if (!NT_STATUS_IS_OK(status)) {
+		return status;
+	}
+
+	gensec_want_feature(gensec_security, GENSEC_FEATURE_ASYNC_REPLIES);
+	gensec_want_feature(gensec_security, GENSEC_FEATURE_LDAP_STYLE);
+
+	status = gensec_start_mech_by_sasl_name(gensec_security, sasl_mech);
+
+	if (!NT_STATUS_IS_OK(status)) {
+		return status;
+	}
+
+	*_gensec_security = gensec_security;
+	return status;
+}
+
 static NTSTATUS ldapsrv_BindSASL(struct ldapsrv_call *call)
 {
 	struct ldap_BindRequest *req = &call->request->r.BindRequest;
@@ -209,32 +241,15 @@ static NTSTATUS ldapsrv_BindSASL(struct ldapsrv_call *call)
 	if (!conn->gensec) {
 		conn->session_info = NULL;
 
-		status = samba_server_gensec_start(conn,
-						   conn->connection->event.ctx,
-						   conn->connection->msg_ctx,
-						   conn->lp_ctx,
-						   conn->server_credentials,
-						   "ldap",
-						   &conn->gensec);
+		status = ldapsrv_setup_gensec(conn, req->creds.SASL.mechanism,
+					      &conn->gensec);
 		if (!NT_STATUS_IS_OK(status)) {
-			DEBUG(1, ("Failed to start GENSEC server code: %s\n", nt_errstr(status)));
+			DEBUG(1, ("Failed to start GENSEC server for [%s] code: %s\n",
+				  ldb_binary_encode_string(call, req->creds.SASL.mechanism),
+				  nt_errstr(status)));
 			result = LDAP_OPERATIONS_ERROR;
 			errstr = talloc_asprintf(reply, "SASL: Failed to start authentication system: %s", 
 						 nt_errstr(status));
-		} else {
-
-			gensec_want_feature(conn->gensec, GENSEC_FEATURE_ASYNC_REPLIES);
-			gensec_want_feature(conn->gensec, GENSEC_FEATURE_LDAP_STYLE);
-			
-			status = gensec_start_mech_by_sasl_name(conn->gensec, req->creds.SASL.mechanism);
-			
-			if (!NT_STATUS_IS_OK(status)) {
-				DEBUG(1, ("Failed to start GENSEC SASL[%s] server code: %s\n", 
-					  req->creds.SASL.mechanism, nt_errstr(status)));
-				result = LDAP_OPERATIONS_ERROR;
-				errstr = talloc_asprintf(reply, "SASL:[%s]: Failed to start authentication backend: %s", 
-							 req->creds.SASL.mechanism, nt_errstr(status));
-			}
 		}
 	}
 
-- 
2.7.4


From 30496c0f422f16c62481c32f44051ca07e4fa3d0 Mon Sep 17 00:00:00 2001
From: Andrew Bartlett <abartlet at samba.org>
Date: Tue, 21 Feb 2017 14:15:05 +1300
Subject: [PATCH 14/43] s4-ldap_server: Set remote and local address values
 into GENSEC

This will allow channel bindings and logging of the address values used during
authentication

Signed-off-by: Andrew Bartlett <abartlet at samba.org>
Pair-Programmed: Gary Lockyer <gary at catalyst.net.nz>
---
 source4/ldap_server/ldap_bind.c | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/source4/ldap_server/ldap_bind.c b/source4/ldap_server/ldap_bind.c
index 8362315..332bad3 100644
--- a/source4/ldap_server/ldap_bind.c
+++ b/source4/ldap_server/ldap_bind.c
@@ -199,6 +199,18 @@ static NTSTATUS ldapsrv_setup_gensec(struct ldapsrv_connection *conn,
 		return status;
 	}
 
+	status = gensec_set_remote_address(gensec_security,
+					   conn->connection->remote_address);
+	if (!NT_STATUS_IS_OK(status)) {
+		return status;
+	}
+
+	status = gensec_set_local_address(gensec_security,
+					  conn->connection->local_address);
+	if (!NT_STATUS_IS_OK(status)) {
+		return status;
+	}
+
 	gensec_want_feature(gensec_security, GENSEC_FEATURE_ASYNC_REPLIES);
 	gensec_want_feature(gensec_security, GENSEC_FEATURE_LDAP_STYLE);
 
-- 
2.7.4


From 676ee4adac0a385a1f2fbae1faf55e2cd6314dfc Mon Sep 17 00:00:00 2001
From: Andrew Bartlett <abartlet at samba.org>
Date: Thu, 9 Mar 2017 15:10:14 +1300
Subject: [PATCH 15/43] s4-ldap_server: Do not set conn->session_info to NULL
 until a new session_info is created

We need this to have a valid value at all times, and we are still anonymous
until the new bind completes

Signed-off-by: Andrew Bartlett <abartlet at samba.org>
Pair-Programmed: Gary Lockyer <gary at catalyst.net.nz>
---
 source4/ldap_server/ldap_bind.c | 2 --
 1 file changed, 2 deletions(-)

diff --git a/source4/ldap_server/ldap_bind.c b/source4/ldap_server/ldap_bind.c
index 332bad3..e0f13f2 100644
--- a/source4/ldap_server/ldap_bind.c
+++ b/source4/ldap_server/ldap_bind.c
@@ -251,8 +251,6 @@ static NTSTATUS ldapsrv_BindSASL(struct ldapsrv_call *call)
 	 */
 
 	if (!conn->gensec) {
-		conn->session_info = NULL;
-
 		status = ldapsrv_setup_gensec(conn, req->creds.SASL.mechanism,
 					      &conn->gensec);
 		if (!NT_STATUS_IS_OK(status)) {
-- 
2.7.4


From 284d7c58630ac49253baab8883b370cb0ad0743d Mon Sep 17 00:00:00 2001
From: Andrew Bartlett <abartlet at samba.org>
Date: Mon, 20 Feb 2017 15:55:34 +1300
Subject: [PATCH 16/43] auth: Add a reminder about the strings currently used
 for auditing

We will soon have a much better replacement, but a note here may help some in the transition

Signed-off-by: Andrew Bartlett <abartlet at samba.org>
Pair-Programmed: Gary Lockyer <gary at catalyst.net.nz>
---
 source3/auth/auth.c      | 4 ++++
 source4/auth/ntlm/auth.c | 4 ++++
 2 files changed, 8 insertions(+)

diff --git a/source3/auth/auth.c b/source3/auth/auth.c
index 1cbe46e..ebd5597 100644
--- a/source3/auth/auth.c
+++ b/source3/auth/auth.c
@@ -315,6 +315,10 @@ fail:
 
 	/* failed authentication; check for guest lapping */
 
+	/*
+	 * Please try not to change this string, it is probably in use
+	 * in audit logging tools
+	 */
 	DEBUG(2, ("check_ntlm_password:  Authentication for user [%s] -> [%s] FAILED with error %s\n",
 		  user_info->client.account_name, user_info->mapped.account_name,
 		  nt_errstr(nt_status)));
diff --git a/source4/auth/ntlm/auth.c b/source4/auth/ntlm/auth.c
index 05d6c3c..310cab4 100644
--- a/source4/auth/ntlm/auth.c
+++ b/source4/auth/ntlm/auth.c
@@ -431,6 +431,10 @@ _PUBLIC_ NTSTATUS auth_check_password_recv(struct tevent_req *req,
 	NTSTATUS status;
 
 	if (tevent_req_is_nterror(req, &status)) {
+		/*
+		 * Please try not to change this string, it is probably in use
+		 * in audit logging tools
+		 */
 		DEBUG(2,("auth_check_password_recv: "
 			 "%s authentication for user [%s\\%s] "
 			 "FAILED with error %s\n",
-- 
2.7.4


From fa20e84c5c75df5b2cbcb6910edf334e79fc73f4 Mon Sep 17 00:00:00 2001
From: Andrew Bartlett <abartlet at samba.org>
Date: Mon, 20 Feb 2017 15:57:03 +1300
Subject: [PATCH 17/43] ldap_server: Move code into
 authenticate_ldap_simple_bind()

This function is only called for simple binds, and by moving the mapping into
the function call we allow the unmapped values to be included in the
user_info and so logged.

We also include the local address and the remote address of the client
for future logging

Signed-off-by: Andrew Bartlett <abartlet at samba.org>
Pair-Programmed: Gary Lockyer <gary at catalyst.net.nz>
---
 source4/auth/auth.h             | 18 +++++++++---------
 source4/auth/ntlm/auth_simple.c | 41 ++++++++++++++++++++++++++++-------------
 source4/ldap_server/ldap_bind.c | 22 +++++++++-------------
 3 files changed, 46 insertions(+), 35 deletions(-)

diff --git a/source4/auth/auth.h b/source4/auth/auth.h
index 7c62318..d4be60e 100644
--- a/source4/auth/auth.h
+++ b/source4/auth/auth.h
@@ -158,15 +158,15 @@ NTSTATUS auth_check_password(struct auth4_context *auth_ctx,
 NTSTATUS auth4_init(void);
 NTSTATUS auth_register(const struct auth_operations *ops);
 NTSTATUS server_service_auth_init(void);
-NTSTATUS authenticate_username_pw(TALLOC_CTX *mem_ctx,
-				  struct tevent_context *ev,
-				  struct imessaging_context *msg,
-				  struct loadparm_context *lp_ctx,
-				  const char *nt4_domain,
-				  const char *nt4_username,
-				  const char *password,
-				  const uint32_t logon_parameters,
-				  struct auth_session_info **session_info);
+NTSTATUS authenticate_ldap_simple_bind(TALLOC_CTX *mem_ctx,
+				       struct tevent_context *ev,
+				       struct imessaging_context *msg,
+				       struct loadparm_context *lp_ctx,
+				       struct tsocket_address *remote_address,
+				       struct tsocket_address *local_address,
+				       const char *dn,
+				       const char *password,
+				       struct auth_session_info **session_info);
 
 struct tevent_req *auth_check_password_send(TALLOC_CTX *mem_ctx,
 					    struct tevent_context *ev,
diff --git a/source4/auth/ntlm/auth_simple.c b/source4/auth/ntlm/auth_simple.c
index f6dd9d0..ef37e68 100644
--- a/source4/auth/ntlm/auth_simple.c
+++ b/source4/auth/ntlm/auth_simple.c
@@ -23,31 +23,42 @@
 
 #include "includes.h"
 #include "auth/auth.h"
+#include "dsdb/samdb/samdb.h"
 
 /*
  It's allowed to pass NULL as session_info,
  when the caller doesn't need a session_info
 */
-_PUBLIC_ NTSTATUS authenticate_username_pw(TALLOC_CTX *mem_ctx,
-					   struct tevent_context *ev,
-					   struct imessaging_context *msg,
-					   struct loadparm_context *lp_ctx,
-					   const char *nt4_domain,
-					   const char *nt4_username,
-					   const char *password,
-					   const uint32_t logon_parameters,
-					   struct auth_session_info **session_info) 
+_PUBLIC_ NTSTATUS authenticate_ldap_simple_bind(TALLOC_CTX *mem_ctx,
+						struct tevent_context *ev,
+						struct imessaging_context *msg,
+						struct loadparm_context *lp_ctx,
+						struct tsocket_address *remote_address,
+						struct tsocket_address *local_address,
+						const char *dn,
+						const char *password,
+						struct auth_session_info **session_info)
 {
 	struct auth4_context *auth_context;
 	struct auth_usersupplied_info *user_info;
 	struct auth_user_info_dc *user_info_dc;
 	NTSTATUS nt_status;
 	TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
+	const char *nt4_domain;
+	const char *nt4_username;
 
 	if (!tmp_ctx) {
 		return NT_STATUS_NO_MEMORY;
 	}
 
+	nt_status = crack_auto_name_to_nt4_name(tmp_ctx, ev, lp_ctx, dn,
+						&nt4_domain, &nt4_username);
+
+	if (!NT_STATUS_IS_OK(nt_status)) {
+		talloc_free(tmp_ctx);
+		return nt_status;
+	}
+
 	nt_status = auth_context_create(tmp_ctx, 
 					ev, msg,
 					lp_ctx,
@@ -64,14 +75,16 @@ _PUBLIC_ NTSTATUS authenticate_username_pw(TALLOC_CTX *mem_ctx,
 	}
 
 	user_info->mapped_state = true;
-	user_info->client.account_name = nt4_username;
+	user_info->client.account_name = dn,
 	user_info->mapped.account_name = nt4_username;
-	user_info->client.domain_name = nt4_domain;
 	user_info->mapped.domain_name = nt4_domain;
 
 	user_info->workstation_name = NULL;
 
-	user_info->remote_host = NULL;
+	user_info->remote_host = remote_address;
+	user_info->local_host = local_address;
+
+	user_info->service_description = "ldap simple bind";
 
 	user_info->password_state = AUTH_PASSWORD_PLAIN;
 	user_info->password.plaintext = talloc_strdup(user_info, password);
@@ -79,7 +92,9 @@ _PUBLIC_ NTSTATUS authenticate_username_pw(TALLOC_CTX *mem_ctx,
 	user_info->flags = USER_INFO_CASE_INSENSITIVE_USERNAME |
 		USER_INFO_DONT_CHECK_UNIX_ACCOUNT;
 
-	user_info->logon_parameters = logon_parameters |
+	user_info->logon_parameters =
+		MSV1_0_ALLOW_SERVER_TRUST_ACCOUNT |
+		MSV1_0_ALLOW_WORKSTATION_TRUST_ACCOUNT |
 		MSV1_0_CLEARTEXT_PASSWORD_ALLOWED |
 		MSV1_0_CLEARTEXT_PASSWORD_SUPPLIED;
 
diff --git a/source4/ldap_server/ldap_bind.c b/source4/ldap_server/ldap_bind.c
index e0f13f2..f517657 100644
--- a/source4/ldap_server/ldap_bind.c
+++ b/source4/ldap_server/ldap_bind.c
@@ -68,7 +68,6 @@ static NTSTATUS ldapsrv_BindSimple(struct ldapsrv_call *call)
 
 	int result;
 	const char *errstr;
-	const char *nt4_domain, *nt4_account;
 
 	struct auth_session_info *session_info;
 
@@ -93,18 +92,15 @@ static NTSTATUS ldapsrv_BindSimple(struct ldapsrv_call *call)
 		goto do_reply;
 	}
 
-	status = crack_auto_name_to_nt4_name(call, call->conn->connection->event.ctx, call->conn->lp_ctx, req->dn, &nt4_domain, &nt4_account);
-	if (NT_STATUS_IS_OK(status)) {
-		status = authenticate_username_pw(call,
-						  call->conn->connection->event.ctx,
-						  call->conn->connection->msg_ctx,
-						  call->conn->lp_ctx,
-						  nt4_domain, nt4_account, 
-						  req->creds.password,
-						  MSV1_0_ALLOW_SERVER_TRUST_ACCOUNT |
-						  MSV1_0_ALLOW_WORKSTATION_TRUST_ACCOUNT,
-						  &session_info);
-	}
+	status = authenticate_ldap_simple_bind(call,
+					       call->conn->connection->event.ctx,
+					       call->conn->connection->msg_ctx,
+					       call->conn->lp_ctx,
+					       call->conn->connection->remote_address,
+					       call->conn->connection->local_address,
+					       req->dn,
+					       req->creds.password,
+					       &session_info);
 
 	if (NT_STATUS_IS_OK(status)) {
 		result = LDAP_SUCCESS;
-- 
2.7.4


From a6208e8269b6cebefe257d122592cfcedf021b87 Mon Sep 17 00:00:00 2001
From: Andrew Bartlett <abartlet at samba.org>
Date: Tue, 21 Feb 2017 11:57:57 +1300
Subject: [PATCH 18/43] auth: Add "auth_description" to allow logs to
 distinguish simple bind (etc)

This will allow the authentication log to indicate clearly how the password was
supplied to the server.

Signed-off-by: Andrew Bartlett <abartlet at samba.org>
Pair-Programmed: Gary Lockyer <gary at catalyst.net.nz>
---
 auth/common_auth.h                            | 1 +
 auth/ntlmssp/ntlmssp_server.c                 | 1 +
 source3/smbd/sesssetup.c                      | 6 ++++++
 source4/auth/ntlm/auth_simple.c               | 4 +++-
 source4/rpc_server/netlogon/dcerpc_netlogon.c | 3 +++
 5 files changed, 14 insertions(+), 1 deletion(-)

diff --git a/auth/common_auth.h b/auth/common_auth.h
index 1e9ca29..869f138 100644
--- a/auth/common_auth.h
+++ b/auth/common_auth.h
@@ -81,6 +81,7 @@ struct auth_usersupplied_info
 	} netlogon_trust_account;
 
 	const char *service_description;
+	const char *auth_description;
 };
 
 struct auth_method_context;
diff --git a/auth/ntlmssp/ntlmssp_server.c b/auth/ntlmssp/ntlmssp_server.c
index 6d7cc2b..322c94c 100644
--- a/auth/ntlmssp/ntlmssp_server.c
+++ b/auth/ntlmssp/ntlmssp_server.c
@@ -720,6 +720,7 @@ static NTSTATUS ntlmssp_server_check_password(struct gensec_security *gensec_sec
 	user_info->remote_host = gensec_get_remote_address(gensec_security);
 	user_info->service_description
 		= gensec_get_target_service_description(gensec_security);
+	user_info->auth_description = "NTLMSSP";
 
 	user_info->password_state = AUTH_PASSWORD_RESPONSE;
 	user_info->password.response.lanman = ntlmssp_state->lm_resp;
diff --git a/source3/smbd/sesssetup.c b/source3/smbd/sesssetup.c
index 3157dfd..e66aae5 100644
--- a/source3/smbd/sesssetup.c
+++ b/source3/smbd/sesssetup.c
@@ -103,6 +103,8 @@ static NTSTATUS check_guest_password(const struct tsocket_address *remote_addres
 		return NT_STATUS_NO_MEMORY;
 	}
 
+	user_info->auth_description = "guest";
+
 	nt_status = auth_check_password_session_info(auth_context, 
 						     mem_ctx, user_info, session_info);
 	TALLOC_FREE(user_info);
@@ -899,6 +901,8 @@ void reply_sesssetup_and_X(struct smb_request *req)
 							 sconn->remote_address,
 							 "smb",
 							 lm_resp, nt_resp);
+		user_info->auth_description = "bare-NTLM";
+
 		if (NT_STATUS_IS_OK(nt_status)) {
 			nt_status = auth_check_password_session_info(negprot_auth_context, 
 								     req, user_info, &session_info);
@@ -925,6 +929,8 @@ void reply_sesssetup_and_X(struct smb_request *req)
 				nt_status = NT_STATUS_NO_MEMORY;
 			}
 
+			user_info->auth_description = "plaintext";
+
 			if (NT_STATUS_IS_OK(nt_status)) {
 				nt_status = auth_check_password_session_info(plaintext_auth_context, 
 									     req, user_info, &session_info);
diff --git a/source4/auth/ntlm/auth_simple.c b/source4/auth/ntlm/auth_simple.c
index ef37e68..7f077a5 100644
--- a/source4/auth/ntlm/auth_simple.c
+++ b/source4/auth/ntlm/auth_simple.c
@@ -84,7 +84,9 @@ _PUBLIC_ NTSTATUS authenticate_ldap_simple_bind(TALLOC_CTX *mem_ctx,
 	user_info->remote_host = remote_address;
 	user_info->local_host = local_address;
 
-	user_info->service_description = "ldap simple bind";
+	user_info->service_description = "ldap";
+
+	user_info->auth_description = "simple bind";
 
 	user_info->password_state = AUTH_PASSWORD_PLAIN;
 	user_info->password.plaintext = talloc_strdup(user_info, password);
diff --git a/source4/rpc_server/netlogon/dcerpc_netlogon.c b/source4/rpc_server/netlogon/dcerpc_netlogon.c
index c10ce09..b459467 100644
--- a/source4/rpc_server/netlogon/dcerpc_netlogon.c
+++ b/source4/rpc_server/netlogon/dcerpc_netlogon.c
@@ -910,6 +910,7 @@ static NTSTATUS dcesrv_netr_LogonSamLogon_base(struct dcesrv_call_state *dce_cal
 	case NetlogonServiceInformation:
 	case NetlogonInteractiveTransitiveInformation:
 	case NetlogonServiceTransitiveInformation:
+		user_info->auth_description = "interactive";
 
 		user_info->logon_parameters
 			= r->in.logon->password->identity_info.parameter_control;
@@ -933,6 +934,8 @@ static NTSTATUS dcesrv_netr_LogonSamLogon_base(struct dcesrv_call_state *dce_cal
 		break;
 	case NetlogonNetworkInformation:
 	case NetlogonNetworkTransitiveInformation:
+		user_info->auth_description = "network";
+
 		nt_status = auth_context_set_challenge(
 			auth_context,
 			r->in.logon->network->challenge,
-- 
2.7.4


From 5e6f7aed9d161722328427cd3e965d1c912fb8fa Mon Sep 17 00:00:00 2001
From: Andrew Bartlett <abartlet at samba.org>
Date: Tue, 21 Feb 2017 12:14:12 +1300
Subject: [PATCH 19/43] winbindd: Clarify that we do not pre-hash the password
 for rpccli_netlogon_password_logon()

rpccli_netlogon_password_logon() is called in winbind_samlogon_retry_loop() if interactive
is set, and does not use the hashed passwords.

This is only needed for winbindd_dual_auth_passdb(), and by moving the call we both
avoid the extra work and allow it to also be removed in this code path

Signed-off-by: Andrew Bartlett <abartlet at samba.org>
Pair-Programmed: Gary Lockyer <gary at catalyst.net.nz>
---
 source3/winbindd/winbindd_pam.c | 78 ++++++++++++++++++++---------------------
 1 file changed, 39 insertions(+), 39 deletions(-)

diff --git a/source3/winbindd/winbindd_pam.c b/source3/winbindd/winbindd_pam.c
index 816991d..93b3493 100644
--- a/source3/winbindd/winbindd_pam.c
+++ b/source3/winbindd/winbindd_pam.c
@@ -1390,7 +1390,7 @@ static NTSTATUS winbind_samlogon_retry_loop(struct winbindd_domain *domain,
 			DBG_NOTICE("No security credentials available for "
 				  "domain [%s]\n", domainname);
 			result = NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
-		} else if (interactive && username != NULL && password != NULL) {
+		} else if (interactive) {
 			result = rpccli_netlogon_password_logon(domain->conn.netlogon_creds,
 								netlogon_pipe->binding_handle,
 								mem_ctx,
@@ -1512,43 +1512,43 @@ static NTSTATUS winbindd_dual_pam_auth_samlogon(TALLOC_CTX *mem_ctx,
 
 	parse_domain_user(user, name_domain, name_user);
 
-	/* do password magic */
-
-	generate_random_buffer(chal, sizeof(chal));
-
-	if (lp_client_ntlmv2_auth()) {
-		DATA_BLOB server_chal;
-		DATA_BLOB names_blob;
-		server_chal = data_blob_const(chal, 8);
-
-		/* note that the 'workgroup' here is for the local
-		   machine.  The 'server name' must match the
-		   'workstation' passed to the actual SamLogon call.
-		*/
-		names_blob = NTLMv2_generate_names_blob(
-			mem_ctx, lp_netbios_name(), lp_workgroup());
+	if (strequal(name_domain, get_global_sam_name())) {
+		DATA_BLOB chal_blob = data_blob_const(chal, sizeof(chal));
 
-		if (!SMBNTLMv2encrypt(mem_ctx, name_user, name_domain,
-				      pass,
-				      &server_chal,
-				      &names_blob,
-				      &lm_resp, &nt_resp, NULL, NULL)) {
+		/* do password magic */
+
+		generate_random_buffer(chal, sizeof(chal));
+
+		if (lp_client_ntlmv2_auth()) {
+			DATA_BLOB server_chal;
+			DATA_BLOB names_blob;
+			server_chal = data_blob_const(chal, 8);
+
+			/* note that the 'workgroup' here is for the local
+			   machine.  The 'server name' must match the
+			   'workstation' passed to the actual SamLogon call.
+			*/
+			names_blob = NTLMv2_generate_names_blob(
+				mem_ctx, lp_netbios_name(), lp_workgroup());
+
+			if (!SMBNTLMv2encrypt(mem_ctx, name_user, name_domain,
+					      pass,
+					      &server_chal,
+					      &names_blob,
+					      &lm_resp, &nt_resp, NULL, NULL)) {
+				data_blob_free(&names_blob);
+				DEBUG(0, ("winbindd_pam_auth: SMBNTLMv2encrypt() failed!\n"));
+				result = NT_STATUS_NO_MEMORY;
+				goto done;
+			}
 			data_blob_free(&names_blob);
-			DEBUG(0, ("winbindd_pam_auth: SMBNTLMv2encrypt() failed!\n"));
-			result = NT_STATUS_NO_MEMORY;
-			goto done;
-		}
-		data_blob_free(&names_blob);
-	} else {
-		lm_resp = data_blob_null;
-		SMBNTencrypt(pass, chal, local_nt_response);
-
-		nt_resp = data_blob_talloc(mem_ctx, local_nt_response,
-					   sizeof(local_nt_response));
-	}
+		} else {
+			lm_resp = data_blob_null;
+			SMBNTencrypt(pass, chal, local_nt_response);
 
-	if (strequal(name_domain, get_global_sam_name())) {
-		DATA_BLOB chal_blob = data_blob_const(chal, sizeof(chal));
+			nt_resp = data_blob_talloc(mem_ctx, local_nt_response,
+						   sizeof(local_nt_response));
+		}
 
 		result = winbindd_dual_auth_passdb(
 			mem_ctx, 0, name_domain, name_user,
@@ -1557,7 +1557,8 @@ static NTSTATUS winbindd_dual_pam_auth_samlogon(TALLOC_CTX *mem_ctx,
 			info3);
 
 		/* 
-		 * We need to try the remote NETLOGON server if this is NOT_IMPLEMENTED 
+		 * We need to try the remote NETLOGON server if this is
+		 * NOT_IMPLEMENTED (for example on the RODC)
 		 */
 		if (!NT_STATUS_EQUAL(result, NT_STATUS_NOT_IMPLEMENTED)) {
 			goto done;
@@ -1573,9 +1574,8 @@ static NTSTATUS winbindd_dual_pam_auth_samlogon(TALLOC_CTX *mem_ctx,
 					     pass,
 					     name_domain,
 					     lp_netbios_name(),
-					     chal,
-					     lm_resp,
-					     nt_resp,
+					     NULL,
+					     data_blob_null, data_blob_null,
 					     true, /* interactive */
 					     &authoritative,
 					     &flags,
-- 
2.7.4


From 800b398140815389d55539ffaa2c5c2308089d5d Mon Sep 17 00:00:00 2001
From: Andrew Bartlett <abartlet at samba.org>
Date: Tue, 21 Feb 2017 16:22:07 +1300
Subject: [PATCH 20/43] s4-rpc_server: Correct comment about where the current
 iface can be found

Signed-off-by: Andrew Bartlett <abartlet at samba.org>
Pair-Programmed: Gary Lockyer <gary at catalyst.net.nz>
---
 source4/rpc_server/dcerpc_server.c | 9 ++++++---
 1 file changed, 6 insertions(+), 3 deletions(-)

diff --git a/source4/rpc_server/dcerpc_server.c b/source4/rpc_server/dcerpc_server.c
index f7ec210..3663a2b 100644
--- a/source4/rpc_server/dcerpc_server.c
+++ b/source4/rpc_server/dcerpc_server.c
@@ -939,9 +939,12 @@ static NTSTATUS dcesrv_bind(struct dcesrv_call_state *call)
 	}
 
 	/*
-	 * At this point we know which interface (eg netlogon, lsa,
-	 * drsuapi) the caller requested.  This is available on
-	 * call->conntext->iface.
+	 * At this point we still don't know which interface (eg
+	 * netlogon, lsa, drsuapi) the caller requested in this bind!
+	 * The most recently added context is available as the first
+	 * element in the linked list at call->conn->contexts, that is
+	 * call->conn->contexts->iface, but they may not have
+	 * requested one at all!
 	 */
 
 	if ((call->pkt.pfc_flags & DCERPC_PFC_FLAG_CONC_MPX) &&
-- 
2.7.4


From 3c5d0f2480af8160225e8c5567f7986a1b489cd6 Mon Sep 17 00:00:00 2001
From: Gary Lockyer <gary at catalyst.net.nz>
Date: Wed, 1 Mar 2017 11:10:29 +1300
Subject: [PATCH 21/43] lib/util: Add functions to escape log lines but not
 break all non-ascii

We do not want to turn every non-ascii username into a pile of hex, so we instead focus
on avoding newline insertion attacks and other low control chars

Pair-programmed-by: Andrew Bartlett <abartlet at samba.org>
Signed-off-by: Gary Lockyer <gary at catalyst.net.nz>
Signed-off-by: Andrew Bartlett <abartlet at samba.org>
---
 lib/util/tests/util_str_escape.c    |  90 ++++++++++++++++++++++++++
 lib/util/util_str_escape.c          | 126 ++++++++++++++++++++++++++++++++++++
 lib/util/util_str_escape.h          |  27 ++++++++
 lib/util/wscript_build              |   5 ++
 source4/torture/local/local.c       |   1 +
 source4/torture/local/wscript_build |   3 +-
 6 files changed, 251 insertions(+), 1 deletion(-)
 create mode 100644 lib/util/tests/util_str_escape.c
 create mode 100644 lib/util/util_str_escape.c
 create mode 100644 lib/util/util_str_escape.h

diff --git a/lib/util/tests/util_str_escape.c b/lib/util/tests/util_str_escape.c
new file mode 100644
index 0000000..82e2209
--- /dev/null
+++ b/lib/util/tests/util_str_escape.c
@@ -0,0 +1,90 @@
+/*
+
+   util_str_escape testing
+
+   Copyright (C) Andrew Bartlett <abartlet at samba.org> 2017
+
+   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 "torture/torture.h"
+#include "torture/local/proto.h"
+#include "lib/util/util_str_escape.h"
+
+static bool test_log_escape_empty_string(struct torture_context *tctx)
+{
+	char *result = log_escape( tctx, "");
+	torture_assert_str_equal(tctx, result, "", "Empty string handling");
+	return true;
+}
+
+static bool test_log_escape_null_string(struct torture_context *tctx)
+{
+	char *result = log_escape( tctx, NULL);
+	torture_assert(tctx, (result == NULL), "Empty string handling");
+	return true;
+}
+
+static bool test_log_escape_plain_string(struct torture_context *tctx)
+{
+	const char *input    = "a plain string with no escapable characters";
+	const char *expected = "a plain string with no escapable characters";
+
+	char *result = log_escape( tctx, input);
+	torture_assert_str_equal(tctx, result, expected,
+				 "Plain string handling");
+	return true;
+}
+
+static bool test_log_escape_string(struct torture_context *tctx)
+{
+	const char *input    = "\a\b\f\n\r\t\v\\\x01";
+	const char *expected = "\\a\\b\\f\\n\\r\\t\\v\\\\\\x01";
+
+	char *result = log_escape( tctx, input);
+	torture_assert_str_equal(tctx, result, expected,
+				 "Escapable characters in string");
+	return true;
+}
+
+static bool test_log_escape_hex_string(struct torture_context *tctx)
+{
+	const char *input    = "\x01\x1F ";
+	const char *expected = "\\x01\\x1F ";
+
+	char *result = log_escape( tctx, input);
+	torture_assert_str_equal(tctx, result, expected,
+				 "hex escaping");
+	return true;
+}
+struct torture_suite *torture_local_util_str_escape(TALLOC_CTX *mem_ctx)
+{
+	struct torture_suite *suite = torture_suite_create(mem_ctx,
+							   "util_str_escape");
+
+	torture_suite_add_simple_test(suite, "log_escape_empty_string",
+				      test_log_escape_empty_string);
+	torture_suite_add_simple_test(suite, "log_escape_null_string",
+				      test_log_escape_null_string);
+	torture_suite_add_simple_test(suite, "log_escape_plain_string",
+				      test_log_escape_plain_string);
+	torture_suite_add_simple_test(suite, "log_escape_string",
+				      test_log_escape_string);
+	torture_suite_add_simple_test(suite, "log_escape_hex_string",
+				      test_log_escape_hex_string);
+
+
+	return suite;
+}
diff --git a/lib/util/util_str_escape.c b/lib/util/util_str_escape.c
new file mode 100644
index 0000000..0d8a871
--- /dev/null
+++ b/lib/util/util_str_escape.c
@@ -0,0 +1,126 @@
+/*
+   Samba string escaping routines
+
+   Copyright (C) Andrew Bartlett <abartlet at samba.org> 2017
+
+   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 "lib/util/util_str_escape.h"
+
+
+/*
+ * Calculate the encoded length of a character for log_escape
+ *
+ */
+static size_t encoded_length(char c)
+{
+	if ( c != '\\' &&  c > 0x1F) {
+		return 1;
+	} else {
+		switch (c) {
+		case '\a':
+		case '\b':
+		case '\f':
+		case '\n':
+		case '\r':
+		case '\t':
+		case '\v':
+		case '\\':
+			return 2;  /* C escape sequence */
+		default:
+			return 4;  /* hex escape \xhh   */
+		}
+	}
+}
+
+/*
+ * Escape any control characters in the inputs to prevent them from
+ * interfering with the log output.
+ */
+char *log_escape(TALLOC_CTX *frame, const char *in)
+{
+	size_t size = 0;        /* Space to allocate for the escaped data */
+	char *encoded = NULL;   /* The encoded string                     */
+	const char *c;
+	char *e;
+
+	if (in == NULL) {
+		return NULL;
+	}
+
+	/* Calculate the size required for the escaped array */
+	c = in;
+	while (*c) {
+		size += encoded_length( *c);
+		c++;
+	}
+	size++;
+
+	encoded = talloc_array( frame, char, size);
+	if (encoded == NULL) {
+		DBG_ERR( "Out of memory allocating encoded string");
+		return NULL;
+	}
+
+	c = in;
+	e = encoded;
+	while (*c) {
+		if (*c != '\\' && *c > 0x1F) {
+			*e++ = *c++;
+		} else {
+			switch (*c) {
+			case '\a':
+				*e++ = '\\';
+				*e++ = 'a';
+				break;
+			case '\b':
+				*e++ = '\\';
+				*e++ = 'b';
+				break;
+			case '\f':
+				*e++ = '\\';
+				*e++ = 'f';
+				break;
+			case '\n':
+				*e++ = '\\';
+				*e++ = 'n';
+				break;
+			case '\r':
+				*e++ = '\\';
+				*e++ = 'r';
+				break;
+			case '\t':
+				*e++ = '\\';
+				*e++ = 't';
+				break;
+			case '\v':
+				*e++ = '\\';
+				*e++ = 'v';
+				break;
+			case '\\':
+				*e++ = '\\';
+				*e++ = '\\';
+				break;
+			default:
+				snprintf(e, 5, "\\x%02X", *c);
+				e += 4;
+			}
+			c++;
+		}
+	}
+	*e = '\0';
+	return encoded;
+}
diff --git a/lib/util/util_str_escape.h b/lib/util/util_str_escape.h
new file mode 100644
index 0000000..0b4c596
--- /dev/null
+++ b/lib/util/util_str_escape.h
@@ -0,0 +1,27 @@
+/*
+   Samba string escaping routines
+
+   Copyright (C) Andrew Bartlett <abartlet at samba.org> 2017
+
+   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/>.
+*/
+
+#ifndef _SAMBA_UTIL_STR_ESCAPE_H
+#define _SAMBA_UTIL_STR_ESCAPE_H
+
+#include <talloc.h>
+
+char *log_escape(TALLOC_CTX *frame, const char *in);
+
+#endif
diff --git a/lib/util/wscript_build b/lib/util/wscript_build
index ddece0e..81178b8 100644
--- a/lib/util/wscript_build
+++ b/lib/util/wscript_build
@@ -204,3 +204,8 @@ else:
                         source='access.c',
                         deps='interfaces samba-util',
                         local_include=False)
+
+    bld.SAMBA_SUBSYSTEM('util_str_escape',
+                        source='util_str_escape.c',
+                        deps='talloc',
+                        local_include=False)
diff --git a/source4/torture/local/local.c b/source4/torture/local/local.c
index 6641f21..89066c5 100644
--- a/source4/torture/local/local.c
+++ b/source4/torture/local/local.c
@@ -74,6 +74,7 @@
 	torture_local_verif_trailer,
 	torture_local_nss,
 	torture_local_fsrvp,
+	torture_local_util_str_escape,
 	NULL
 };
 
diff --git a/source4/torture/local/wscript_build b/source4/torture/local/wscript_build
index 087b842..2f1a7c8 100644
--- a/source4/torture/local/wscript_build
+++ b/source4/torture/local/wscript_build
@@ -20,11 +20,12 @@ TORTURE_LOCAL_SOURCE = '''../../../lib/util/charset/tests/iconv.c
 	../../../lib/util/tests/strv.c
 	../../../lib/util/tests/strv_util.c
 	../../../lib/util/tests/util.c
+	../../../lib/util/tests/util_str_escape.c
 	verif_trailer.c
 	nss_tests.c
 	fsrvp_state.c'''
 
-TORTURE_LOCAL_DEPS = 'RPC_NDR_ECHO TDR LIBCLI_SMB MESSAGING iconv POPT_CREDENTIALS TORTURE_AUTH TORTURE_UTIL TORTURE_NDR TORTURE_LIBCRYPTO share torture_registry PROVISION ldb samdb replace-test RPC_FSS_STATE'
+TORTURE_LOCAL_DEPS = 'RPC_NDR_ECHO TDR LIBCLI_SMB MESSAGING iconv POPT_CREDENTIALS TORTURE_AUTH TORTURE_UTIL TORTURE_NDR TORTURE_LIBCRYPTO share torture_registry PROVISION ldb samdb replace-test RPC_FSS_STATE util_str_escape'
 
 bld.SAMBA_MODULE('TORTURE_LOCAL',
 	source=TORTURE_LOCAL_SOURCE,
-- 
2.7.4


From 2fb210f38cc6c8de7ea50dca02ac21240ceebb04 Mon Sep 17 00:00:00 2001
From: Andrew Bartlett <abartlet at samba.org>
Date: Wed, 1 Mar 2017 11:22:43 +1300
Subject: [PATCH 22/43] s3-auth: Split out get_user_sid_info3_and_extra() from
 create_local_nt_token_from_info3()

This will allow us to get the SID in another location for logging

Signed-off-by: Andrew Bartlett <abartlet at samba.org>
Pair-Programmed: Gary Lockyer <gary at catalyst.net.nz>
---
 source3/auth/proto.h      |  3 +++
 source3/auth/token_util.c | 41 ++++++++++++++++++++++++++---------------
 2 files changed, 29 insertions(+), 15 deletions(-)

diff --git a/source3/auth/proto.h b/source3/auth/proto.h
index 69fa20c..eb9756c 100644
--- a/source3/auth/proto.h
+++ b/source3/auth/proto.h
@@ -351,6 +351,9 @@ struct security_token *create_local_nt_token(TALLOC_CTX *mem_ctx,
 					    bool is_guest,
 					    int num_groupsids,
 					    const struct dom_sid *groupsids);
+NTSTATUS get_user_sid_info3_and_extra(const struct netr_SamInfo3 *info3,
+				      const struct extra_auth_info *extra,
+				      struct dom_sid *sid);
 NTSTATUS create_local_nt_token_from_info3(TALLOC_CTX *mem_ctx,
 					  bool is_guest,
 					  const struct netr_SamInfo3 *info3,
diff --git a/source3/auth/token_util.c b/source3/auth/token_util.c
index 77b63e4..03c4b64 100644
--- a/source3/auth/token_util.c
+++ b/source3/auth/token_util.c
@@ -211,6 +211,28 @@ static NTSTATUS add_builtin_administrators(struct security_token *token,
 static NTSTATUS finalize_local_nt_token(struct security_token *result,
 					bool is_guest);
 
+NTSTATUS get_user_sid_info3_and_extra(const struct netr_SamInfo3 *info3,
+				      const struct extra_auth_info *extra,
+				      struct dom_sid *sid)
+{
+	/* USER SID */
+	if (info3->base.rid == (uint32_t)(-1)) {
+		/* this is a signal the user was fake and generated,
+		 * the actual SID we want to use is stored in the extra
+		 * sids */
+		if (is_null_sid(&extra->user_sid)) {
+			/* we couldn't find the user sid, bail out */
+			DEBUG(3, ("Invalid user SID\n"));
+			return NT_STATUS_UNSUCCESSFUL;
+		}
+		sid_copy(sid, &extra->user_sid);
+	} else {
+		sid_copy(sid, info3->base.domain_sid);
+		sid_append_rid(sid, info3->base.rid);
+	}
+	return NT_STATUS_OK;
+}
+
 NTSTATUS create_local_nt_token_from_info3(TALLOC_CTX *mem_ctx,
 					  bool is_guest,
 					  const struct netr_SamInfo3 *info3,
@@ -241,21 +263,10 @@ NTSTATUS create_local_nt_token_from_info3(TALLOC_CTX *mem_ctx,
 	}
 	usrtok->num_sids = 2;
 
-	/* USER SID */
-	if (info3->base.rid == (uint32_t)(-1)) {
-		/* this is a signal the user was fake and generated,
-		 * the actual SID we want to use is stored in the extra
-		 * sids */
-		if (is_null_sid(&extra->user_sid)) {
-			/* we couldn't find the user sid, bail out */
-			DEBUG(3, ("Invalid user SID\n"));
-			TALLOC_FREE(usrtok);
-			return NT_STATUS_UNSUCCESSFUL;
-		}
-		sid_copy(&usrtok->sids[0], &extra->user_sid);
-	} else {
-		sid_copy(&usrtok->sids[0], info3->base.domain_sid);
-		sid_append_rid(&usrtok->sids[0], info3->base.rid);
+	status = get_user_sid_info3_and_extra(info3, extra, &usrtok->sids[0]);
+	if (!NT_STATUS_IS_OK(status)) {
+		TALLOC_FREE(usrtok);
+		return status;
 	}
 
 	/* GROUP SID */
-- 
2.7.4


From 0b65ae49cd35a313d97317cca81de49ad57f823b Mon Sep 17 00:00:00 2001
From: Gary Lockyer <gary at catalyst.net.nz>
Date: Thu, 23 Feb 2017 13:50:14 +1300
Subject: [PATCH 23/43] auth: Generate a human readable Authentication log
 message.

Add a human readable authentication log line, to allow
verification that all required details are being passed.

Signed-off-by: Andrew Bartlett <abartlet at samba.org>
Pair-Programmed: Gary Lockyer <gary at catalyst.net.nz>
---
 auth/auth_log.c                     | 119 ++++++++++++++++++++++++++++++++++++
 auth/common_auth.h                  |   6 ++
 auth/wscript_build                  |   6 +-
 source3/auth/auth.c                 |  18 +++++-
 source3/rpc_server/wscript_build    |   2 +-
 source4/auth/kerberos/wscript_build |   2 +-
 source4/auth/ntlm/auth.c            |  15 ++++-
 source4/kdc/wscript_build           |  10 +--
 8 files changed, 165 insertions(+), 13 deletions(-)
 create mode 100644 auth/auth_log.c

diff --git a/auth/auth_log.c b/auth/auth_log.c
new file mode 100644
index 0000000..fc3f550
--- /dev/null
+++ b/auth/auth_log.c
@@ -0,0 +1,119 @@
+/*
+
+   Authentication and authorization logging
+
+   Copyright (C) Andrew Bartlett <abartlet at samba.org> 2017
+
+   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/>.
+*/
+
+/*
+ * Debug log levels for authentication logging (these both map to
+ * LOG_NOTICE in syslog)
+ */
+#define AUTH_SUCCESS_LEVEL 4
+#define AUTHZ_SUCCESS_LEVEL 5
+#define AUTH_FAILURE_LEVEL 2
+
+#include "includes.h"
+#include "../lib/tsocket/tsocket.h"
+#include "common_auth.h"
+#include "lib/util/util_str_escape.h"
+#include "libcli/security/dom_sid.h"
+
+/*
+ * Log details of an authentication attempt.
+ * Successful and unsuccessful attempts are logged.
+ *
+ */
+void log_authentication_event(const struct auth_usersupplied_info *ui,
+			      NTSTATUS status,
+			      const char *domain_name,
+			      const char *account_name,
+			      const char *unix_username,
+			      struct dom_sid *sid)
+{
+	TALLOC_CTX *frame = NULL;
+
+	char *ts = NULL;         /* formatted current time      */
+	char *remote = NULL;     /* formatted remote host       */
+	char *local = NULL;      /* formatted local host        */
+	char *nl = NULL;         /* NETLOGON details if present */
+	char *trust_computer_name = NULL;
+	char *trust_account_name = NULL;
+	char *logon_line = NULL;
+
+	/* set the log level */
+	int  level = NT_STATUS_IS_OK(status) ? AUTH_FAILURE_LEVEL : AUTH_SUCCESS_LEVEL;
+	if (!CHECK_DEBUGLVLC( DBGC_AUTH_AUDIT, level)) {
+		return;
+	}
+
+	frame = talloc_stackframe();
+
+	/* Get the current time */
+        ts = http_timestring(frame, time(NULL));
+
+	/* Only log the NETLOGON details if they are present */
+	if (ui->netlogon_trust_account.computer_name ||
+	    ui->netlogon_trust_account.account_name) {
+		trust_computer_name = log_escape(frame,
+			ui->netlogon_trust_account.computer_name);
+		trust_account_name  = log_escape(frame,
+			ui->netlogon_trust_account.account_name);
+		nl = talloc_asprintf(frame,
+			" NETLOGON computer [%s] trust account [%s]",
+			trust_computer_name, trust_account_name);
+	}
+
+	remote = tsocket_address_string(ui->remote_host, frame);
+	local  = tsocket_address_string(ui->local_host, frame);
+
+	if (NT_STATUS_IS_OK(status)) {
+		char sid_buf[DOM_SID_STR_BUFLEN];
+
+		dom_sid_string_buf(sid, sid_buf, sizeof(sid_buf));
+		logon_line = talloc_asprintf(frame,
+					     " became [%s]\\[%s] %s.",
+					     log_escape(frame, domain_name),
+					     log_escape(frame, account_name),
+					     sid_buf);
+	} else {
+		logon_line = talloc_asprintf(frame,
+					     " mapped to [%s]\\[%s].",
+					     log_escape(frame, ui->mapped.domain_name),
+					     log_escape(frame, ui->mapped.account_name));
+	}
+
+	DEBUGC( DBGC_AUTH_AUDIT, level, (
+		"Auth: [%s,%s] user [%s]\\[%s]"
+		" at [%s] status [%s]"
+		" workstation [%s] remote host [%s]"
+		"%s local host [%s]"
+		" %s\n",
+		ui->service_description,
+		ui->auth_description,
+		log_escape(frame, ui->client.domain_name),
+		log_escape(frame, ui->client.account_name),
+		ts,
+		nt_errstr( status),
+		log_escape(frame, ui->workstation_name),
+		remote,
+		logon_line,
+		local,
+		nl ? nl : ""
+		));
+
+	talloc_free(frame);
+}
diff --git a/auth/common_auth.h b/auth/common_auth.h
index 869f138..9a83158 100644
--- a/auth/common_auth.h
+++ b/auth/common_auth.h
@@ -146,4 +146,10 @@ struct auth4_context {
 					      struct auth_session_info **session_info);
 };
 
+void log_authentication_event(const struct auth_usersupplied_info *ui,
+			      NTSTATUS status,
+			      const char *account_name,
+			      const char *domain_name,
+			      const char *unix_username,
+			      struct dom_sid *sid);
 #endif
diff --git a/auth/wscript_build b/auth/wscript_build
index 2026153..732536d 100644
--- a/auth/wscript_build
+++ b/auth/wscript_build
@@ -1,8 +1,8 @@
 #!/usr/bin/env python
 
-bld.SAMBA_LIBRARY('auth_sam_reply',
-                  source='auth_sam_reply.c wbc_auth_util.c',
-                  deps='talloc samba-security samba-util',
+bld.SAMBA_LIBRARY('common_auth',
+                  source='auth_sam_reply.c wbc_auth_util.c auth_log.c',
+                  deps='talloc samba-security samba-util util_str_escape LIBTSOCKET',
                   private_library=True
                   )
 
diff --git a/source3/auth/auth.c b/source3/auth/auth.c
index ebd5597..19115e8 100644
--- a/source3/auth/auth.c
+++ b/source3/auth/auth.c
@@ -170,7 +170,8 @@ NTSTATUS auth_check_ntlm_password(TALLOC_CTX *mem_ctx,
 	NTSTATUS nt_status = NT_STATUS_NO_SUCH_USER;
 	const char *unix_username;
 	auth_methods *auth_method;
-	struct auth_serversupplied_info *server_info;
+	struct auth_serversupplied_info *server_info = NULL;
+	struct dom_sid sid = {0};
 
 	if (user_info == NULL || auth_context == NULL || pserver_info == NULL) {
 		return NT_STATUS_LOGON_FAILURE;
@@ -298,6 +299,18 @@ NTSTATUS auth_check_ntlm_password(TALLOC_CTX *mem_ctx,
 		goto fail;
 	}
 
+	nt_status = get_user_sid_info3_and_extra(server_info->info3,
+						 &server_info->extra,
+						 &sid);
+	if (!NT_STATUS_IS_OK(nt_status)) {
+		sid = (struct dom_sid) {0};
+	}
+
+	log_authentication_event(user_info, nt_status,
+				 server_info->info3->base.logon_domain.string,
+				 server_info->info3->base.account_name.string,
+				 unix_username, &sid);
+
 	DEBUG(server_info->guest ? 5 : 2,
 	      ("check_ntlm_password:  %sauthentication for user "
 	       "[%s] -> [%s] -> [%s] succeeded\n",
@@ -322,6 +335,9 @@ fail:
 	DEBUG(2, ("check_ntlm_password:  Authentication for user [%s] -> [%s] FAILED with error %s\n",
 		  user_info->client.account_name, user_info->mapped.account_name,
 		  nt_errstr(nt_status)));
+
+	log_authentication_event(user_info, nt_status, NULL, NULL, NULL, NULL);
+
 	ZERO_STRUCTP(pserver_info);
 
 	TALLOC_FREE(frame);
diff --git a/source3/rpc_server/wscript_build b/source3/rpc_server/wscript_build
index 7fe4fda..ae75e56 100644
--- a/source3/rpc_server/wscript_build
+++ b/source3/rpc_server/wscript_build
@@ -11,7 +11,7 @@ bld.SAMBA3_SUBSYSTEM('RPC_CONFIG',
 
 bld.SAMBA3_SUBSYSTEM('RPC_NCACN_NP',
                     source='rpc_ncacn_np.c rpc_handles.c rpc_contexts.c',
-                    deps='RPC_CONFIG auth auth_sam_reply RPC_PIPE_REGISTER npa_tstream')
+                    deps='RPC_CONFIG auth common_auth RPC_PIPE_REGISTER npa_tstream')
 
 bld.SAMBA3_SUBSYSTEM('RPC_SERVER_LOOP',
                     source='rpc_server.c',
diff --git a/source4/auth/kerberos/wscript_build b/source4/auth/kerberos/wscript_build
index 0f886fa..30853ec 100644
--- a/source4/auth/kerberos/wscript_build
+++ b/source4/auth/kerberos/wscript_build
@@ -9,7 +9,7 @@ bld.SAMBA_LIBRARY('authkrb5',
                   source='kerberos_pac.c',
                   autoproto='proto.h',
                   public_deps='ndr-krb5pac krb5samba samba_socket LIBCLI_RESOLVE asn1',
-                  deps='auth_sam_reply tevent LIBPACKET ndr ldb krb5samba KRB_INIT_CTX KRB5_PAC samba-errors',
+                  deps='common_auth tevent LIBPACKET ndr ldb krb5samba KRB_INIT_CTX KRB5_PAC samba-errors',
                   private_library=True
                   )
 
diff --git a/source4/auth/ntlm/auth.c b/source4/auth/ntlm/auth.c
index 310cab4..9a0345c 100644
--- a/source4/auth/ntlm/auth.c
+++ b/source4/auth/ntlm/auth.c
@@ -428,9 +428,11 @@ _PUBLIC_ NTSTATUS auth_check_password_recv(struct tevent_req *req,
 {
 	struct auth_check_password_state *state =
 		tevent_req_data(req, struct auth_check_password_state);
-	NTSTATUS status;
+	NTSTATUS status = NT_STATUS_OK;
+
+	bool err = tevent_req_is_nterror(req, &status);
 
-	if (tevent_req_is_nterror(req, &status)) {
+	if (err) {
 		/*
 		 * Please try not to change this string, it is probably in use
 		 * in audit logging tools
@@ -442,6 +444,9 @@ _PUBLIC_ NTSTATUS auth_check_password_recv(struct tevent_req *req,
 			 state->user_info->mapped.domain_name,
 			 state->user_info->mapped.account_name,
 			 nt_errstr(status)));
+
+		log_authentication_event(state->user_info, status,
+					 NULL, NULL, NULL, NULL);
 		tevent_req_received(req);
 		return status;
 	}
@@ -452,6 +457,12 @@ _PUBLIC_ NTSTATUS auth_check_password_recv(struct tevent_req *req,
 		 state->user_info_dc->info->domain_name,
 		 state->user_info_dc->info->account_name));
 
+	log_authentication_event(state->user_info, status,
+				 state->user_info_dc->info->domain_name,
+				 state->user_info_dc->info->account_name,
+				 NULL,
+				 &state->user_info_dc->sids[0]);
+
 	*user_info_dc = talloc_move(mem_ctx, &state->user_info_dc);
 
 	tevent_req_received(req);
diff --git a/source4/kdc/wscript_build b/source4/kdc/wscript_build
index 24d89f4..76efb1f 100644
--- a/source4/kdc/wscript_build
+++ b/source4/kdc/wscript_build
@@ -27,7 +27,7 @@ bld.SAMBA_MODULE('service_kdc',
 
 bld.SAMBA_LIBRARY('HDB_SAMBA4',
                   source='hdb-samba4.c hdb-samba4-plugin.c',
-                  deps='ldb auth4_sam auth_sam_reply samba-credentials hdb db-glue samba-hostconfig com_err sdb_hdb',
+                  deps='ldb auth4_sam common_auth samba-credentials hdb db-glue samba-hostconfig com_err sdb_hdb',
                   includes=kdc_include,
                   private_library=True,
                   enabled=bld.CONFIG_SET('SAMBA4_USES_HEIMDAL')
@@ -78,7 +78,7 @@ bld.SAMBA_SUBSYSTEM('KDC-GLUE',
 bld.SAMBA_SUBSYSTEM('WDC_SAMBA4',
 	source='wdc-samba4.c',
         includes=kdc_include,
-	deps='ldb auth4_sam auth_sam_reply samba-credentials hdb PAC_GLUE samba-hostconfig com_err KDC-GLUE',
+	deps='ldb auth4_sam common_auth samba-credentials hdb PAC_GLUE samba-hostconfig com_err KDC-GLUE',
 	enabled=bld.CONFIG_SET('SAMBA4_USES_HEIMDAL')
 	)
 
@@ -107,7 +107,7 @@ bld.SAMBA_SUBSYSTEM('sdb_kdb',
 bld.SAMBA_SUBSYSTEM('PAC_GLUE',
 	source='pac-glue.c',
         includes=kdc_include,
-	deps='ldb auth4_sam auth_sam_reply samba-credentials samba-hostconfig com_err'
+	deps='ldb auth4_sam common_auth samba-credentials samba-hostconfig com_err'
 	)
 
 bld.SAMBA_LIBRARY('pac',
@@ -119,7 +119,7 @@ bld.SAMBA_LIBRARY('pac',
 
 bld.SAMBA_LIBRARY('db-glue',
 	source='db-glue.c',
-	deps='ldb auth4_sam auth_sam_reply samba-credentials sdb samba-hostconfig com_err',
+	deps='ldb auth4_sam common_auth samba-credentials sdb samba-hostconfig com_err',
 	private_library=True,
         includes=kdc_include,
 	)
@@ -134,7 +134,7 @@ bld.SAMBA_SUBSYSTEM('MIT_SAMBA',
                     deps='''
                          ldb
                          auth4_sam
-                         auth_sam_reply
+                         common_auth
                          samba-credentials
                          db-glue
                          PAC_GLUE
-- 
2.7.4


From 300a215b3461bbfec7678cb1024527e5c57e17fe Mon Sep 17 00:00:00 2001
From: Andrew Bartlett <abartlet at samba.org>
Date: Wed, 1 Mar 2017 11:23:28 +1300
Subject: [PATCH 24/43] s3-auth: Clarify the role and purpose of the
 auth_serversupplied_info->security_token

Signed-off-by: Andrew Bartlett <abartlet at samba.org>
Pair-Programmed: Gary Lockyer <gary at catalyst.net.nz>
---
 source3/include/auth.h | 9 ++++++++-
 1 file changed, 8 insertions(+), 1 deletion(-)

diff --git a/source3/include/auth.h b/source3/include/auth.h
index d35936b..406c2c5 100644
--- a/source3/include/auth.h
+++ b/source3/include/auth.h
@@ -34,7 +34,14 @@ struct auth_serversupplied_info {
 
 	struct security_unix_token utok;
 
-	/* NT group information taken from the info3 structure */
+	/*
+	 * NT group information taken from the info3 structure
+	 *
+	 * This is not normally filled in, during the typical
+	 * authentication process.  If filled in, it has already been
+	 * finalised by a nasty hack to support a cached guest/system
+	 * session_info
+	 */
 
 	struct security_token *security_token;
 
-- 
2.7.4


From 6aebddca18255f39b5670c6a13949159fb7eb0ce Mon Sep 17 00:00:00 2001
From: Andrew Bartlett <abartlet at samba.org>
Date: Thu, 23 Feb 2017 14:31:52 +1300
Subject: [PATCH 25/43] auth: Always supply both the remote and local address
 to the auth subsystem

This ensures that gensec, and then the NTLM auth subsystem under it, always gets the
remote and local address pointers for potential logging.

The local address allows us to know which interface an authentication is on

Signed-off-by: Andrew Bartlett <abartlet at samba.org>
Pair-Programmed: Gary Lockyer <gary at catalyst.net.nz>
---
 auth/ntlmssp/ntlmssp_server.c            |  1 +
 source3/auth/auth_generic.c              |  8 +++++
 source3/auth/proto.h                     |  4 ++-
 source3/rpc_server/dcesrv_auth_generic.c |  7 ++++-
 source3/rpc_server/dcesrv_auth_generic.h |  1 +
 source3/rpc_server/srv_pipe.c            |  1 +
 source3/smbd/negprot.c                   |  7 +++--
 source3/smbd/seal.c                      |  5 +++
 source3/smbd/sesssetup.c                 |  4 ++-
 source3/smbd/smb2_sesssetup.c            |  1 +
 source4/smb_server/smb/sesssetup.c       | 53 ++++++++++++++++++++++++++++++--
 source4/smb_server/smb2/sesssetup.c      | 39 +++++++++++++++++++++++
 12 files changed, 122 insertions(+), 9 deletions(-)

diff --git a/auth/ntlmssp/ntlmssp_server.c b/auth/ntlmssp/ntlmssp_server.c
index 322c94c..85d204b 100644
--- a/auth/ntlmssp/ntlmssp_server.c
+++ b/auth/ntlmssp/ntlmssp_server.c
@@ -718,6 +718,7 @@ static NTSTATUS ntlmssp_server_check_password(struct gensec_security *gensec_sec
 	user_info->client.domain_name = ntlmssp_state->domain;
 	user_info->workstation_name = ntlmssp_state->client.netbios_name;
 	user_info->remote_host = gensec_get_remote_address(gensec_security);
+	user_info->local_host = gensec_get_local_address(gensec_security);
 	user_info->service_description
 		= gensec_get_target_service_description(gensec_security);
 	user_info->auth_description = "NTLMSSP";
diff --git a/source3/auth/auth_generic.c b/source3/auth/auth_generic.c
index 55555e8..05f3019 100644
--- a/source3/auth/auth_generic.c
+++ b/source3/auth/auth_generic.c
@@ -233,6 +233,7 @@ NTSTATUS make_auth4_context(TALLOC_CTX *mem_ctx, struct auth4_context **auth4_co
 
 NTSTATUS auth_generic_prepare(TALLOC_CTX *mem_ctx,
 			      const struct tsocket_address *remote_address,
+			      const struct tsocket_address *local_address,
 			      const char *service_description,
 			      struct gensec_security **gensec_security_out)
 {
@@ -378,6 +379,13 @@ NTSTATUS auth_generic_prepare(TALLOC_CTX *mem_ctx,
 		return nt_status;
 	}
 
+	nt_status = gensec_set_local_address(gensec_security,
+					     local_address);
+	if (!NT_STATUS_IS_OK(nt_status)) {
+		TALLOC_FREE(tmp_ctx);
+		return nt_status;
+	}
+
 	nt_status = gensec_set_target_service_description(gensec_security,
 							  service_description);
 
diff --git a/source3/auth/proto.h b/source3/auth/proto.h
index eb9756c..7f8b28c 100644
--- a/source3/auth/proto.h
+++ b/source3/auth/proto.h
@@ -98,7 +98,9 @@ NTSTATUS auth_domain_init(void);
 /* The following definitions come from auth/auth_generic.c  */
 
 NTSTATUS make_auth4_context(TALLOC_CTX *mem_ctx, struct auth4_context **auth4_context_out);
-NTSTATUS auth_generic_prepare(TALLOC_CTX *mem_ctx, const struct tsocket_address *remote_address,
+NTSTATUS auth_generic_prepare(TALLOC_CTX *mem_ctx,
+			      const struct tsocket_address *remote_address,
+			      const struct tsocket_address *local_address,
 			      const char *service_description,
 			      struct gensec_security **gensec_security_out);
 
diff --git a/source3/rpc_server/dcesrv_auth_generic.c b/source3/rpc_server/dcesrv_auth_generic.c
index 7bdfdee..1092cd3 100644
--- a/source3/rpc_server/dcesrv_auth_generic.c
+++ b/source3/rpc_server/dcesrv_auth_generic.c
@@ -29,13 +29,16 @@ static NTSTATUS auth_generic_server_authtype_start_as_root(TALLOC_CTX *mem_ctx,
 							   DATA_BLOB *token_in,
 							   DATA_BLOB *token_out,
 							   const struct tsocket_address *remote_address,
+							   const struct tsocket_address *local_address,
 							   const char *service_description,
 							   struct gensec_security **ctx)
 {
 	struct gensec_security *gensec_security = NULL;
 	NTSTATUS status;
 
-	status = auth_generic_prepare(talloc_tos(), remote_address,
+	status = auth_generic_prepare(talloc_tos(),
+				      remote_address,
+				      local_address,
 				      service_description,
 				      &gensec_security);
 	if (!NT_STATUS_IS_OK(status)) {
@@ -70,6 +73,7 @@ NTSTATUS auth_generic_server_authtype_start(TALLOC_CTX *mem_ctx,
 					    DATA_BLOB *token_in,
 					    DATA_BLOB *token_out,
 					    const struct tsocket_address *remote_address,
+					    const struct tsocket_address *local_address,
 					    const char *service_description,
 					    struct gensec_security **ctx)
 {
@@ -82,6 +86,7 @@ NTSTATUS auth_generic_server_authtype_start(TALLOC_CTX *mem_ctx,
 							    token_in,
 							    token_out,
 							    remote_address,
+							    local_address,
 							    service_description,
 							    ctx);
 	unbecome_root();
diff --git a/source3/rpc_server/dcesrv_auth_generic.h b/source3/rpc_server/dcesrv_auth_generic.h
index 36e1a83..4e86eab 100644
--- a/source3/rpc_server/dcesrv_auth_generic.h
+++ b/source3/rpc_server/dcesrv_auth_generic.h
@@ -27,6 +27,7 @@ NTSTATUS auth_generic_server_authtype_start(TALLOC_CTX *mem_ctx,
 					    DATA_BLOB *token_in,
 					    DATA_BLOB *token_out,
 					    const struct tsocket_address *remote_address,
+					    const struct tsocket_address *local_address,
 					    const char *service_description,
 					    struct gensec_security **ctx);
 
diff --git a/source3/rpc_server/srv_pipe.c b/source3/rpc_server/srv_pipe.c
index 4a63dd7..446679f 100644
--- a/source3/rpc_server/srv_pipe.c
+++ b/source3/rpc_server/srv_pipe.c
@@ -530,6 +530,7 @@ static bool pipe_auth_generic_bind(struct pipes_struct *p,
 						    &auth_info->credentials,
 						    response,
 						    p->remote_address,
+						    p->local_address,
 						    service_description,
 						    &gensec_security);
 	if (!NT_STATUS_IS_OK(status) &&
diff --git a/source3/smbd/negprot.c b/source3/smbd/negprot.c
index 119f2a9..de3d531 100644
--- a/source3/smbd/negprot.c
+++ b/source3/smbd/negprot.c
@@ -171,13 +171,14 @@ DATA_BLOB negprot_spnego(TALLOC_CTX *ctx, struct smbXsrv_connection *xconn)
 	/* See if we can get an SPNEGO blob */
 	status = auth_generic_prepare(talloc_tos(),
 				      xconn->remote_address,
+				      xconn->local_address,
 				      "smb",
 				      &gensec_security);
 
 	/*
-	 * There is no need to set a remote address or similar as we
-	 * are just interested in the SPNEGO blob, we never keep this
-	 * context.
+	 * Despite including it above, there is no need to set a
+	 * remote address or similar as we are just interested in the
+	 * SPNEGO blob, we never keep this context.
 	 */
 
 	if (NT_STATUS_IS_OK(status)) {
diff --git a/source3/smbd/seal.c b/source3/smbd/seal.c
index f406c43..8a0dbeb 100644
--- a/source3/smbd/seal.c
+++ b/source3/smbd/seal.c
@@ -72,11 +72,13 @@ bool is_encrypted_packet(const uint8_t *inbuf)
 ******************************************************************************/
 
 static NTSTATUS make_auth_gensec(const struct tsocket_address *remote_address,
+				 const struct tsocket_address *local_address,
 				 struct smb_trans_enc_state *es)
 {
 	NTSTATUS status;
 
 	status = auth_generic_prepare(es, remote_address,
+				      local_address,
 				      "SMB encryption",
 				      &es->gensec_security);
 	if (!NT_STATUS_IS_OK(status)) {
@@ -107,6 +109,7 @@ static NTSTATUS make_auth_gensec(const struct tsocket_address *remote_address,
 ******************************************************************************/
 
 static NTSTATUS make_srv_encryption_context(const struct tsocket_address *remote_address,
+					    const struct tsocket_address *local_address,
 					    struct smb_trans_enc_state **pp_es)
 {
 	NTSTATUS status;
@@ -120,6 +123,7 @@ static NTSTATUS make_srv_encryption_context(const struct tsocket_address *remote
 		return NT_STATUS_NO_MEMORY;
 	}
 	status = make_auth_gensec(remote_address,
+				  local_address,
 				  es);
 	if (!NT_STATUS_IS_OK(status)) {
 		TALLOC_FREE(es);
@@ -208,6 +212,7 @@ NTSTATUS srv_request_encryption_setup(connection_struct *conn,
 	if (!partial_srv_trans_enc_ctx) {
 		/* This is the initial step. */
 		status = make_srv_encryption_context(conn->sconn->remote_address,
+						     conn->sconn->local_address,
 					&partial_srv_trans_enc_ctx);
 		if (!NT_STATUS_IS_OK(status)) {
 			return status;
diff --git a/source3/smbd/sesssetup.c b/source3/smbd/sesssetup.c
index e66aae5..5afd2a4 100644
--- a/source3/smbd/sesssetup.c
+++ b/source3/smbd/sesssetup.c
@@ -249,7 +249,9 @@ static void reply_sesssetup_and_X_spnego(struct smb_request *req)
 	}
 
 	if (auth->gensec == NULL) {
-		status = auth_generic_prepare(session, xconn->remote_address,
+		status = auth_generic_prepare(session,
+					      xconn->remote_address,
+					      xconn->local_address,
 					      "SMB",
 					      &auth->gensec);
 		if (!NT_STATUS_IS_OK(status)) {
diff --git a/source3/smbd/smb2_sesssetup.c b/source3/smbd/smb2_sesssetup.c
index 7e3102b..5246288 100644
--- a/source3/smbd/smb2_sesssetup.c
+++ b/source3/smbd/smb2_sesssetup.c
@@ -855,6 +855,7 @@ auth:
 	if (state->auth->gensec == NULL) {
 		status = auth_generic_prepare(state->auth,
 					      state->smb2req->xconn->remote_address,
+					      state->smb2req->xconn->local_address,
 					      "SMB2",
 					      &state->auth->gensec);
 		if (tevent_req_nterror(req, status)) {
diff --git a/source4/smb_server/smb/sesssetup.c b/source4/smb_server/smb/sesssetup.c
index 94f8bbc..3541926 100644
--- a/source4/smb_server/smb/sesssetup.c
+++ b/source4/smb_server/smb/sesssetup.c
@@ -117,7 +117,7 @@ failed:
 static void sesssetup_old(struct smbsrv_request *req, union smb_sesssetup *sess)
 {
 	struct auth_usersupplied_info *user_info = NULL;
-	struct tsocket_address *remote_address;
+	struct tsocket_address *remote_address, *local_address;
 	const char *remote_machine = NULL;
 	struct tevent_req *subreq;
 	struct sesssetup_context *state;
@@ -146,6 +146,9 @@ static void sesssetup_old(struct smbsrv_request *req, union smb_sesssetup *sess)
 		if (!remote_machine) goto nomem;
 	}
 
+	local_address = socket_get_local_addr(req->smb_conn->connection->socket, req);
+	if (!local_address) goto nomem;
+
 	user_info = talloc_zero(req, struct auth_usersupplied_info);
 	if (!user_info) goto nomem;
 
@@ -157,7 +160,9 @@ static void sesssetup_old(struct smbsrv_request *req, union smb_sesssetup *sess)
 	user_info->client.account_name = sess->old.in.user;
 	user_info->client.domain_name = sess->old.in.domain;
 	user_info->workstation_name = remote_machine;
+
 	user_info->remote_host = talloc_steal(user_info, remote_address);
+	user_info->local_host = talloc_steal(user_info, local_address);
 	
 	user_info->password_state = AUTH_PASSWORD_RESPONSE;
 	user_info->password.response.lanman = sess->old.in.password;
@@ -261,7 +266,7 @@ static void sesssetup_nt1(struct smbsrv_request *req, union smb_sesssetup *sess)
 {
 	NTSTATUS status;
 	struct auth_usersupplied_info *user_info = NULL;
-	struct tsocket_address *remote_address;
+	struct tsocket_address *remote_address, *local_address;
 	const char *remote_machine = NULL;
 	struct tevent_req *subreq;
 	struct sesssetup_context *state;
@@ -324,6 +329,9 @@ static void sesssetup_nt1(struct smbsrv_request *req, union smb_sesssetup *sess)
 		if (!remote_machine) goto nomem;
 	}
 
+	local_address = socket_get_local_addr(req->smb_conn->connection->socket, req);
+	if (!local_address) goto nomem;
+
 	user_info = talloc_zero(req, struct auth_usersupplied_info);
 	if (!user_info) goto nomem;
 
@@ -336,6 +344,7 @@ static void sesssetup_nt1(struct smbsrv_request *req, union smb_sesssetup *sess)
 	user_info->client.domain_name = sess->nt1.in.domain;
 	user_info->workstation_name = remote_machine;
 	user_info->remote_host = talloc_steal(user_info, remote_address);
+	user_info->local_host = talloc_steal(user_info, local_address);
 	
 	user_info->password_state = AUTH_PASSWORD_RESPONSE;
 	user_info->password.response.lanman = sess->nt1.in.password1;
@@ -452,7 +461,7 @@ static void sesssetup_spnego(struct smbsrv_request *req, union smb_sesssetup *se
 	/* lookup an existing session */
 	if (vuid == 0) {
 		struct gensec_security *gensec_ctx;
-
+		struct tsocket_address *remote_address, *local_address;
 		status = samba_server_gensec_start(req,
 						   req->smb_conn->connection->event.ctx,
 						   req->smb_conn->connection->msg_ctx,
@@ -467,6 +476,44 @@ static void sesssetup_spnego(struct smbsrv_request *req, union smb_sesssetup *se
 
 		gensec_want_feature(gensec_ctx, GENSEC_FEATURE_SESSION_KEY);
 
+		remote_address = socket_get_remote_addr(req->smb_conn->connection->socket,
+							req);
+		if (!remote_address) {
+			status = NT_STATUS_INTERNAL_ERROR;
+			DBG_ERR("Failed to obtain remote address");
+			goto failed;
+		}
+
+		status = gensec_set_remote_address(gensec_ctx,
+						   remote_address);
+		if (!NT_STATUS_IS_OK(status)) {
+			DBG_ERR("Failed to set remote address");
+			goto failed;
+		}
+
+		local_address = socket_get_local_addr(req->smb_conn->connection->socket,
+							req);
+		if (!local_address) {
+			status = NT_STATUS_INTERNAL_ERROR;
+			DBG_ERR("Failed to obtain local address");
+			goto failed;
+		}
+
+		status = gensec_set_local_address(gensec_ctx,
+						   local_address);
+		if (!NT_STATUS_IS_OK(status)) {
+			DBG_ERR("Failed to set local address");
+			goto failed;
+		}
+
+		status = gensec_set_target_service_description(gensec_ctx,
+							       "smb");
+
+		if (!NT_STATUS_IS_OK(status)) {
+			DBG_ERR("Failed to set service description");
+			goto failed;
+		}
+
 		status = gensec_start_mech_by_oid(gensec_ctx, req->smb_conn->negotiate.oid);
 		if (!NT_STATUS_IS_OK(status)) {
 			DEBUG(1, ("Failed to start GENSEC %s server code: %s\n", 
diff --git a/source4/smb_server/smb2/sesssetup.c b/source4/smb_server/smb2/sesssetup.c
index 5e261a2..7d92aa2 100644
--- a/source4/smb_server/smb2/sesssetup.c
+++ b/source4/smb_server/smb2/sesssetup.c
@@ -130,6 +130,7 @@ static void smb2srv_sesssetup_backend(struct smb2srv_request *req, union smb_ses
 	 */
 	if (vuid == 0) {
 		struct gensec_security *gensec_ctx;
+		struct tsocket_address *remote_address, *local_address;
 
 		status = samba_server_gensec_start(req,
 						   req->smb_conn->connection->event.ctx,
@@ -145,6 +146,44 @@ static void smb2srv_sesssetup_backend(struct smb2srv_request *req, union smb_ses
 
 		gensec_want_feature(gensec_ctx, GENSEC_FEATURE_SESSION_KEY);
 
+		remote_address = socket_get_remote_addr(req->smb_conn->connection->socket,
+							req);
+		if (!remote_address) {
+			status = NT_STATUS_INTERNAL_ERROR;
+			DBG_ERR("Failed to obtain remote address");
+			goto failed;
+		}
+
+		status = gensec_set_remote_address(gensec_ctx,
+						   remote_address);
+		if (!NT_STATUS_IS_OK(status)) {
+			DBG_ERR("Failed to set remote address");
+			goto failed;
+		}
+
+		local_address = socket_get_local_addr(req->smb_conn->connection->socket,
+							req);
+		if (!local_address) {
+			status = NT_STATUS_INTERNAL_ERROR;
+			DBG_ERR("Failed to obtain local address");
+			goto failed;
+		}
+
+		status = gensec_set_local_address(gensec_ctx,
+						   local_address);
+		if (!NT_STATUS_IS_OK(status)) {
+			DBG_ERR("Failed to set local address");
+			goto failed;
+		}
+
+		status = gensec_set_target_service_description(gensec_ctx,
+							       "smb2");
+
+		if (!NT_STATUS_IS_OK(status)) {
+			DBG_ERR("Failed to set service description");
+			goto failed;
+		}
+
 		status = gensec_start_mech_by_oid(gensec_ctx, GENSEC_OID_SPNEGO);
 		if (!NT_STATUS_IS_OK(status)) {
 			DEBUG(1, ("Failed to start GENSEC SPNEGO server code: %s\n", nt_errstr(status)));
-- 
2.7.4


From 559362f27a068c0dbd3bcb8ff10dbe3b9b8b7489 Mon Sep 17 00:00:00 2001
From: Gary Lockyer <gary at catalyst.net.nz>
Date: Fri, 24 Feb 2017 13:29:12 +1300
Subject: [PATCH 26/43] rpc: Always supply both the remote and local address to
 the auth subsystem

This ensures that gensec, and then the NTLM auth subsystem under it, always gets the
remote and local address pointers for potential logging.

The local address allows us to know which interface an authentication is on

Signed-off-by: Andrew Bartlett <abartlet at samba.org>
Pair-Programmed: Gary Lockyer <gary at catalyst.net.nz>
---
 source3/auth/auth_ntlmssp.c                     |  1 +
 source3/auth/auth_util.c                        | 17 +++++++--
 source3/auth/proto.h                            |  7 ++++
 source3/auth/user_info.c                        |  8 +++++
 source3/librpc/rpc/dcerpc_ep.c                  |  1 +
 source3/printing/nt_printing_migrate_internal.c |  1 +
 source3/printing/printspoolss.c                 |  2 ++
 source3/rpc_client/cli_winreg_int.c             |  1 +
 source3/rpc_server/netlogon/srv_netlog_nt.c     |  5 +++
 source3/rpc_server/rpc_ncacn_np.c               | 15 ++++++--
 source3/rpc_server/rpc_ncacn_np.h               |  4 +++
 source3/rpc_server/rpc_server.c                 | 48 +++++++++++++++++++------
 source3/rpc_server/spoolss/srv_spoolss_util.c   |  1 +
 source3/smbd/lanman.c                           | 20 +++++++++--
 source3/smbd/reply.c                            |  1 +
 source3/smbd/sesssetup.c                        | 11 ++++--
 source3/torture/pdbtest.c                       | 15 +++++---
 source3/winbindd/winbindd_cm.c                  |  2 ++
 source3/winbindd/winbindd_pam.c                 |  2 +-
 source4/rpc_server/dcesrv_auth.c                | 10 ++++++
 20 files changed, 143 insertions(+), 29 deletions(-)

diff --git a/source3/auth/auth_ntlmssp.c b/source3/auth/auth_ntlmssp.c
index 71b8183..f004c59 100644
--- a/source3/auth/auth_ntlmssp.c
+++ b/source3/auth/auth_ntlmssp.c
@@ -163,6 +163,7 @@ NTSTATUS auth3_check_password(struct auth4_context *auth4_context,
 				       user_info->client.domain_name,
 				       user_info->workstation_name,
 				       user_info->remote_host,
+				       user_info->local_host,
 				       user_info->service_description,
 	                               user_info->password.response.lanman.data ? &user_info->password.response.lanman : NULL,
 	                               user_info->password.response.nt.data ? &user_info->password.response.nt : NULL,
diff --git a/source3/auth/auth_util.c b/source3/auth/auth_util.c
index d015165..ffd60e0 100644
--- a/source3/auth/auth_util.c
+++ b/source3/auth/auth_util.c
@@ -97,6 +97,7 @@ NTSTATUS make_user_info_map(TALLOC_CTX *mem_ctx,
 			    const char *client_domain,
 			    const char *workstation_name,
 			    const struct tsocket_address *remote_address,
+			    const struct tsocket_address *local_address,
 			    const char *service_description,
 			    const DATA_BLOB *lm_pwd,
 			    const DATA_BLOB *nt_pwd,
@@ -151,8 +152,8 @@ NTSTATUS make_user_info_map(TALLOC_CTX *mem_ctx,
 
 	result = make_user_info(mem_ctx, user_info, smb_name, internal_username,
 				client_domain, domain, workstation_name,
-				remote_address, service_description,
-				lm_pwd, nt_pwd,
+				remote_address, local_address,
+				service_description, lm_pwd, nt_pwd,
 				lm_interactive_pwd, nt_interactive_pwd,
 				plaintext, password_state);
 	if (NT_STATUS_IS_OK(result)) {
@@ -175,6 +176,7 @@ bool make_user_info_netlogon_network(TALLOC_CTX *mem_ctx,
 				     const char *client_domain, 
 				     const char *workstation_name,
 				     const struct tsocket_address *remote_address,
+				     const struct tsocket_address *local_address,
 				     uint32_t logon_parameters,
 				     const uchar *lm_network_pwd,
 				     int lm_pwd_len,
@@ -190,6 +192,7 @@ bool make_user_info_netlogon_network(TALLOC_CTX *mem_ctx,
 				    smb_name, client_domain, 
 				    workstation_name,
 				    remote_address,
+				    local_address,
 				    "SamLogon",
 				    lm_pwd_len ? &lm_blob : NULL, 
 				    nt_pwd_len ? &nt_blob : NULL,
@@ -217,6 +220,7 @@ bool make_user_info_netlogon_interactive(TALLOC_CTX *mem_ctx,
 					 const char *client_domain, 
 					 const char *workstation_name,
 					 const struct tsocket_address *remote_address,
+					 const struct tsocket_address *local_address,
 					 uint32_t logon_parameters,
 					 const uchar chal[8], 
 					 const uchar lm_interactive_pwd[16], 
@@ -262,6 +266,7 @@ bool make_user_info_netlogon_interactive(TALLOC_CTX *mem_ctx,
 			user_info, 
 			smb_name, client_domain, workstation_name,
 			remote_address,
+			local_address,
 			"SamLogon",
 			lm_interactive_pwd ? &local_lm_blob : NULL,
 			nt_interactive_pwd ? &local_nt_blob : NULL,
@@ -290,6 +295,7 @@ bool make_user_info_for_reply(TALLOC_CTX *mem_ctx,
 			      const char *smb_name, 
 			      const char *client_domain,
 			      const struct tsocket_address *remote_address,
+			      const struct tsocket_address *local_address,
 			      const char *service_description,
 			      const uint8_t chal[8],
 			      DATA_BLOB plaintext_password)
@@ -338,6 +344,7 @@ bool make_user_info_for_reply(TALLOC_CTX *mem_ctx,
 		user_info, smb_name, smb_name, client_domain, client_domain, 
 		get_remote_machine_name(),
 		remote_address,
+		local_address,
 	        service_description,
 		local_lm_blob.data ? &local_lm_blob : NULL,
 		local_nt_blob.data ? &local_nt_blob : NULL,
@@ -363,6 +370,7 @@ NTSTATUS make_user_info_for_reply_enc(TALLOC_CTX *mem_ctx,
                                       const char *smb_name,
                                       const char *client_domain,
 				      const struct tsocket_address *remote_address,
+				      const struct tsocket_address *local_address,
 				      const char *service_description,
 				      DATA_BLOB lm_resp, DATA_BLOB nt_resp)
 {
@@ -382,9 +390,10 @@ NTSTATUS make_user_info_for_reply_enc(TALLOC_CTX *mem_ctx,
 
 	return make_user_info(mem_ctx,
 			      user_info, smb_name, smb_name,
-			      client_domain, client_domain, 
+			      client_domain, client_domain,
 			      get_remote_machine_name(),
 			      remote_address,
+			      local_address,
 			      service_description,
 			      lm_resp.data && (lm_resp.length > 0) ? &lm_resp : NULL,
 			      nt_resp.data && (nt_resp.length > 0) ? &nt_resp : NULL,
@@ -398,6 +407,7 @@ NTSTATUS make_user_info_for_reply_enc(TALLOC_CTX *mem_ctx,
 
 bool make_user_info_guest(TALLOC_CTX *mem_ctx,
 			  const struct tsocket_address *remote_address,
+			  const struct tsocket_address *local_address,
 			  const char *service_description,
 			  struct auth_usersupplied_info **user_info)
 {
@@ -409,6 +419,7 @@ bool make_user_info_guest(TALLOC_CTX *mem_ctx,
 				   "","", 
 				   "", 
 				   remote_address,
+				   local_address,
 				   service_description,
 				   NULL, NULL, 
 				   NULL, NULL, 
diff --git a/source3/auth/proto.h b/source3/auth/proto.h
index 7f8b28c..4ac9689 100644
--- a/source3/auth/proto.h
+++ b/source3/auth/proto.h
@@ -156,6 +156,7 @@ NTSTATUS make_user_info_map(TALLOC_CTX *mem_ctx,
 			    const char *client_domain,
 			    const char *workstation_name,
 			    const struct tsocket_address *remote_address,
+			    const struct tsocket_address *local_address,
 			    const char *service_description,
 			    const DATA_BLOB *lm_pwd,
 			    const DATA_BLOB *nt_pwd,
@@ -169,6 +170,7 @@ bool make_user_info_netlogon_network(TALLOC_CTX *mem_ctx,
 				     const char *client_domain,
 				     const char *workstation_name,
 				     const struct tsocket_address *remote_address,
+				     const struct tsocket_address *local_address,
 				     uint32_t logon_parameters,
 				     const uchar *lm_network_pwd,
 				     int lm_pwd_len,
@@ -180,6 +182,7 @@ bool make_user_info_netlogon_interactive(TALLOC_CTX *mem_ctx,
 					 const char *client_domain,
 					 const char *workstation_name,
 					 const struct tsocket_address *remote_address,
+					 const struct tsocket_address *local_address,
 					 uint32_t logon_parameters,
 					 const uchar chal[8],
 					 const uchar lm_interactive_pwd[16],
@@ -189,6 +192,7 @@ bool make_user_info_for_reply(TALLOC_CTX *mem_ctx,
 			      const char *smb_name,
 			      const char *client_domain,
 			      const struct tsocket_address *remote_address,
+			      const struct tsocket_address *local_address,
 			      const char *service_description,
 			      const uint8_t chal[8],
 			      DATA_BLOB plaintext_password);
@@ -197,10 +201,12 @@ NTSTATUS make_user_info_for_reply_enc(TALLOC_CTX *mem_ctx,
                                       const char *smb_name,
                                       const char *client_domain,
 				      const struct tsocket_address *remote_address,
+				      const struct tsocket_address *local_address,
 				      const char *service_description,
                                       DATA_BLOB lm_resp, DATA_BLOB nt_resp);
 bool make_user_info_guest(TALLOC_CTX *mem_ctx,
 			  const struct tsocket_address *remote_address,
+			  const struct tsocket_address *local_address,
 			  const char *service_description,
 			  struct auth_usersupplied_info **user_info);
 
@@ -270,6 +276,7 @@ NTSTATUS make_user_info(TALLOC_CTX *mem_ctx,
 			const char *domain,
 			const char *workstation_name,
 			const struct tsocket_address *remote_address,
+			const struct tsocket_address *local_address,
 			const char *service_description,
 			const DATA_BLOB *lm_pwd,
 			const DATA_BLOB *nt_pwd,
diff --git a/source3/auth/user_info.c b/source3/auth/user_info.c
index c410d22..6165d59 100644
--- a/source3/auth/user_info.c
+++ b/source3/auth/user_info.c
@@ -49,6 +49,7 @@ NTSTATUS make_user_info(TALLOC_CTX *mem_ctx,
 			const char *domain,
 			const char *workstation_name,
 			const struct tsocket_address *remote_address,
+			const struct tsocket_address *local_address,
 			const char *service_description,
 			const DATA_BLOB *lm_pwd,
 			const DATA_BLOB *nt_pwd,
@@ -106,6 +107,13 @@ NTSTATUS make_user_info(TALLOC_CTX *mem_ctx,
 		return NT_STATUS_NO_MEMORY;
 	}
 
+	user_info->local_host = tsocket_address_copy(local_address,
+						     user_info);
+	if (user_info->local_host == NULL) {
+		TALLOC_FREE(user_info);
+		return NT_STATUS_NO_MEMORY;
+	}
+
 	user_info->service_description = talloc_strdup(user_info, service_description);
 	if (user_info->service_description == NULL) {
 		TALLOC_FREE(user_info);
diff --git a/source3/librpc/rpc/dcerpc_ep.c b/source3/librpc/rpc/dcerpc_ep.c
index 0502557..da26fab 100644
--- a/source3/librpc/rpc/dcerpc_ep.c
+++ b/source3/librpc/rpc/dcerpc_ep.c
@@ -382,6 +382,7 @@ static NTSTATUS ep_register(TALLOC_CTX *mem_ctx,
 		status = rpcint_binding_handle(tmp_ctx,
 					       &ndr_table_epmapper,
 					       local,
+					       NULL,
 					       get_session_info_system(),
 					       msg_ctx,
 					       &h);
diff --git a/source3/printing/nt_printing_migrate_internal.c b/source3/printing/nt_printing_migrate_internal.c
index 34133b2..dd78e69 100644
--- a/source3/printing/nt_printing_migrate_internal.c
+++ b/source3/printing/nt_printing_migrate_internal.c
@@ -227,6 +227,7 @@ bool nt_printing_tdb_migrate(struct messaging_context *msg_ctx)
 					&ndr_table_winreg,
 					session_info,
 					NULL,
+					NULL,
 					msg_ctx,
 					&winreg_pipe);
 	if (!NT_STATUS_IS_OK(status)) {
diff --git a/source3/printing/printspoolss.c b/source3/printing/printspoolss.c
index e92f461..6000202 100644
--- a/source3/printing/printspoolss.c
+++ b/source3/printing/printspoolss.c
@@ -154,6 +154,7 @@ NTSTATUS print_spool_open(files_struct *fsp,
 					 &ndr_table_spoolss,
 					 fsp->conn->session_info,
 					 fsp->conn->sconn->remote_address,
+					 fsp->conn->sconn->local_address,
 					 fsp->conn->sconn->msg_ctx,
 					 &fsp->conn->spoolss_pipe);
 	if (!NT_STATUS_IS_OK(status)) {
@@ -343,6 +344,7 @@ void print_spool_terminate(struct connection_struct *conn,
 					 &ndr_table_spoolss,
 					 conn->session_info,
 					 conn->sconn->remote_address,
+					 conn->sconn->local_address,
 					 conn->sconn->msg_ctx,
 					 &conn->spoolss_pipe);
 	if (!NT_STATUS_IS_OK(status)) {
diff --git a/source3/rpc_client/cli_winreg_int.c b/source3/rpc_client/cli_winreg_int.c
index ac04460..3ac8380 100644
--- a/source3/rpc_client/cli_winreg_int.c
+++ b/source3/rpc_client/cli_winreg_int.c
@@ -115,6 +115,7 @@ static NTSTATUS _winreg_int_openkey(TALLOC_CTX *mem_ctx,
 	status = rpcint_binding_handle(mem_ctx,
 				       &ndr_table_winreg,
 				       local,
+				       NULL,
 				       session_info,
 				       msg_ctx,
 				       &binding_handle);
diff --git a/source3/rpc_server/netlogon/srv_netlog_nt.c b/source3/rpc_server/netlogon/srv_netlog_nt.c
index ef2c827..424ff71 100644
--- a/source3/rpc_server/netlogon/srv_netlog_nt.c
+++ b/source3/rpc_server/netlogon/srv_netlog_nt.c
@@ -423,6 +423,7 @@ NTSTATUS _netr_NetrEnumerateTrustedDomains(struct pipes_struct *p,
 	status = rpcint_binding_handle(p->mem_ctx,
 				       &ndr_table_lsarpc,
 				       p->remote_address,
+				       p->local_address,
 				       p->session_info,
 				       p->msg_ctx,
 				       &h);
@@ -703,6 +704,7 @@ static NTSTATUS get_md4pw(struct samr_Password *md4pw, const char *mach_acct,
 	status = rpcint_binding_handle(mem_ctx,
 				       &ndr_table_samr,
 				       local,
+				       NULL,
 				       session_info,
 				       msg_ctx,
 				       &h);
@@ -1181,6 +1183,7 @@ static NTSTATUS netr_set_machine_account_password(TALLOC_CTX *mem_ctx,
 	status = rpcint_binding_handle(mem_ctx,
 				       &ndr_table_samr,
 				       local,
+				       NULL,
 				       session_info,
 				       msg_ctx,
 				       &h);
@@ -1605,6 +1608,7 @@ static NTSTATUS _netr_LogonSamLogon_base(struct pipes_struct *p,
 						     nt_username, nt_domain,
 						     wksname,
 						     p->remote_address,
+						     p->local_address,
 						     logon->network->identity_info.parameter_control,
 						     logon->network->lm.data,
 						     logon->network->lm.length,
@@ -1664,6 +1668,7 @@ static NTSTATUS _netr_LogonSamLogon_base(struct pipes_struct *p,
 							 nt_username, nt_domain,
 							 nt_workstation,
 							 p->remote_address,
+							 p->local_address,
 							 logon->password->identity_info.parameter_control,
 							 chal,
 							 logon->password->lmpassword.hash,
diff --git a/source3/rpc_server/rpc_ncacn_np.c b/source3/rpc_server/rpc_ncacn_np.c
index cb3b8e6..121e776 100644
--- a/source3/rpc_server/rpc_ncacn_np.c
+++ b/source3/rpc_server/rpc_ncacn_np.c
@@ -183,6 +183,7 @@ out:
 struct pipes_struct *make_internal_rpc_pipe_p(TALLOC_CTX *mem_ctx,
 					      const struct ndr_syntax_id *syntax,
 					      const struct tsocket_address *remote_address,
+					      const struct tsocket_address *local_address,
 					      const struct auth_session_info *session_info,
 					      struct messaging_context *msg_ctx)
 {
@@ -204,7 +205,7 @@ struct pipes_struct *make_internal_rpc_pipe_p(TALLOC_CTX *mem_ctx,
 
 	ret = make_base_pipes_struct(mem_ctx, msg_ctx, pipe_name,
 				     NCALRPC, RPC_LITTLE_ENDIAN,
-				     remote_address, NULL, &p);
+				     remote_address, local_address, &p);
 	if (ret) {
 		DEBUG(0,("ERROR! no memory for pipes_struct!\n"));
 		return NULL;
@@ -492,6 +493,7 @@ static NTSTATUS rpcint_binding_handle_ex(TALLOC_CTX *mem_ctx,
 			const struct ndr_syntax_id *abstract_syntax,
 			const struct ndr_interface_table *ndr_table,
 			const struct tsocket_address *remote_address,
+			const struct tsocket_address *local_address,
 			const struct auth_session_info *session_info,
 			struct messaging_context *msg_ctx,
 			struct dcerpc_binding_handle **binding_handle)
@@ -516,6 +518,7 @@ static NTSTATUS rpcint_binding_handle_ex(TALLOC_CTX *mem_ctx,
 	hs->p = make_internal_rpc_pipe_p(hs,
 					 abstract_syntax,
 					 remote_address,
+					 local_address,
 					 session_info,
 					 msg_ctx);
 	if (hs->p == NULL) {
@@ -560,12 +563,14 @@ static NTSTATUS rpcint_binding_handle_ex(TALLOC_CTX *mem_ctx,
 NTSTATUS rpcint_binding_handle(TALLOC_CTX *mem_ctx,
 			       const struct ndr_interface_table *ndr_table,
 			       const struct tsocket_address *remote_address,
+			       const struct tsocket_address *local_address,
 			       const struct auth_session_info *session_info,
 			       struct messaging_context *msg_ctx,
 			       struct dcerpc_binding_handle **binding_handle)
 {
 	return rpcint_binding_handle_ex(mem_ctx, NULL, ndr_table, remote_address,
-					session_info, msg_ctx, binding_handle);
+					local_address, session_info,
+					msg_ctx, binding_handle);
 }
 
 /**
@@ -596,6 +601,7 @@ NTSTATUS rpc_pipe_open_internal(TALLOC_CTX *mem_ctx,
 				const struct ndr_interface_table *ndr_table,
 				const struct auth_session_info *session_info,
 				const struct tsocket_address *remote_address,
+				const struct tsocket_address *local_address,
 				struct messaging_context *msg_ctx,
 				struct rpc_pipe_client **presult)
 {
@@ -632,6 +638,7 @@ NTSTATUS rpc_pipe_open_internal(TALLOC_CTX *mem_ctx,
 	status = rpcint_binding_handle(result,
 				       ndr_table,
 				       remote_address,
+				       local_address,
 				       session_info,
 				       msg_ctx,
 				       &result->binding_handle);
@@ -1033,6 +1040,7 @@ NTSTATUS rpc_pipe_open_interface(TALLOC_CTX *mem_ctx,
 				 const struct ndr_interface_table *table,
 				 const struct auth_session_info *session_info,
 				 const struct tsocket_address *remote_address,
+				 const struct tsocket_address *local_address,
 				 struct messaging_context *msg_ctx,
 				 struct rpc_pipe_client **cli_pipe)
 {
@@ -1074,7 +1082,8 @@ NTSTATUS rpc_pipe_open_interface(TALLOC_CTX *mem_ctx,
 	case RPC_SERVICE_MODE_EMBEDDED:
 		status = rpc_pipe_open_internal(tmp_ctx,
 						table, session_info,
-						remote_address, msg_ctx,
+						remote_address, local_address,
+						msg_ctx,
 						&cli);
 		if (!NT_STATUS_IS_OK(status)) {
 			goto done;
diff --git a/source3/rpc_server/rpc_ncacn_np.h b/source3/rpc_server/rpc_ncacn_np.h
index 59b9d5a..2ae126d 100644
--- a/source3/rpc_server/rpc_ncacn_np.h
+++ b/source3/rpc_server/rpc_ncacn_np.h
@@ -65,6 +65,7 @@ struct np_proxy_state {
 struct pipes_struct *make_internal_rpc_pipe_p(TALLOC_CTX *mem_ctx,
 					      const struct ndr_syntax_id *syntax,
 					      const struct tsocket_address *remote_address,
+					      const struct tsocket_address *local_address,
 					      const struct auth_session_info *session_info,
 					      struct messaging_context *msg_ctx);
 struct np_proxy_state *make_external_rpc_pipe_p(TALLOC_CTX *mem_ctx,
@@ -75,6 +76,7 @@ struct np_proxy_state *make_external_rpc_pipe_p(TALLOC_CTX *mem_ctx,
 NTSTATUS rpcint_binding_handle(TALLOC_CTX *mem_ctx,
 			       const struct ndr_interface_table *ndr_table,
 			       const struct tsocket_address *remote_address,
+			       const struct tsocket_address *local_address,
 			       const struct auth_session_info *session_info,
 			       struct messaging_context *msg_ctx,
 			       struct dcerpc_binding_handle **binding_handle);
@@ -82,6 +84,7 @@ NTSTATUS rpc_pipe_open_interface(TALLOC_CTX *mem_ctx,
 				 const struct ndr_interface_table *table,
 				 const struct auth_session_info *session_info,
 				 const struct tsocket_address *remote_address,
+				 const struct tsocket_address *local_address,
 				 struct messaging_context *msg_ctx,
 				 struct rpc_pipe_client **cli_pipe);
 
@@ -89,6 +92,7 @@ NTSTATUS rpc_pipe_open_internal(TALLOC_CTX *mem_ctx,
 				const struct ndr_interface_table *ndr_table,
 				const struct auth_session_info *session_info,
 				const struct tsocket_address *remote_address,
+				const struct tsocket_address *local_address,
 				struct messaging_context *msg_ctx,
 				struct rpc_pipe_client **presult);
 
diff --git a/source3/rpc_server/rpc_server.c b/source3/rpc_server/rpc_server.c
index 6c988ce..21504c0 100644
--- a/source3/rpc_server/rpc_server.c
+++ b/source3/rpc_server/rpc_server.c
@@ -872,14 +872,18 @@ static void dcerpc_ncalrpc_listener(struct tevent_context *ev,
 	struct dcerpc_ncacn_listen_state *state =
 			talloc_get_type_abort(private_data,
 					      struct dcerpc_ncacn_listen_state);
-	struct tsocket_address *cli_addr = NULL;
+	struct tsocket_address *cli_addr = NULL, *srv_addr = NULL;
 	struct sockaddr_un sunaddr;
 	struct sockaddr *addr = (struct sockaddr *)(void *)&sunaddr;
 	socklen_t len = sizeof(sunaddr);
+	struct sockaddr_un sunaddr_server;
+	struct sockaddr *addr_server = (struct sockaddr *)(void *)&sunaddr_server;
+	socklen_t len_server = sizeof(sunaddr_server);
 	int sd = -1;
 	int rc;
 
 	ZERO_STRUCT(sunaddr);
+	ZERO_STRUCT(sunaddr_server);
 
 	sd = accept(state->fd, addr, &len);
 	if (sd == -1) {
@@ -897,13 +901,29 @@ static void dcerpc_ncalrpc_listener(struct tevent_context *ev,
 		return;
 	}
 
-	DEBUG(10, ("Accepted ncalrpc socket %d\n", sd));
+	rc = getsockname(sd, addr_server, &len_server);
+	if (rc < 0) {
+		close(sd);
+		return;
+	}
+
+	rc = tsocket_address_bsd_from_sockaddr(state,
+					       addr_server,
+					       len_server,
+					       &srv_addr);
+	if (rc < 0) {
+		close(sd);
+		return;
+	}
+
+	DEBUG(10, ("Accepted ncalrpc socket %s (fd: %d)\n",
+		   sunaddr.sun_path, sd));
 
 	dcerpc_ncacn_accept(state->ev_ctx,
 			    state->msg_ctx,
 			    NCALRPC,
 			    state->ep.name,
-			    cli_addr, NULL, sd,
+			    cli_addr, srv_addr, sd,
 			    state->disconnect_fn);
 }
 
@@ -977,7 +997,7 @@ void dcerpc_ncacn_accept(struct tevent_context *ev_ctx,
 						  ncacn_conn);
 	}
 	if (ncacn_conn->client_name == NULL) {
-		DEBUG(0, ("Out of memory!\n"));
+		DEBUG(0, ("Out of memory obtaining remote socket address as a string!\n"));
 		talloc_free(ncacn_conn);
 		close(s);
 		return;
@@ -986,11 +1006,17 @@ void dcerpc_ncacn_accept(struct tevent_context *ev_ctx,
 	if (srv_addr != NULL) {
 		ncacn_conn->server = talloc_move(ncacn_conn, &srv_addr);
 
-		ncacn_conn->server_name =
-			tsocket_address_inet_addr_string(ncacn_conn->server,
-							 ncacn_conn);
+		if (tsocket_address_is_inet(ncacn_conn->server, "ip")) {
+			ncacn_conn->server_name =
+				tsocket_address_inet_addr_string(ncacn_conn->server,
+								 ncacn_conn);
+		} else {
+			ncacn_conn->server_name =
+				tsocket_address_unix_path(ncacn_conn->server,
+							  ncacn_conn);
+		}
 		if (ncacn_conn->server_name == NULL) {
-			DEBUG(0, ("Out of memory!\n"));
+			DEBUG(0, ("Out of memory obtaining local socket address as a string!\n"));
 			talloc_free(ncacn_conn);
 			close(s);
 			return;
@@ -1021,7 +1047,7 @@ void dcerpc_ncacn_accept(struct tevent_context *ev_ctx,
 									    "/root/ncalrpc_as_system",
 									    &ncacn_conn->client);
 					if (rc < 0) {
-						DEBUG(0, ("Out of memory!\n"));
+						DEBUG(0, ("Out of memory building magic ncalrpc_as_system path!\n"));
 						talloc_free(ncacn_conn);
 						close(s);
 						return;
@@ -1031,7 +1057,7 @@ void dcerpc_ncacn_accept(struct tevent_context *ev_ctx,
 					ncacn_conn->client_name = tsocket_address_unix_path(ncacn_conn->client,
 											    ncacn_conn);
 					if (ncacn_conn->client == NULL) {
-						DEBUG(0, ("Out of memory!\n"));
+						DEBUG(0, ("Out of memory getting magic ncalrpc_as_system string!\n"));
 						talloc_free(ncacn_conn);
 						close(s);
 						return;
@@ -1110,7 +1136,7 @@ void dcerpc_ncacn_accept(struct tevent_context *ev_ctx,
 	ncacn_conn->send_queue = tevent_queue_create(ncacn_conn,
 							"dcerpc send queue");
 	if (ncacn_conn->send_queue == NULL) {
-		DEBUG(0, ("Out of memory!\n"));
+		DEBUG(0, ("Out of memory building dcerpc send queue!\n"));
 		talloc_free(ncacn_conn);
 		return;
 	}
diff --git a/source3/rpc_server/spoolss/srv_spoolss_util.c b/source3/rpc_server/spoolss/srv_spoolss_util.c
index 32f0e27..17acf51 100644
--- a/source3/rpc_server/spoolss/srv_spoolss_util.c
+++ b/source3/rpc_server/spoolss/srv_spoolss_util.c
@@ -48,6 +48,7 @@ WERROR winreg_printer_binding_handle(TALLOC_CTX *mem_ctx,
 	status = rpcint_binding_handle(mem_ctx,
 				       &ndr_table_winreg,
 				       local,
+				       NULL,
 				       session_info,
 				       msg_ctx,
 				       winreg_binding_handle);
diff --git a/source3/smbd/lanman.c b/source3/smbd/lanman.c
index 995ed08..c3e540f 100644
--- a/source3/smbd/lanman.c
+++ b/source3/smbd/lanman.c
@@ -835,6 +835,7 @@ static bool api_DosPrintQGetInfo(struct smbd_server_connection *sconn,
 					 &ndr_table_spoolss,
 					 conn->session_info,
 					 conn->sconn->remote_address,
+					 conn->sconn->local_address,
 					 conn->sconn->msg_ctx,
 					 &cli);
 	if (!NT_STATUS_IS_OK(status)) {
@@ -1032,6 +1033,7 @@ static bool api_DosPrintQEnum(struct smbd_server_connection *sconn,
 					 &ndr_table_spoolss,
 					 conn->session_info,
 					 conn->sconn->remote_address,
+					 conn->sconn->local_address,
 					 conn->sconn->msg_ctx,
 					 &cli);
 	if (!NT_STATUS_IS_OK(status)) {
@@ -2266,6 +2268,7 @@ static bool api_RNetShareAdd(struct smbd_server_connection *sconn,
 	status = rpc_pipe_open_interface(mem_ctx, &ndr_table_srvsvc,
 					conn->session_info,
 					conn->sconn->remote_address,
+					conn->sconn->local_address,
 					conn->sconn->msg_ctx,
 					&cli);
 	if (!NT_STATUS_IS_OK(status)) {
@@ -2377,7 +2380,7 @@ static bool api_RNetGroupEnum(struct smbd_server_connection *sconn,
 	status = rpc_pipe_open_interface(
 		talloc_tos(), &ndr_table_samr,
 		conn->session_info, conn->sconn->remote_address,
-		conn->sconn->msg_ctx, &samr_pipe);
+		conn->sconn->local_address, conn->sconn->msg_ctx, &samr_pipe);
 	if (!NT_STATUS_IS_OK(status)) {
 		DEBUG(0, ("api_RNetUserEnum: Could not connect to samr: %s\n",
 			  nt_errstr(status)));
@@ -2583,7 +2586,7 @@ static bool api_NetUserGetGroups(struct smbd_server_connection *sconn,
 	status = rpc_pipe_open_interface(
 		talloc_tos(), &ndr_table_samr,
 		conn->session_info, conn->sconn->remote_address,
-		conn->sconn->msg_ctx, &samr_pipe);
+		conn->sconn->local_address, conn->sconn->msg_ctx, &samr_pipe);
 	if (!NT_STATUS_IS_OK(status)) {
 		DEBUG(0, ("api_RNetUserEnum: Could not connect to samr: %s\n",
 			  nt_errstr(status)));
@@ -2783,7 +2786,7 @@ static bool api_RNetUserEnum(struct smbd_server_connection *sconn,
 	status = rpc_pipe_open_interface(
 		talloc_tos(), &ndr_table_samr,
 		conn->session_info, conn->sconn->remote_address,
-		conn->sconn->msg_ctx, &samr_pipe);
+		conn->sconn->local_address, conn->sconn->msg_ctx, &samr_pipe);
 	if (!NT_STATUS_IS_OK(status)) {
 		DEBUG(0, ("api_RNetUserEnum: Could not connect to samr: %s\n",
 			  nt_errstr(status)));
@@ -3047,6 +3050,7 @@ static bool api_SamOEMChangePassword(struct smbd_server_connection *sconn,
 	status = rpc_pipe_open_interface(mem_ctx, &ndr_table_samr,
 					conn->session_info,
 					conn->sconn->remote_address,
+					conn->sconn->local_address,
 					conn->sconn->msg_ctx,
 					&cli);
 	if (!NT_STATUS_IS_OK(status)) {
@@ -3144,6 +3148,7 @@ static bool api_RDosPrintJobDel(struct smbd_server_connection *sconn,
 					 &ndr_table_spoolss,
 					 conn->session_info,
 					 conn->sconn->remote_address,
+					 conn->sconn->local_address,
 					 conn->sconn->msg_ctx,
 					 &cli);
 	if (!NT_STATUS_IS_OK(status)) {
@@ -3272,6 +3277,7 @@ static bool api_WPrintQueueCtrl(struct smbd_server_connection *sconn,
 					 &ndr_table_spoolss,
 					 conn->session_info,
 					 conn->sconn->remote_address,
+					 conn->sconn->local_address,
 					 conn->sconn->msg_ctx,
 					 &cli);
 	if (!NT_STATUS_IS_OK(status)) {
@@ -3454,6 +3460,7 @@ static bool api_PrintJobInfo(struct smbd_server_connection *sconn,
 					 &ndr_table_spoolss,
 					 conn->session_info,
 					 conn->sconn->remote_address,
+					 conn->sconn->local_address,
 					 conn->sconn->msg_ctx,
 					 &cli);
 	if (!NT_STATUS_IS_OK(status)) {
@@ -3631,6 +3638,7 @@ static bool api_RNetServerGetInfo(struct smbd_server_connection *sconn,
 	status = rpc_pipe_open_interface(mem_ctx, &ndr_table_srvsvc,
 					conn->session_info,
 					conn->sconn->remote_address,
+					conn->sconn->local_address,
 					conn->sconn->msg_ctx,
 					&cli);
 	if (!NT_STATUS_IS_OK(status)) {
@@ -4067,6 +4075,7 @@ static bool api_RNetUserGetInfo(struct smbd_server_connection *sconn,
 	status = rpc_pipe_open_interface(mem_ctx, &ndr_table_samr,
 					conn->session_info,
 					conn->sconn->remote_address,
+					conn->sconn->local_address,
 					conn->sconn->msg_ctx,
 					&cli);
 	if (!NT_STATUS_IS_OK(status)) {
@@ -4596,6 +4605,7 @@ static bool api_WPrintJobGetInfo(struct smbd_server_connection *sconn,
 					 &ndr_table_spoolss,
 					 conn->session_info,
 					 conn->sconn->remote_address,
+					 conn->sconn->local_address,
 					 conn->sconn->msg_ctx,
 					 &cli);
 	if (!NT_STATUS_IS_OK(status)) {
@@ -4738,6 +4748,7 @@ static bool api_WPrintJobEnumerate(struct smbd_server_connection *sconn,
 					 &ndr_table_spoolss,
 					 conn->session_info,
 					 conn->sconn->remote_address,
+					 conn->sconn->local_address,
 					 conn->sconn->msg_ctx,
 					 &cli);
 	if (!NT_STATUS_IS_OK(status)) {
@@ -4938,6 +4949,7 @@ static bool api_WPrintDestGetInfo(struct smbd_server_connection *sconn,
 					 &ndr_table_spoolss,
 					 conn->session_info,
 					 conn->sconn->remote_address,
+					 conn->sconn->local_address,
 					 conn->sconn->msg_ctx,
 					 &cli);
 	if (!NT_STATUS_IS_OK(status)) {
@@ -5070,6 +5082,7 @@ static bool api_WPrintDestEnum(struct smbd_server_connection *sconn,
 					 &ndr_table_spoolss,
 					 conn->session_info,
 					 conn->sconn->remote_address,
+					 conn->sconn->local_address,
 					 conn->sconn->msg_ctx,
 					 &cli);
 	if (!NT_STATUS_IS_OK(status)) {
@@ -5381,6 +5394,7 @@ static bool api_RNetSessionEnum(struct smbd_server_connection *sconn,
 					 &ndr_table_srvsvc,
 					 conn->session_info,
 					 conn->sconn->remote_address,
+					 conn->sconn->local_address,
 					 conn->sconn->msg_ctx,
 					 &cli);
 	if (!NT_STATUS_IS_OK(status)) {
diff --git a/source3/smbd/reply.c b/source3/smbd/reply.c
index 22941ec..f8cd39d 100644
--- a/source3/smbd/reply.c
+++ b/source3/smbd/reply.c
@@ -5954,6 +5954,7 @@ void reply_printqueue(struct smb_request *req)
 						 &ndr_table_spoolss,
 						 conn->session_info,
 						 conn->sconn->remote_address,
+						 conn->sconn->local_address,
 						 conn->sconn->msg_ctx,
 						 &cli);
 		if (!NT_STATUS_IS_OK(status)) {
diff --git a/source3/smbd/sesssetup.c b/source3/smbd/sesssetup.c
index 5afd2a4..a570849 100644
--- a/source3/smbd/sesssetup.c
+++ b/source3/smbd/sesssetup.c
@@ -79,6 +79,7 @@ static int push_signature(uint8_t **outbuf)
 ****************************************************************************/
 
 static NTSTATUS check_guest_password(const struct tsocket_address *remote_address,
+				     const struct tsocket_address *local_address,
 				     TALLOC_CTX *mem_ctx, 
 				     struct auth_session_info **session_info)
 {
@@ -97,8 +98,8 @@ static NTSTATUS check_guest_password(const struct tsocket_address *remote_addres
 	auth_context->get_ntlm_challenge(auth_context,
 					 chal);
 
-	if (!make_user_info_guest(talloc_tos(), remote_address, "smb",
-				  &user_info)) {
+	if (!make_user_info_guest(talloc_tos(), remote_address, local_address,
+				  "smb", &user_info)) {
 		TALLOC_FREE(auth_context);
 		return NT_STATUS_NO_MEMORY;
 	}
@@ -884,7 +885,9 @@ void reply_sesssetup_and_X(struct smb_request *req)
 
 	if (!*user) {
 
-		nt_status = check_guest_password(sconn->remote_address, req, &session_info);
+		nt_status = check_guest_password(sconn->remote_address,
+						 sconn->local_address,
+						 req, &session_info);
 
 	} else if (doencrypt) {
 		struct auth4_context *negprot_auth_context = NULL;
@@ -901,6 +904,7 @@ void reply_sesssetup_and_X(struct smb_request *req)
 							 &user_info, user,
 							 domain,
 							 sconn->remote_address,
+							 sconn->local_address,
 							 "smb",
 							 lm_resp, nt_resp);
 		user_info->auth_description = "bare-NTLM";
@@ -925,6 +929,7 @@ void reply_sesssetup_and_X(struct smb_request *req)
 						      &user_info,
 						      user, domain,
 						      sconn->remote_address,
+						      sconn->local_address,
 						      "smb",
 						      chal,
 						      plaintext_password)) {
diff --git a/source3/torture/pdbtest.c b/source3/torture/pdbtest.c
index 56bacd5..f73c2c5 100644
--- a/source3/torture/pdbtest.c
+++ b/source3/torture/pdbtest.c
@@ -261,7 +261,8 @@ static bool test_auth(TALLOC_CTX *mem_ctx, struct samu *pdb_entry)
 	struct auth_context *auth_context;
 	static const uint8_t challenge_8[8] = {1, 2, 3, 4, 5, 6, 7, 8};
 	DATA_BLOB challenge = data_blob_const(challenge_8, sizeof(challenge_8));
-	struct tsocket_address *tsocket_address;
+	struct tsocket_address *remote_address;
+	struct tsocket_address *local_address;
 	unsigned char local_nt_response[24];
 	DATA_BLOB nt_resp = data_blob_const(local_nt_response, sizeof(local_nt_response));
 	unsigned char local_nt_session_key[16];
@@ -273,14 +274,18 @@ static bool test_auth(TALLOC_CTX *mem_ctx, struct samu *pdb_entry)
 		      local_nt_response);
 	SMBsesskeygen_ntv1(pdb_get_nt_passwd(pdb_entry), local_nt_session_key);
 
-	if (tsocket_address_inet_from_strings(NULL, "ip", NULL, 0, &tsocket_address) != 0) {
+	if (tsocket_address_inet_from_strings(NULL, "ip", NULL, 0, &remote_address) != 0) {
 		return False;
 	}
-	
+
+	if (tsocket_address_inet_from_strings(NULL, "ip", NULL, 0, &local_address) != 0) {
+		return False;
+	}
+
 	status = make_user_info(mem_ctx,
 				&user_info, pdb_get_username(pdb_entry), pdb_get_username(pdb_entry),
-				pdb_get_domain(pdb_entry), pdb_get_domain(pdb_entry), lp_netbios_name(), 
-				tsocket_address, "pdbtest",
+				pdb_get_domain(pdb_entry), pdb_get_domain(pdb_entry), lp_netbios_name(),
+				remote_address,local_address, "pdbtest",
 				NULL, &nt_resp, NULL, NULL, NULL,
 				AUTH_PASSWORD_RESPONSE);
 	if (!NT_STATUS_IS_OK(status)) {
diff --git a/source3/winbindd/winbindd_cm.c b/source3/winbindd/winbindd_cm.c
index 3df4af3..157a193 100644
--- a/source3/winbindd/winbindd_cm.c
+++ b/source3/winbindd/winbindd_cm.c
@@ -1778,6 +1778,7 @@ NTSTATUS wb_open_internal_pipe(TALLOC_CTX *mem_ctx,
 						 table,
 						 session_info,
 						 NULL,
+						 NULL,
 						 winbind_messaging_context(),
 						 &cli);
 	} else {
@@ -1785,6 +1786,7 @@ NTSTATUS wb_open_internal_pipe(TALLOC_CTX *mem_ctx,
 						table,
 						session_info,
 						NULL,
+						NULL,
 						winbind_messaging_context(),
 						&cli);
 	}
diff --git a/source3/winbindd/winbindd_pam.c b/source3/winbindd/winbindd_pam.c
index 93b3493..419ed6e 100644
--- a/source3/winbindd/winbindd_pam.c
+++ b/source3/winbindd/winbindd_pam.c
@@ -1254,7 +1254,7 @@ static NTSTATUS winbindd_dual_auth_passdb(TALLOC_CTX *mem_ctx,
 	 * here.
 	 */
 	status = make_user_info(frame, &user_info, user, user, domain, domain,
-				lp_netbios_name(), local,
+				lp_netbios_name(), local, local,
 				"winbind",
 				lm_resp, nt_resp, NULL, NULL,
 				NULL, AUTH_PASSWORD_RESPONSE);
diff --git a/source4/rpc_server/dcesrv_auth.c b/source4/rpc_server/dcesrv_auth.c
index 769b52b..ece314d 100644
--- a/source4/rpc_server/dcesrv_auth.c
+++ b/source4/rpc_server/dcesrv_auth.c
@@ -149,6 +149,16 @@ bool dcesrv_auth_bind(struct dcesrv_call_state *call)
 		}
 	}
 
+	if (call->conn->local_address != NULL) {
+		status = gensec_set_local_address(auth->gensec_security,
+						  call->conn->local_address);
+		if (!NT_STATUS_IS_OK(status)) {
+			DEBUG(1, ("Failed to call gensec_set_local_address() %s\n",
+				  nt_errstr(status)));
+			return false;
+		}
+	}
+
 	status = gensec_start_mech_by_authtype(auth->gensec_security, auth->auth_type,
 					       auth->auth_level);
 	if (!NT_STATUS_IS_OK(status)) {
-- 
2.7.4


From 363ffd40ad6faacad748ee06280e89319db5052e Mon Sep 17 00:00:00 2001
From: Andrew Bartlett <abartlet at samba.org>
Date: Wed, 1 Mar 2017 12:18:49 +1300
Subject: [PATCH 27/43] auth: Add logging of service authorization

Signed-off-by: Andrew Bartlett <abartlet at samba.org>
Pair-Programmed: Gary Lockyer <gary at catalyst.net.nz>
---
 auth/auth_log.c           | 54 +++++++++++++++++++++++++++++++++++++++++++++++
 auth/common_auth.h        |  5 +++++
 auth/gensec/gensec.c      | 36 +++++++++++++++++++++++++++++--
 auth/gensec/gensec.h      |  1 +
 source3/libads/authdata.c |  2 ++
 source3/utils/ntlm_auth.c |  2 ++
 6 files changed, 98 insertions(+), 2 deletions(-)

diff --git a/auth/auth_log.c b/auth/auth_log.c
index fc3f550..db46f2b 100644
--- a/auth/auth_log.c
+++ b/auth/auth_log.c
@@ -117,3 +117,57 @@ void log_authentication_event(const struct auth_usersupplied_info *ui,
 
 	talloc_free(frame);
 }
+
+
+/*
+ * Log details of a successful authorization to a service.
+ *
+ * Only successful authorizations are logged.  For clarity:
+ * - NTLM bad passwords will be recorded by the above
+ * - Kerberos decrypt failures need to be logged in gensec_gssapi et al
+ *
+ * The service may later refuse authorization due to an ACL.
+ *
+ */
+void log_successful_authz_event(const struct tsocket_address *remote,
+				const struct tsocket_address *local,
+				const char *service_description,
+				struct auth_session_info *session_info)
+{
+	TALLOC_CTX *frame = NULL;
+
+	char *ts = NULL;             /* formatted current time      */
+	char *remote_str = NULL;     /* formatted remote host       */
+	char *local_str = NULL;      /* formatted local host        */
+	char sid_buf[DOM_SID_STR_BUFLEN];
+
+	/* set the log level */
+	if (!CHECK_DEBUGLVLC( DBGC_AUTH_AUDIT, AUTHZ_SUCCESS_LEVEL)) {
+		return;
+	}
+
+	frame = talloc_stackframe();
+
+	/* Get the current time */
+        ts = http_timestring(frame, time(NULL));
+
+	remote_str = tsocket_address_string(remote, frame);
+	local_str  = tsocket_address_string(local, frame);
+
+	dom_sid_string_buf(&session_info->security_token->sids[0], sid_buf, sizeof(sid_buf));
+
+	DEBUGC( DBGC_AUTH_AUDIT, AUTHZ_SUCCESS_LEVEL, (
+		"Successful AuthZ: [%s] user [%s]\\[%s] [%s]"
+		" at [%s]"
+		" Remote host [%s]"
+		" local host [%s]\n",
+		service_description,
+		log_escape(frame, session_info->info->domain_name),
+		log_escape(frame, session_info->info->account_name),
+		sid_buf,
+		ts,
+		remote_str,
+		local_str));
+
+	talloc_free(frame);
+}
diff --git a/auth/common_auth.h b/auth/common_auth.h
index 9a83158..67fc6bc 100644
--- a/auth/common_auth.h
+++ b/auth/common_auth.h
@@ -152,4 +152,9 @@ void log_authentication_event(const struct auth_usersupplied_info *ui,
 			      const char *domain_name,
 			      const char *unix_username,
 			      struct dom_sid *sid);
+
+void log_successful_authz_event(const struct tsocket_address *remote,
+				const struct tsocket_address *local,
+				const char *service_description,
+				struct auth_session_info *session_info);
 #endif
diff --git a/auth/gensec/gensec.c b/auth/gensec/gensec.c
index e413fbd..d97d3b4 100644
--- a/auth/gensec/gensec.c
+++ b/auth/gensec/gensec.c
@@ -29,6 +29,7 @@
 #include "auth/gensec/gensec.h"
 #include "auth/gensec/gensec_internal.h"
 #include "librpc/gen_ndr/dcerpc.h"
+#include "auth/common_auth.h"
 
 _PRIVATE_ NTSTATUS gensec_may_reset_crypto(struct gensec_security *gensec_security,
 					   bool full_reset)
@@ -192,13 +193,36 @@ _PUBLIC_ NTSTATUS gensec_session_key(struct gensec_security *gensec_security,
 	return gensec_security->ops->session_key(gensec_security, mem_ctx, session_key);
 }
 
+/*
+ * Log details of a successful GENSEC authorization to a service.
+ *
+ * Only successful authorizations are logged, as only these call gensec_session_info()
+ *
+ * The service may later refuse authorization due to an ACL.
+ *
+ */
+static void log_successful_gensec_authz_event(struct gensec_security *gensec_security,
+					      struct auth_session_info *session_info)
+{
+	const struct tsocket_address *remote
+		= gensec_get_remote_address(gensec_security);
+	const struct tsocket_address *local
+		= gensec_get_local_address(gensec_security);
+	const char *service_description
+		= gensec_get_target_service_description(gensec_security);
+	log_successful_authz_event(remote, local, service_description, session_info);
+}
+
+
 /**
  * Return the credentials of a logged on user, including session keys
  * etc.
  *
  * Only valid after a successful authentication
  *
- * May only be called once per authentication.
+ * May only be called once per authentication.  This will also make an
+ * authorization log entry, as it is already called by all the
+ * callers.
  *
  */
 
@@ -206,10 +230,18 @@ _PUBLIC_ NTSTATUS gensec_session_info(struct gensec_security *gensec_security,
 				      TALLOC_CTX *mem_ctx,
 				      struct auth_session_info **session_info)
 {
+	NTSTATUS status;
 	if (!gensec_security->ops->session_info) {
 		return NT_STATUS_NOT_IMPLEMENTED;
 	}
-	return gensec_security->ops->session_info(gensec_security, mem_ctx, session_info);
+	status = gensec_security->ops->session_info(gensec_security, mem_ctx, session_info);
+
+	if (NT_STATUS_IS_OK(status)
+	    && (gensec_security->want_features & GENSEC_FEATURE_NO_AUTHZ_LOG) == 0) {
+		log_successful_gensec_authz_event(gensec_security, *session_info);
+	}
+
+	return status;
 }
 
 _PUBLIC_ void gensec_set_max_update_size(struct gensec_security *gensec_security,
diff --git a/auth/gensec/gensec.h b/auth/gensec/gensec.h
index 0c9fa26..7bd8932 100644
--- a/auth/gensec/gensec.h
+++ b/auth/gensec/gensec.h
@@ -64,6 +64,7 @@ struct gensec_target {
 #define GENSEC_FEATURE_UNIX_TOKEN	0x00000100
 #define GENSEC_FEATURE_NTLM_CCACHE	0x00000200
 #define GENSEC_FEATURE_LDAP_STYLE	0x00000400
+#define GENSEC_FEATURE_NO_AUTHZ_LOG	0x00000800
 
 #define GENSEC_EXPIRE_TIME_INFINITY (NTTIME)0x8000000000000000LL
 
diff --git a/source3/libads/authdata.c b/source3/libads/authdata.c
index f4f4b4f..2d7153b 100644
--- a/source3/libads/authdata.c
+++ b/source3/libads/authdata.c
@@ -269,6 +269,8 @@ NTSTATUS kerberos_return_pac(TALLOC_CTX *mem_ctx,
 	talloc_unlink(tmp_ctx, gensec_settings);
 	talloc_unlink(tmp_ctx, auth_context);
 
+	gensec_want_feature(gensec_server_context, GENSEC_FEATURE_NO_AUTHZ_LOG);
+
 	status = gensec_start_mech_by_oid(gensec_server_context, GENSEC_OID_KERBEROS5);
 	if (!NT_STATUS_IS_OK(status)) {
 		DEBUG(1, (__location__ "Failed to start server-side GENSEC krb5 to validate a Kerberos ticket: %s\n", nt_errstr(status)));
diff --git a/source3/utils/ntlm_auth.c b/source3/utils/ntlm_auth.c
index 516b485..968f980 100644
--- a/source3/utils/ntlm_auth.c
+++ b/source3/utils/ntlm_auth.c
@@ -1446,6 +1446,8 @@ static void manage_gensec_request(enum stdio_helper_mode stdio_helper_mode,
 
 		gensec_want_feature_list(state->gensec_state, want_feature_list);
 
+		gensec_want_feature(state->gensec_state, GENSEC_FEATURE_NO_AUTHZ_LOG);
+		
 		switch (stdio_helper_mode) {
 		case GSS_SPNEGO_CLIENT:
 		case GSS_SPNEGO_SERVER:
-- 
2.7.4


From a59084beeb7aade07af2b7d12646bdc0fc761bd4 Mon Sep 17 00:00:00 2001
From: Andrew Bartlett <abartlet at samba.org>
Date: Wed, 1 Mar 2017 14:19:50 +1300
Subject: [PATCH 28/43] dns: Provide local and remote socket address to GENSEC

This can be used for logging and for Kerberos channel bindings

Signed-off-by: Andrew Bartlett <abartlet at samba.org>
Pair-Programmed: Gary Lockyer <gary at catalyst.net.nz>
---
 source4/dns_server/dns_query.c  | 21 +++++++++++++++++++++
 source4/dns_server/dns_server.c | 14 ++++++++++++--
 source4/dns_server/dns_server.h |  2 ++
 3 files changed, 35 insertions(+), 2 deletions(-)

diff --git a/source4/dns_server/dns_query.c b/source4/dns_server/dns_query.c
index c0ae19a..2373dde 100644
--- a/source4/dns_server/dns_query.c
+++ b/source4/dns_server/dns_query.c
@@ -702,6 +702,8 @@ static WERROR handle_authoritative_recv(struct tevent_req *req)
 static NTSTATUS create_tkey(struct dns_server *dns,
 			    const char* name,
 			    const char* algorithm,
+			    const struct tsocket_address *remote_address,
+			    const struct tsocket_address *local_address,
 			    struct dns_server_tkey **tkey)
 {
 	NTSTATUS status;
@@ -738,6 +740,23 @@ static NTSTATUS create_tkey(struct dns_server *dns,
 
 	gensec_want_feature(k->gensec, GENSEC_FEATURE_SIGN);
 
+	status = gensec_set_remote_address(k->gensec,
+					   remote_address);
+	if (!NT_STATUS_IS_OK(status)) {
+		DEBUG(1, ("Failed to set remote address into GENSEC: %s\n",
+			  nt_errstr(status)));
+		*tkey = NULL;
+	}
+
+	status = gensec_set_local_address(k->gensec,
+					  local_address);
+	if (!NT_STATUS_IS_OK(status)) {
+		DEBUG(1, ("Failed to set local address into GENSEC: %s\n",
+			  nt_errstr(status)));
+		*tkey = NULL;
+		return status;
+	}
+
 	status = gensec_start_mech_by_oid(k->gensec, GENSEC_OID_SPNEGO);
 
 	if (!NT_STATUS_IS_OK(status)) {
@@ -861,6 +880,8 @@ static WERROR handle_tkey(struct dns_server *dns,
 		if (tkey == NULL) {
 			status  = create_tkey(dns, in->questions[0].name,
 					      in_tkey->rdata.tkey_record.algorithm,
+					      state->remote_address,
+					      state->local_address,
 					      &tkey);
 			if (!NT_STATUS_IS_OK(status)) {
 				ret_tkey->rdata.tkey_record.error = DNS_RCODE_BADKEY;
diff --git a/source4/dns_server/dns_server.c b/source4/dns_server/dns_server.c
index 830e070..86776b0 100644
--- a/source4/dns_server/dns_server.c
+++ b/source4/dns_server/dns_server.c
@@ -117,6 +117,8 @@ static void dns_process_done(struct tevent_req *subreq);
 static struct tevent_req *dns_process_send(TALLOC_CTX *mem_ctx,
 					   struct tevent_context *ev,
 					   struct dns_server *dns,
+					   const struct tsocket_address *remote_address,
+					   const struct tsocket_address *local_address,
 					   DATA_BLOB *in)
 {
 	struct tevent_req *req, *subreq;
@@ -161,6 +163,8 @@ static struct tevent_req *dns_process_send(TALLOC_CTX *mem_ctx,
 	state->state.flags = state->in_packet.operation;
 	state->state.flags |= DNS_FLAG_REPLY;
 
+	state->state.local_address = local_address;
+	state->state.remote_address = remote_address;
 
 	if (forwarder && *forwarder && **forwarder) {
 		state->state.flags |= DNS_FLAG_RECURSION_AVAIL;
@@ -168,7 +172,8 @@ static struct tevent_req *dns_process_send(TALLOC_CTX *mem_ctx,
 
 	state->out_packet = state->in_packet;
 
-	ret = dns_verify_tsig(dns, state, &state->state, &state->out_packet, in);
+	ret = dns_verify_tsig(dns, state, &state->state,
+			      &state->out_packet, in);
 	if (!W_ERROR_IS_OK(ret)) {
 		state->dns_err = werr_to_dns_err(ret);
 		tevent_req_done(req);
@@ -178,7 +183,8 @@ static struct tevent_req *dns_process_send(TALLOC_CTX *mem_ctx,
 	switch (state->in_packet.operation & DNS_OPCODE) {
 	case DNS_OPCODE_QUERY:
 		subreq = dns_server_process_query_send(
-			state, ev, dns, &state->state, &state->in_packet);
+			state, ev, dns,
+			&state->state, &state->in_packet);
 		if (tevent_req_nomem(subreq, req)) {
 			return tevent_req_post(req, ev);
 		}
@@ -333,6 +339,8 @@ static void dns_tcp_call_loop(struct tevent_req *subreq)
 	call->in.length -= 2;
 
 	subreq = dns_process_send(call, dns->task->event_ctx, dns,
+				  dns_conn->conn->remote_address,
+				  dns_conn->conn->local_address,
 				  &call->in);
 	if (subreq == NULL) {
 		dns_tcp_terminate_connection(
@@ -534,6 +542,8 @@ static void dns_udp_call_loop(struct tevent_req *subreq)
 		 tsocket_address_string(call->src, call)));
 
 	subreq = dns_process_send(call, dns->task->event_ctx, dns,
+				  call->src,
+				  sock->dns_socket->local_address,
 				  &call->in);
 	if (subreq == NULL) {
 		TALLOC_FREE(call);
diff --git a/source4/dns_server/dns_server.h b/source4/dns_server/dns_server.h
index e623f97..5395ff9 100644
--- a/source4/dns_server/dns_server.h
+++ b/source4/dns_server/dns_server.h
@@ -61,6 +61,8 @@ struct dns_request_state {
 	char *key_name;
 	struct dns_res_rec *tsig;
 	uint16_t tsig_error;
+	const struct tsocket_address *local_address;
+	const struct tsocket_address *remote_address;
 };
 
 struct tevent_req *dns_server_process_query_send(
-- 
2.7.4


From 8b3ffc7adf509a653305caf039807348671ae2c9 Mon Sep 17 00:00:00 2001
From: Andrew Bartlett <abartlet at samba.org>
Date: Wed, 1 Mar 2017 15:06:25 +1300
Subject: [PATCH 29/43] auth_log: Expand to include the type of password used
 (eg ntlmv2)

Signed-off-by: Andrew Bartlett <abartlet at samba.org>
Pair-Programmed: Gary Lockyer <gary at catalyst.net.nz>
---
 auth/auth_log.c | 41 ++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 40 insertions(+), 1 deletion(-)

diff --git a/auth/auth_log.c b/auth/auth_log.c
index db46f2b..3ec8dc8 100644
--- a/auth/auth_log.c
+++ b/auth/auth_log.c
@@ -33,6 +33,42 @@
 #include "libcli/security/dom_sid.h"
 
 /*
+ * Determine the type of the password supplied for the
+ * authorisation attempt.
+ *
+ */
+static const char* get_password_type(const struct auth_usersupplied_info *ui)
+{
+
+	const char *password_type = NULL;
+
+	if (ui->password_state == AUTH_PASSWORD_RESPONSE &&
+		   (ui->logon_parameters & MSV1_0_ALLOW_MSVCHAPV2) &&
+	    ui->password.response.nt.length == 24) {
+		password_type = "mschapv2";
+	} else if ((ui->logon_parameters & MSV1_0_CLEARTEXT_PASSWORD_SUPPLIED)
+		   || (ui->password_state == AUTH_PASSWORD_PLAIN)) {
+		password_type = "plaintext";
+	} else if (ui->password_state == AUTH_PASSWORD_HASH) {
+		password_type = "supplied-hash";
+	} else if (ui->password_state == AUTH_PASSWORD_RESPONSE
+		   && ui->password.response.nt.length > 24) {
+		password_type = "ntlmv2";
+	} else if (ui->password_state == AUTH_PASSWORD_RESPONSE
+		   && ui->password.response.nt.length == 24) {
+		password_type = "ntlmv1";
+	} else if (ui->password_state == AUTH_PASSWORD_RESPONSE
+		   && ui->password.response.lanman.length == 24) {
+		password_type = "lanman";
+	} else if (ui->password_state == AUTH_PASSWORD_RESPONSE
+		   && ui->password.response.nt.length == 0
+		   && ui->password.response.lanman.length == 0) {
+		password_type = "no-password";
+	}
+	return password_type;
+}
+
+/*
  * Log details of an authentication attempt.
  * Successful and unsuccessful attempts are logged.
  *
@@ -53,6 +89,7 @@ void log_authentication_event(const struct auth_usersupplied_info *ui,
 	char *trust_computer_name = NULL;
 	char *trust_account_name = NULL;
 	char *logon_line = NULL;
+	const char *password_type = NULL;
 
 	/* set the log level */
 	int  level = NT_STATUS_IS_OK(status) ? AUTH_FAILURE_LEVEL : AUTH_SUCCESS_LEVEL;
@@ -62,6 +99,7 @@ void log_authentication_event(const struct auth_usersupplied_info *ui,
 
 	frame = talloc_stackframe();
 
+	password_type = get_password_type( ui);
 	/* Get the current time */
         ts = http_timestring(frame, time(NULL));
 
@@ -98,7 +136,7 @@ void log_authentication_event(const struct auth_usersupplied_info *ui,
 
 	DEBUGC( DBGC_AUTH_AUDIT, level, (
 		"Auth: [%s,%s] user [%s]\\[%s]"
-		" at [%s] status [%s]"
+		" at [%s] with [%s] status [%s]"
 		" workstation [%s] remote host [%s]"
 		"%s local host [%s]"
 		" %s\n",
@@ -107,6 +145,7 @@ void log_authentication_event(const struct auth_usersupplied_info *ui,
 		log_escape(frame, ui->client.domain_name),
 		log_escape(frame, ui->client.account_name),
 		ts,
+		password_type,
 		nt_errstr( status),
 		log_escape(frame, ui->workstation_name),
 		remote,
-- 
2.7.4


From ad485585efe139669697072f87cb53547b8d4450 Mon Sep 17 00:00:00 2001
From: Andrew Bartlett <abartlet at samba.org>
Date: Wed, 1 Mar 2017 16:00:03 +1300
Subject: [PATCH 30/43] auth_log: Also log the final type of authentication
 (ntlmssp,krb5)

Administrators really care about how their users were authenticated, so make
this clear.

Signed-off-by: Andrew Bartlett <abartlet at samba.org>
Pair-Programmed: Gary Lockyer <gary at catalyst.net.nz>
---
 auth/auth_log.c                     |  4 +++-
 auth/common_auth.h                  |  1 +
 auth/gensec/gensec.c                | 16 +++++++++++++++-
 auth/gensec/gensec.h                |  2 ++
 auth/gensec/gensec_internal.h       |  3 +++
 auth/gensec/spnego.c                | 12 ++++++++++++
 auth/ntlmssp/ntlmssp_server.c       |  9 ++++++++-
 source3/librpc/crypto/gse.c         | 16 ++++++++++++++++
 source4/auth/gensec/gensec_gssapi.c | 16 ++++++++++++++++
 source4/auth/gensec/gensec_krb5.c   |  9 ++++++++-
 10 files changed, 84 insertions(+), 4 deletions(-)

diff --git a/auth/auth_log.c b/auth/auth_log.c
index 3ec8dc8..5a0d868 100644
--- a/auth/auth_log.c
+++ b/auth/auth_log.c
@@ -171,6 +171,7 @@ void log_authentication_event(const struct auth_usersupplied_info *ui,
 void log_successful_authz_event(const struct tsocket_address *remote,
 				const struct tsocket_address *local,
 				const char *service_description,
+				const char *auth_type,
 				struct auth_session_info *session_info)
 {
 	TALLOC_CTX *frame = NULL;
@@ -196,11 +197,12 @@ void log_successful_authz_event(const struct tsocket_address *remote,
 	dom_sid_string_buf(&session_info->security_token->sids[0], sid_buf, sizeof(sid_buf));
 
 	DEBUGC( DBGC_AUTH_AUDIT, AUTHZ_SUCCESS_LEVEL, (
-		"Successful AuthZ: [%s] user [%s]\\[%s] [%s]"
+		"Successful AuthZ: [%s,%s] user [%s]\\[%s] [%s]"
 		" at [%s]"
 		" Remote host [%s]"
 		" local host [%s]\n",
 		service_description,
+		auth_type,
 		log_escape(frame, session_info->info->domain_name),
 		log_escape(frame, session_info->info->account_name),
 		sid_buf,
diff --git a/auth/common_auth.h b/auth/common_auth.h
index 67fc6bc..999d05c 100644
--- a/auth/common_auth.h
+++ b/auth/common_auth.h
@@ -156,5 +156,6 @@ void log_authentication_event(const struct auth_usersupplied_info *ui,
 void log_successful_authz_event(const struct tsocket_address *remote,
 				const struct tsocket_address *local,
 				const char *service_description,
+				const char *auth_type,
 				struct auth_session_info *session_info);
 #endif
diff --git a/auth/gensec/gensec.c b/auth/gensec/gensec.c
index d97d3b4..d275976 100644
--- a/auth/gensec/gensec.c
+++ b/auth/gensec/gensec.c
@@ -193,6 +193,15 @@ _PUBLIC_ NTSTATUS gensec_session_key(struct gensec_security *gensec_security,
 	return gensec_security->ops->session_key(gensec_security, mem_ctx, session_key);
 }
 
+const char *gensec_final_auth_type(struct gensec_security *gensec_security)
+{
+	if (!gensec_security->ops->final_auth_type) {
+		return gensec_security->ops->name;
+	}
+
+	return gensec_security->ops->final_auth_type(gensec_security);
+}
+
 /*
  * Log details of a successful GENSEC authorization to a service.
  *
@@ -210,7 +219,12 @@ static void log_successful_gensec_authz_event(struct gensec_security *gensec_sec
 		= gensec_get_local_address(gensec_security);
 	const char *service_description
 		= gensec_get_target_service_description(gensec_security);
-	log_successful_authz_event(remote, local, service_description, session_info);
+	const char *final_auth_type
+		= gensec_final_auth_type(gensec_security);
+	log_successful_authz_event(remote, local,
+				   service_description,
+				   final_auth_type,
+				   session_info);
 }
 
 
diff --git a/auth/gensec/gensec.h b/auth/gensec/gensec.h
index 7bd8932..e9fab5f 100644
--- a/auth/gensec/gensec.h
+++ b/auth/gensec/gensec.h
@@ -34,6 +34,8 @@
 #define GENSEC_OID_KERBEROS5_OLD "1.2.840.48018.1.2.2"
 #define GENSEC_OID_KERBEROS5_USER2USER "1.2.840.113554.1.2.2.3"
 
+#define GENSEC_FINAL_AUTH_TYPE_KRB5 "krb5"
+
 enum gensec_priority {
 	GENSEC_SPNEGO = 90,
 	GENSEC_GSSAPI = 80,
diff --git a/auth/gensec/gensec_internal.h b/auth/gensec/gensec_internal.h
index 5535241..26c9817 100644
--- a/auth/gensec/gensec_internal.h
+++ b/auth/gensec/gensec_internal.h
@@ -85,6 +85,7 @@ struct gensec_security_ops {
 	bool (*have_feature)(struct gensec_security *gensec_security,
 				    uint32_t feature);
 	NTTIME (*expire_time)(struct gensec_security *gensec_security);
+	const char *(*final_auth_type)(struct gensec_security *gensec_security);
 	bool enabled;
 	bool kerberos;
 	enum gensec_priority priority;
@@ -126,4 +127,6 @@ struct gensec_critical_sizes {
 NTSTATUS gensec_may_reset_crypto(struct gensec_security *gensec_security,
 				 bool full_reset);
 
+const char *gensec_final_auth_type(struct gensec_security *gensec_security);
+
 #endif /* __GENSEC_H__ */
diff --git a/auth/gensec/spnego.c b/auth/gensec/spnego.c
index f063f7b..017181a 100644
--- a/auth/gensec/spnego.c
+++ b/auth/gensec/spnego.c
@@ -1651,6 +1651,17 @@ static NTTIME gensec_spnego_expire_time(struct gensec_security *gensec_security)
 	return gensec_expire_time(spnego_state->sub_sec_security);
 }
 
+static const char *gensec_spnego_final_auth_type(struct gensec_security *gensec_security)
+{
+	struct spnego_state *spnego_state = (struct spnego_state *)gensec_security->private_data;
+
+	if (!spnego_state->sub_sec_security) {
+		return "NONE";
+	} else {
+		return gensec_final_auth_type(spnego_state->sub_sec_security);
+	}
+}
+
 static const char *gensec_spnego_oids[] = { 
 	GENSEC_OID_SPNEGO,
 	NULL 
@@ -1678,6 +1689,7 @@ static const struct gensec_security_ops gensec_spnego_security_ops = {
 	.want_feature     = gensec_spnego_want_feature,
 	.have_feature     = gensec_spnego_have_feature,
 	.expire_time      = gensec_spnego_expire_time,
+	.final_auth_type  = gensec_spnego_final_auth_type,
 	.enabled          = true,
 	.priority         = GENSEC_SPNEGO
 };
diff --git a/auth/ntlmssp/ntlmssp_server.c b/auth/ntlmssp/ntlmssp_server.c
index 85d204b..8d3b556 100644
--- a/auth/ntlmssp/ntlmssp_server.c
+++ b/auth/ntlmssp/ntlmssp_server.c
@@ -721,7 +721,14 @@ static NTSTATUS ntlmssp_server_check_password(struct gensec_security *gensec_sec
 	user_info->local_host = gensec_get_local_address(gensec_security);
 	user_info->service_description
 		= gensec_get_target_service_description(gensec_security);
-	user_info->auth_description = "NTLMSSP";
+
+	/*
+	 * This will just be the string "ntlmssp" from
+	 * gensec_ntlmssp_security_ops, but ensures it stays in sync
+	 * with the same use in the authorization logging triggered by
+	 * gensec_session_info() later
+	 */
+	user_info->auth_description = gensec_final_auth_type(gensec_security);
 
 	user_info->password_state = AUTH_PASSWORD_RESPONSE;
 	user_info->password.response.lanman = ntlmssp_state->lm_resp;
diff --git a/source3/librpc/crypto/gse.c b/source3/librpc/crypto/gse.c
index 1d9e8dc..476447c 100644
--- a/source3/librpc/crypto/gse.c
+++ b/source3/librpc/crypto/gse.c
@@ -1274,6 +1274,21 @@ static size_t gensec_gse_sig_size(struct gensec_security *gensec_security,
 	return gse_ctx->sig_size;
 }
 
+static const char *gensec_gse_final_auth_type(struct gensec_security *gensec_security)
+{
+	struct gse_context *gse_ctx =
+		talloc_get_type_abort(gensec_security->private_data,
+		struct gse_context);
+
+	/* Only return the string for GSSAPI/Krb5 */
+	if (smb_gss_oid_equal(&gse_ctx->gss_mech,
+			      gss_mech_krb5)) {
+		return GENSEC_FINAL_AUTH_TYPE_KRB5;
+	} else {
+		return "gensec_gse: UNKNOWN MECH";
+	}
+}
+
 static const char *gensec_gse_krb5_oids[] = {
 	GENSEC_OID_KERBEROS5_OLD,
 	GENSEC_OID_KERBEROS5,
@@ -1301,6 +1316,7 @@ const struct gensec_security_ops gensec_gse_krb5_security_ops = {
 	.unwrap         = gensec_gse_unwrap,
 	.have_feature   = gensec_gse_have_feature,
 	.expire_time    = gensec_gse_expire_time,
+	.final_auth_type  = gensec_gse_final_auth_type,
 	.enabled        = true,
 	.kerberos       = true,
 	.priority       = GENSEC_GSSAPI
diff --git a/source4/auth/gensec/gensec_gssapi.c b/source4/auth/gensec/gensec_gssapi.c
index cfe2ea8..e2755b3 100644
--- a/source4/auth/gensec/gensec_gssapi.c
+++ b/source4/auth/gensec/gensec_gssapi.c
@@ -1539,6 +1539,19 @@ static size_t gensec_gssapi_sig_size(struct gensec_security *gensec_security, si
 	return gensec_gssapi_state->sig_size;
 }
 
+static const char *gensec_gssapi_final_auth_type(struct gensec_security *gensec_security)
+{
+	struct gensec_gssapi_state *gensec_gssapi_state
+		= talloc_get_type(gensec_security->private_data, struct gensec_gssapi_state);
+	/* Only return the string for GSSAPI/Krb5 */
+	if (smb_gss_oid_equal(gensec_gssapi_state->gss_oid,
+			      gss_mech_krb5)) {
+		return GENSEC_FINAL_AUTH_TYPE_KRB5;
+	} else {
+		return "gensec_gssapi: UNKNOWN MECH";
+	}
+}
+
 static const char *gensec_gssapi_krb5_oids[] = { 
 	GENSEC_OID_KERBEROS5_OLD,
 	GENSEC_OID_KERBEROS5,
@@ -1572,6 +1585,7 @@ static const struct gensec_security_ops gensec_gssapi_spnego_security_ops = {
 	.unwrap         = gensec_gssapi_unwrap,
 	.have_feature   = gensec_gssapi_have_feature,
 	.expire_time    = gensec_gssapi_expire_time,
+	.final_auth_type = gensec_gssapi_final_auth_type,
 	.enabled        = false,
 	.kerberos       = true,
 	.priority       = GENSEC_GSSAPI
@@ -1599,6 +1613,7 @@ static const struct gensec_security_ops gensec_gssapi_krb5_security_ops = {
 	.unwrap         = gensec_gssapi_unwrap,
 	.have_feature   = gensec_gssapi_have_feature,
 	.expire_time    = gensec_gssapi_expire_time,
+	.final_auth_type = gensec_gssapi_final_auth_type,
 	.enabled        = true,
 	.kerberos       = true,
 	.priority       = GENSEC_GSSAPI
@@ -1619,6 +1634,7 @@ static const struct gensec_security_ops gensec_gssapi_sasl_krb5_security_ops = {
 	.unwrap           = gensec_gssapi_unwrap,
 	.have_feature     = gensec_gssapi_have_feature,
 	.expire_time      = gensec_gssapi_expire_time,
+	.final_auth_type = gensec_gssapi_final_auth_type,
 	.enabled          = true,
 	.kerberos         = true,
 	.priority         = GENSEC_GSSAPI
diff --git a/source4/auth/gensec/gensec_krb5.c b/source4/auth/gensec/gensec_krb5.c
index b54a41b..4946929 100644
--- a/source4/auth/gensec/gensec_krb5.c
+++ b/source4/auth/gensec/gensec_krb5.c
@@ -1038,6 +1038,11 @@ static bool gensec_krb5_have_feature(struct gensec_security *gensec_security,
 	return false;
 }
 
+static const char *gensec_krb5_final_auth_type(struct gensec_security *gensec_security)
+{
+	return GENSEC_FINAL_AUTH_TYPE_KRB5;
+}
+
 static const char *gensec_krb5_oids[] = { 
 	GENSEC_OID_KERBEROS5,
 	GENSEC_OID_KERBEROS5_OLD,
@@ -1055,9 +1060,10 @@ static const struct gensec_security_ops gensec_fake_gssapi_krb5_security_ops = {
 	.session_key	= gensec_krb5_session_key,
 	.session_info	= gensec_krb5_session_info,
 	.have_feature   = gensec_krb5_have_feature,
+	.final_auth_type = gensec_krb5_final_auth_type,
 	.enabled        = false,
 	.kerberos       = true,
-	.priority       = GENSEC_KRB5
+	.priority       = GENSEC_KRB5,
 };
 
 static const struct gensec_security_ops gensec_krb5_security_ops = {
@@ -1070,6 +1076,7 @@ static const struct gensec_security_ops gensec_krb5_security_ops = {
 	.have_feature   = gensec_krb5_have_feature,
 	.wrap           = gensec_krb5_wrap,
 	.unwrap         = gensec_krb5_unwrap,
+	.final_auth_type = gensec_krb5_final_auth_type,
 	.enabled        = true,
 	.kerberos       = true,
 	.priority       = GENSEC_KRB5
-- 
2.7.4


From 4c892e36deee82d0468687f22e9dd1798919d776 Mon Sep 17 00:00:00 2001
From: Andrew Bartlett <abartlet at samba.org>
Date: Wed, 1 Mar 2017 16:27:51 +1300
Subject: [PATCH 31/43] s3-auth: Log SMB authorization for bare NTLM
 (NTLMSSP/krb5 already done)

gensec_session_info() is not called for bare NTLM, so we have to log manually

Signed-off-by: Andrew Bartlett <abartlet at samba.org>
Pair-Programmed: Gary Lockyer <gary at catalyst.net.nz>
---
 source3/auth/auth_generic.c | 17 +++++++++++++++++
 1 file changed, 17 insertions(+)

diff --git a/source3/auth/auth_generic.c b/source3/auth/auth_generic.c
index 05f3019..4033996 100644
--- a/source3/auth/auth_generic.c
+++ b/source3/auth/auth_generic.c
@@ -399,6 +399,11 @@ NTSTATUS auth_generic_prepare(TALLOC_CTX *mem_ctx,
 	return NT_STATUS_OK;
 }
 
+/*
+ * Check a username and password, and return the final session_info.
+ * We also log the authorization of the session here, just as
+ * gensec_session_info() does.
+ */
 NTSTATUS auth_check_password_session_info(struct auth4_context *auth_context,
 					  TALLOC_CTX *mem_ctx,
 					  struct auth_usersupplied_info *user_info,
@@ -422,5 +427,17 @@ NTSTATUS auth_check_password_session_info(struct auth4_context *auth_context,
 								session_info);
 		TALLOC_FREE(server_info);
 	}
+
+	/*
+	 * This is rather redundant, but because we want to log all
+	 * authorizations consistently (be they NLTM, NTLMSSP or
+	 * krb5) we log this info again.
+	 */
+	log_successful_authz_event(user_info->remote_host,
+				   user_info->local_host,
+				   user_info->service_description,
+				   user_info->auth_description,
+				   *session_info);
+
 	return nt_status;
 }
-- 
2.7.4


From c1e5891122171ed88c4d88b592729a962d2206d0 Mon Sep 17 00:00:00 2001
From: Andrew Bartlett <abartlet at samba.org>
Date: Wed, 1 Mar 2017 16:28:06 +1300
Subject: [PATCH 32/43] s4-auth: Log SMB authorization for bare NTLM
 (NTLMSSP/krb5 already done)

gensec_session_info() is not called for bare NTLM, so we have to log manually

Signed-off-by: Andrew Bartlett <abartlet at samba.org>
Pair-Programmed: Gary Lockyer <gary at catalyst.net.nz>
---
 source4/smb_server/smb/sesssetup.c | 32 ++++++++++++++++++++++++++++++++
 1 file changed, 32 insertions(+)

diff --git a/source4/smb_server/smb/sesssetup.c b/source4/smb_server/smb/sesssetup.c
index 3541926..ebe310a 100644
--- a/source4/smb_server/smb/sesssetup.c
+++ b/source4/smb_server/smb/sesssetup.c
@@ -39,6 +39,33 @@ struct sesssetup_context {
 };
 
 /*
+ * Log the SMB authentication, as by not calling GENSEC we won't log
+ * it during the gensec_session_info().
+ */
+void smbsrv_not_spengo_sesssetup_authz_log(struct smbsrv_request *req,
+					       struct auth_session_info *session_info)
+{
+	struct tsocket_address *local_address;
+	struct tsocket_address *remote_address;
+	TALLOC_CTX *frame = talloc_stackframe();
+
+	remote_address = socket_get_remote_addr(req->smb_conn->connection->socket,
+						frame);
+	local_address = socket_get_local_addr(req->smb_conn->connection->socket,
+					      frame);
+
+	log_successful_authz_event(remote_address,
+				   local_address,
+				   "SMB",
+				   "bare-NTLM",
+				   session_info);
+
+	talloc_free(frame);
+	return;
+}
+
+
+/*
   setup the OS, Lanman and domain portions of a session setup reply
 */
 static void sesssetup_common_strings(struct smbsrv_request *req,
@@ -96,6 +123,8 @@ static void sesssetup_old_send(struct tevent_req *subreq)
 		goto failed;
 	}
 
+	smbsrv_not_spengo_sesssetup_authz_log(req, session_info);
+
 	/* Ensure this is marked as a 'real' vuid, not one
 	 * simply valid for the session setup leg */
 	status = smbsrv_session_sesssetup_finished(smb_sess, session_info);
@@ -237,6 +266,8 @@ static void sesssetup_nt1_send(struct tevent_req *subreq)
 		goto failed;
 	}
 
+	smbsrv_not_spengo_sesssetup_authz_log(req, session_info);
+
 	/* Ensure this is marked as a 'real' vuid, not one
 	 * simply valid for the session setup leg */
 	status = smbsrv_session_sesssetup_finished(smb_sess, session_info);
@@ -336,6 +367,7 @@ static void sesssetup_nt1(struct smbsrv_request *req, union smb_sesssetup *sess)
 	if (!user_info) goto nomem;
 
 	user_info->service_description = "smb";
+	user_info->auth_description = "bare-NTLM";
 
 	user_info->mapped_state = false;
 	user_info->logon_parameters = 0;
-- 
2.7.4


From c31ed6c09a8e62d2c6fd2d2c9a3ecadd3f239c2e Mon Sep 17 00:00:00 2001
From: Andrew Bartlett <abartlet at samba.org>
Date: Wed, 1 Mar 2017 16:49:01 +1300
Subject: [PATCH 33/43] ldap_server: Log authorization for simple binds

Signed-off-by: Andrew Bartlett <abartlet at samba.org>
Pair-Programmed: Gary Lockyer <gary at catalyst.net.nz>
---
 source4/auth/ntlm/auth_simple.c | 37 +++++++++++++++++++++----------------
 source4/ldap_server/ldap_bind.c |  6 ++++++
 2 files changed, 27 insertions(+), 16 deletions(-)

diff --git a/source4/auth/ntlm/auth_simple.c b/source4/auth/ntlm/auth_simple.c
index 7f077a5..a14883d 100644
--- a/source4/auth/ntlm/auth_simple.c
+++ b/source4/auth/ntlm/auth_simple.c
@@ -46,6 +46,7 @@ _PUBLIC_ NTSTATUS authenticate_ldap_simple_bind(TALLOC_CTX *mem_ctx,
 	TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
 	const char *nt4_domain;
 	const char *nt4_username;
+	uint32_t flags = 0;
 
 	if (!tmp_ctx) {
 		return NT_STATUS_NO_MEMORY;
@@ -84,7 +85,7 @@ _PUBLIC_ NTSTATUS authenticate_ldap_simple_bind(TALLOC_CTX *mem_ctx,
 	user_info->remote_host = remote_address;
 	user_info->local_host = local_address;
 
-	user_info->service_description = "ldap";
+	user_info->service_description = "LDAP";
 
 	user_info->auth_description = "simple bind";
 
@@ -106,22 +107,26 @@ _PUBLIC_ NTSTATUS authenticate_ldap_simple_bind(TALLOC_CTX *mem_ctx,
 		return nt_status;
 	}
 
-	if (session_info) {
-		uint32_t flags = AUTH_SESSION_INFO_DEFAULT_GROUPS;
-		if (user_info_dc->info->authenticated) {
-			flags |= AUTH_SESSION_INFO_AUTHENTICATED;
-		}
-		nt_status = auth_context->generate_session_info(auth_context,
-								tmp_ctx, 
-								user_info_dc,
-								nt4_username,
-								flags,
-								session_info);
-
-		if (NT_STATUS_IS_OK(nt_status)) {
-			talloc_steal(mem_ctx, *session_info);
-		}
+	flags = AUTH_SESSION_INFO_DEFAULT_GROUPS;
+	if (user_info_dc->info->authenticated) {
+		flags |= AUTH_SESSION_INFO_AUTHENTICATED;
 	}
+	nt_status = auth_context->generate_session_info(auth_context,
+							tmp_ctx,
+							user_info_dc,
+							nt4_username,
+							flags,
+							session_info);
+
+	if (NT_STATUS_IS_OK(nt_status)) {
+		talloc_steal(mem_ctx, *session_info);
+	}
+
+	log_successful_authz_event(remote_address,
+				   local_address,
+				   "LDAP",
+				   "simple bind",
+				   *session_info);
 
 	talloc_free(tmp_ctx);
 	return nt_status;
diff --git a/source4/ldap_server/ldap_bind.c b/source4/ldap_server/ldap_bind.c
index f517657..e70545f 100644
--- a/source4/ldap_server/ldap_bind.c
+++ b/source4/ldap_server/ldap_bind.c
@@ -195,6 +195,12 @@ static NTSTATUS ldapsrv_setup_gensec(struct ldapsrv_connection *conn,
 		return status;
 	}
 
+	status = gensec_set_target_service_description(gensec_security,
+						       "LDAP");
+	if (!NT_STATUS_IS_OK(status)) {
+		return status;
+	}
+
 	status = gensec_set_remote_address(gensec_security,
 					   conn->connection->remote_address);
 	if (!NT_STATUS_IS_OK(status)) {
-- 
2.7.4


From 27d274fc2c520f6053c85a3a7d05a0ed3fb0dac4 Mon Sep 17 00:00:00 2001
From: Andrew Bartlett <abartlet at samba.org>
Date: Fri, 3 Mar 2017 11:49:43 +1300
Subject: [PATCH 34/43] s4-rpc_server: Log authorization to DCE/RPC for
 anonymous and ncacn_np pass-though

Signed-off-by: Andrew Bartlett <abartlet at samba.org>
Pair-Programmed: Gary Lockyer <gary at catalyst.net.nz>
---
 source4/rpc_server/dcesrv_auth.c | 15 +++++++++++++++
 1 file changed, 15 insertions(+)

diff --git a/source4/rpc_server/dcesrv_auth.c b/source4/rpc_server/dcesrv_auth.c
index ece314d..4b0bfdf 100644
--- a/source4/rpc_server/dcesrv_auth.c
+++ b/source4/rpc_server/dcesrv_auth.c
@@ -46,9 +46,24 @@ bool dcesrv_auth_bind(struct dcesrv_call_state *call)
 	NTSTATUS status;
 
 	if (pkt->auth_length == 0) {
+		enum dcerpc_transport_t transport =
+			dcerpc_binding_get_transport(call->conn->endpoint->ep_description);
+		const char *auth_type = derpc_transport_string_by_transport(transport);
 		auth->auth_type = DCERPC_AUTH_TYPE_NONE;
 		auth->auth_level = DCERPC_AUTH_LEVEL_NONE;
 		auth->auth_context_id = 0;
+
+		/*
+		 * Log the authorization to this RPC interface.  This
+		 * covered ncacn_np pass-through auth, and anonymous
+		 * DCE/RPC (eg epmapper, netlogon etc)
+		 */
+		log_successful_authz_event(call->conn->remote_address,
+					   call->conn->local_address,
+					   "DCE/RPC",
+					   auth_type,
+					   call->conn->auth_state.session_info);
+
 		return true;
 	}
 
-- 
2.7.4


From 594f39b3fe9372bf56a2915a761f6c51d1e3c68d Mon Sep 17 00:00:00 2001
From: Andrew Bartlett <abartlet at samba.org>
Date: Fri, 3 Mar 2017 12:03:04 +1300
Subject: [PATCH 35/43] s3-rpc_server: Log authorization to DCE/RPC for
 anonymous and ncacn_np pass-though

Signed-off-by: Andrew Bartlett <abartlet at samba.org>
Pair-Programmed: Gary Lockyer <gary at catalyst.net.nz>
---
 source3/rpc_server/srv_pipe.c | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/source3/rpc_server/srv_pipe.c b/source3/rpc_server/srv_pipe.c
index 446679f..bd56be6 100644
--- a/source3/rpc_server/srv_pipe.c
+++ b/source3/rpc_server/srv_pipe.c
@@ -825,6 +825,17 @@ static bool api_pipe_bind_req(struct pipes_struct *p,
 		p->auth.auth_type = DCERPC_AUTH_TYPE_NONE;
 		p->auth.auth_level = DCERPC_AUTH_LEVEL_NONE;
 		p->auth.auth_context_id = 0;
+
+		/*
+		 * Log the authorization to this RPC interface.  This
+		 * covered ncacn_np pass-through auth, and anonymous
+		 * DCE/RPC (eg epmapper, netlogon etc)
+		 */
+		log_successful_authz_event(p->remote_address,
+					   p->local_address,
+					   table->name,
+					   derpc_transport_string_by_transport(p->transport),
+					   p->session_info);
 	}
 
 	ZERO_STRUCT(u.bind_ack);
-- 
2.7.4


From e6811a0c28dcddda782dcf7c67c5fa335407f845 Mon Sep 17 00:00:00 2001
From: Andrew Bartlett <abartlet at samba.org>
Date: Fri, 3 Mar 2017 12:40:04 +1300
Subject: [PATCH 36/43] auth_log: Split up auth/authz logging levels and handle
 anonymous better

We typically do not want a lot of logging of anonymous access, as this is often
simple a preperation for authenticated access, so we make that level 5.

Bad passwords remain at level 2, successful password authentication is level 3
and successful authorization (eg kerberos login to SMB) is level 4.

Signed-off-by: Andrew Bartlett <abartlet at samba.org>
Pair-Programmed: Gary Lockyer <gary at catalyst.net.nz>
---
 auth/auth_log.c | 30 ++++++++++++++++++++++++------
 1 file changed, 24 insertions(+), 6 deletions(-)

diff --git a/auth/auth_log.c b/auth/auth_log.c
index 5a0d868..f390ced 100644
--- a/auth/auth_log.c
+++ b/auth/auth_log.c
@@ -22,15 +22,20 @@
  * Debug log levels for authentication logging (these both map to
  * LOG_NOTICE in syslog)
  */
-#define AUTH_SUCCESS_LEVEL 4
-#define AUTHZ_SUCCESS_LEVEL 5
 #define AUTH_FAILURE_LEVEL 2
+#define AUTH_SUCCESS_LEVEL 3
+#define AUTHZ_SUCCESS_LEVEL 4
+
+/* 5 is used for both authentication and authorization */
+#define AUTH_ANONYMOUS_LEVEL 5
+#define AUTHZ_ANONYMOUS_LEVEL 5
 
 #include "includes.h"
 #include "../lib/tsocket/tsocket.h"
 #include "common_auth.h"
 #include "lib/util/util_str_escape.h"
 #include "libcli/security/dom_sid.h"
+#include "libcli/security/security_token.h"
 
 /*
  * Determine the type of the password supplied for the
@@ -92,8 +97,16 @@ void log_authentication_event(const struct auth_usersupplied_info *ui,
 	const char *password_type = NULL;
 
 	/* set the log level */
-	int  level = NT_STATUS_IS_OK(status) ? AUTH_FAILURE_LEVEL : AUTH_SUCCESS_LEVEL;
-	if (!CHECK_DEBUGLVLC( DBGC_AUTH_AUDIT, level)) {
+	int debug_level = AUTH_FAILURE_LEVEL;
+
+	if (NT_STATUS_IS_OK(status)) {
+		debug_level = AUTH_SUCCESS_LEVEL;
+		if (dom_sid_equal(sid, &global_sid_Anonymous)) {
+			debug_level = AUTH_ANONYMOUS_LEVEL;
+		}
+	}
+
+	if (!CHECK_DEBUGLVLC( DBGC_AUTH_AUDIT, debug_level)) {
 		return;
 	}
 
@@ -134,7 +147,7 @@ void log_authentication_event(const struct auth_usersupplied_info *ui,
 					     log_escape(frame, ui->mapped.account_name));
 	}
 
-	DEBUGC( DBGC_AUTH_AUDIT, level, (
+	DEBUGC( DBGC_AUTH_AUDIT, debug_level, (
 		"Auth: [%s,%s] user [%s]\\[%s]"
 		" at [%s] with [%s] status [%s]"
 		" workstation [%s] remote host [%s]"
@@ -180,9 +193,14 @@ void log_successful_authz_event(const struct tsocket_address *remote,
 	char *remote_str = NULL;     /* formatted remote host       */
 	char *local_str = NULL;      /* formatted local host        */
 	char sid_buf[DOM_SID_STR_BUFLEN];
+	int debug_level = AUTHZ_SUCCESS_LEVEL;
+
+	if (security_token_is_anonymous(session_info->security_token)) {
+		debug_level = AUTH_ANONYMOUS_LEVEL;
+	}
 
 	/* set the log level */
-	if (!CHECK_DEBUGLVLC( DBGC_AUTH_AUDIT, AUTHZ_SUCCESS_LEVEL)) {
+	if (!CHECK_DEBUGLVLC( DBGC_AUTH_AUDIT, debug_level)) {
 		return;
 	}
 
-- 
2.7.4


From efdee3b4b042e55b887e832810a9ba6ea290ae62 Mon Sep 17 00:00:00 2001
From: Andrew Bartlett <abartlet at samba.org>
Date: Fri, 3 Mar 2017 12:53:06 +1300
Subject: [PATCH 37/43] ldap_server: Log access without a bind

This can be over the privileged ldapi socket, or just as the implicit anonymous access

However, do not log for setting up StartTLS, or a rootDSE search.

Signed-off-by: Andrew Bartlett <abartlet at samba.org>
Pair-Programmed: Gary Lockyer <gary at catalyst.net.nz>
---
 source4/ldap_server/ldap_backend.c | 52 ++++++++++++++++++++++++++++++++++++++
 source4/ldap_server/ldap_bind.c    |  6 ++++-
 source4/ldap_server/ldap_server.h  |  1 +
 source4/ldap_server/wscript_build  |  2 +-
 4 files changed, 59 insertions(+), 2 deletions(-)

diff --git a/source4/ldap_server/ldap_backend.c b/source4/ldap_server/ldap_backend.c
index dc6a44c..b023eb4 100644
--- a/source4/ldap_server/ldap_backend.c
+++ b/source4/ldap_server/ldap_backend.c
@@ -24,6 +24,7 @@
 #include "auth/credentials/credentials.h"
 #include "auth/gensec/gensec.h"
 #include "auth/gensec/gensec_internal.h" /* TODO: remove this */
+#include "auth/common_auth.h"
 #include "param/param.h"
 #include "smbd/service_stream.h"
 #include "dsdb/samdb/samdb.h"
@@ -1227,6 +1228,7 @@ NTSTATUS ldapsrv_do_call(struct ldapsrv_call *call)
 	unsigned int i;
 	struct ldap_message *msg = call->request;
 	NTSTATUS status;
+	bool log = true;
 
 	/* Check for undecoded critical extensions */
 	for (i=0; msg->controls && msg->controls[i]; i++) {
@@ -1238,6 +1240,56 @@ NTSTATUS ldapsrv_do_call(struct ldapsrv_call *call)
 		}
 	}
 
+	if (call->conn->authz_logged == false) {
+
+		/*
+		 * We do not want to log anonymous access if the query
+		 * is just for the rootDSE, or it is a startTLS or a
+		 * Bind.
+		 *
+		 * A rootDSE search could also be done over
+		 * CLDAP anonymously for example, so these don't
+		 * really count.
+		 * Essentially we want to know about
+		 * access beyond that normally done prior to a
+		 * bind.
+		 */
+
+		switch(call->request->type) {
+		case LDAP_TAG_BindRequest:
+			log = false;
+			break;
+		case LDAP_TAG_ExtendedResponse: {
+			struct ldap_ExtendedRequest *req = &call->request->r.ExtendedRequest;
+			if (strcmp(req->oid, LDB_EXTENDED_START_TLS_OID) == 0) {
+				log = false;
+			}
+			break;
+		}
+		case LDAP_TAG_SearchRequest: {
+			struct ldap_SearchRequest *req = &call->request->r.SearchRequest;
+			if (req->scope == LDAP_SEARCH_SCOPE_BASE) {
+				if (req->basedn[0] == '\0') {
+					log = false;
+				}
+			}
+			break;
+		}
+		default:
+			break;
+		}
+
+		if (log) {
+			log_successful_authz_event(call->conn->connection->remote_address,
+						   call->conn->connection->local_address,
+						   "LDAP",
+						   "no bind",
+						   call->conn->session_info);
+
+			call->conn->authz_logged = true;
+		}
+	}
+
 	switch(call->request->type) {
 	case LDAP_TAG_BindRequest:
 		return ldapsrv_BindRequest(call);
diff --git a/source4/ldap_server/ldap_bind.c b/source4/ldap_server/ldap_bind.c
index e70545f..5fc50dc 100644
--- a/source4/ldap_server/ldap_bind.c
+++ b/source4/ldap_server/ldap_bind.c
@@ -109,6 +109,8 @@ static NTSTATUS ldapsrv_BindSimple(struct ldapsrv_call *call)
 		talloc_unlink(call->conn, call->conn->session_info);
 		call->conn->session_info = talloc_steal(call->conn, session_info);
 
+		call->conn->authz_logged = true;
+
 		/* don't leak the old LDB */
 		talloc_unlink(call->conn, call->conn->ldb);
 
@@ -379,7 +381,9 @@ static NTSTATUS ldapsrv_BindSASL(struct ldapsrv_call *call)
 				
 				/* don't leak the old LDB */
 				talloc_unlink(conn, conn->ldb);
-				
+
+				call->conn->authz_logged = true;
+
 				status = ldapsrv_backend_Init(conn);		
 				
 				if (!NT_STATUS_IS_OK(status)) {
diff --git a/source4/ldap_server/ldap_server.h b/source4/ldap_server/ldap_server.h
index 86e5d34..337c974 100644
--- a/source4/ldap_server/ldap_server.h
+++ b/source4/ldap_server/ldap_server.h
@@ -46,6 +46,7 @@ struct ldapsrv_connection {
 	bool global_catalog;
 	bool is_privileged;
 	enum ldap_server_require_strong_auth require_strong_auth;
+	bool authz_logged;
 
 	struct {
 		int initial_timeout;
diff --git a/source4/ldap_server/wscript_build b/source4/ldap_server/wscript_build
index 32a77c7..881cc89 100644
--- a/source4/ldap_server/wscript_build
+++ b/source4/ldap_server/wscript_build
@@ -6,7 +6,7 @@ bld.SAMBA_MODULE('service_ldap',
 	autoproto='proto.h',
 	subsystem='service',
 	init_function='server_service_ldap_init',
-	deps='samba-credentials cli-ldap samdb process_model gensec samba-hostconfig samba_server_gensec',
+	deps='samba-credentials cli-ldap samdb process_model gensec samba-hostconfig samba_server_gensec common_auth',
 	internal_module=False,
 	enabled=bld.AD_DC_BUILD_IS_ENABLED()
 	)
-- 
2.7.4


From d2c9d9e95b77fd5fa7144be87df6b1093b31d591 Mon Sep 17 00:00:00 2001
From: Andrew Bartlett <abartlet at samba.org>
Date: Mon, 6 Mar 2017 11:54:56 +1300
Subject: [PATCH 38/43] gensec: Return upper-case NTLMSSP for NTLMSSP auth

By making this a #define, we can rely on it in other places.

Signed-off-by: Andrew Bartlett <abartlet at samba.org>
Pair-Programmed: Gary Lockyer <gary at catalyst.net.nz>
---
 auth/gensec/gensec.h          | 1 +
 auth/ntlmssp/ntlmssp.c        | 6 ++++++
 auth/ntlmssp/ntlmssp_server.c | 4 ++--
 3 files changed, 9 insertions(+), 2 deletions(-)

diff --git a/auth/gensec/gensec.h b/auth/gensec/gensec.h
index e9fab5f..bc96e69 100644
--- a/auth/gensec/gensec.h
+++ b/auth/gensec/gensec.h
@@ -35,6 +35,7 @@
 #define GENSEC_OID_KERBEROS5_USER2USER "1.2.840.113554.1.2.2.3"
 
 #define GENSEC_FINAL_AUTH_TYPE_KRB5 "krb5"
+#define GENSEC_FINAL_AUTH_TYPE_NTLMSSP "NTLMSSP"
 
 enum gensec_priority {
 	GENSEC_SPNEGO = 90,
diff --git a/auth/ntlmssp/ntlmssp.c b/auth/ntlmssp/ntlmssp.c
index 3283c96..6f7c089 100644
--- a/auth/ntlmssp/ntlmssp.c
+++ b/auth/ntlmssp/ntlmssp.c
@@ -207,6 +207,11 @@ static NTSTATUS gensec_ntlmssp_may_reset_crypto(struct gensec_security *gensec_s
 	return NT_STATUS_OK;
 }
 
+static const char *gensec_ntlmssp_final_auth_type(struct gensec_security *gensec_security)
+{
+	return GENSEC_FINAL_AUTH_TYPE_NTLMSSP;
+}
+
 static const char *gensec_ntlmssp_oids[] = {
 	GENSEC_OID_NTLMSSP,
 	NULL
@@ -232,6 +237,7 @@ static const struct gensec_security_ops gensec_ntlmssp_security_ops = {
 	.session_key	= gensec_ntlmssp_session_key,
 	.session_info   = gensec_ntlmssp_session_info,
 	.have_feature   = gensec_ntlmssp_have_feature,
+	.final_auth_type = gensec_ntlmssp_final_auth_type,
 	.enabled        = true,
 	.priority       = GENSEC_NTLMSSP
 };
diff --git a/auth/ntlmssp/ntlmssp_server.c b/auth/ntlmssp/ntlmssp_server.c
index 8d3b556..38c38d4 100644
--- a/auth/ntlmssp/ntlmssp_server.c
+++ b/auth/ntlmssp/ntlmssp_server.c
@@ -723,8 +723,8 @@ static NTSTATUS ntlmssp_server_check_password(struct gensec_security *gensec_sec
 		= gensec_get_target_service_description(gensec_security);
 
 	/*
-	 * This will just be the string "ntlmssp" from
-	 * gensec_ntlmssp_security_ops, but ensures it stays in sync
+	 * This will just be the string "NTLMSSP" from
+	 * gensec_ntlmssp_final_auth_type, but ensures it stays in sync
 	 * with the same use in the authorization logging triggered by
 	 * gensec_session_info() later
 	 */
-- 
2.7.4


From fb65de05509fb67b0dab4193ff1adc51ae08c1a8 Mon Sep 17 00:00:00 2001
From: Andrew Bartlett <abartlet at samba.org>
Date: Mon, 6 Mar 2017 12:13:47 +1300
Subject: [PATCH 39/43] auth: Log SMB and SMB2 in upper-case, these are
 acronyms and should be logged this way

Signed-off-by: Andrew Bartlett <abartlet at samba.org>
Pair-Programmed: Gary Lockyer <gary at catalyst.net.nz>
---
 source3/smbd/sesssetup.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/source3/smbd/sesssetup.c b/source3/smbd/sesssetup.c
index a570849..0cc49d9 100644
--- a/source3/smbd/sesssetup.c
+++ b/source3/smbd/sesssetup.c
@@ -99,7 +99,7 @@ static NTSTATUS check_guest_password(const struct tsocket_address *remote_addres
 					 chal);
 
 	if (!make_user_info_guest(talloc_tos(), remote_address, local_address,
-				  "smb", &user_info)) {
+				  "SMB", &user_info)) {
 		TALLOC_FREE(auth_context);
 		return NT_STATUS_NO_MEMORY;
 	}
@@ -905,7 +905,7 @@ void reply_sesssetup_and_X(struct smb_request *req)
 							 domain,
 							 sconn->remote_address,
 							 sconn->local_address,
-							 "smb",
+							 "SMB",
 							 lm_resp, nt_resp);
 		user_info->auth_description = "bare-NTLM";
 
@@ -930,7 +930,7 @@ void reply_sesssetup_and_X(struct smb_request *req)
 						      user, domain,
 						      sconn->remote_address,
 						      sconn->local_address,
-						      "smb",
+						      "SMB",
 						      chal,
 						      plaintext_password)) {
 				nt_status = NT_STATUS_NO_MEMORY;
-- 
2.7.4


From 99d43c60064eb8fe1f1373f00672d99d8cc9b62a Mon Sep 17 00:00:00 2001
From: Andrew Bartlett <abartlet at samba.org>
Date: Mon, 6 Mar 2017 14:10:17 +1300
Subject: [PATCH 40/43] auth: Log the transport connection for the
 authorization

We also log if a simple bind was over TLS, as this particular case matters to a lot of folks

Signed-off-by: Andrew Bartlett <abartlet at samba.org>
Pair-Programmed: Gary Lockyer <gary at catalyst.net.nz>
---
 auth/auth_log.c                     |  1 +
 auth/common_auth.h                  |  7 +++++++
 auth/gensec/gensec.c                | 13 +++++++++++++
 auth/gensec/gensec.h                |  2 ++
 source3/auth/auth_generic.c         |  1 +
 source3/rpc_server/srv_pipe.c       |  6 ++++++
 source3/smbd/sesssetup.c            |  1 +
 source3/smbd/smb2_sesssetup.c       |  1 +
 source4/auth/auth.h                 |  1 +
 source4/auth/ntlm/auth_simple.c     | 12 +++++++++++-
 source4/ldap_server/ldap_backend.c  |  6 ++++++
 source4/ldap_server/ldap_bind.c     |  9 ++++++++-
 source4/rpc_server/dcesrv_auth.c    |  5 +++++
 source4/smb_server/smb/sesssetup.c  |  2 ++
 source4/smb_server/smb2/sesssetup.c |  1 +
 15 files changed, 66 insertions(+), 2 deletions(-)

diff --git a/auth/auth_log.c b/auth/auth_log.c
index f390ced..e2512f7 100644
--- a/auth/auth_log.c
+++ b/auth/auth_log.c
@@ -185,6 +185,7 @@ void log_successful_authz_event(const struct tsocket_address *remote,
 				const struct tsocket_address *local,
 				const char *service_description,
 				const char *auth_type,
+				const char *transport_protection,
 				struct auth_session_info *session_info)
 {
 	TALLOC_CTX *frame = NULL;
diff --git a/auth/common_auth.h b/auth/common_auth.h
index 999d05c..2568237 100644
--- a/auth/common_auth.h
+++ b/auth/common_auth.h
@@ -146,6 +146,12 @@ struct auth4_context {
 					      struct auth_session_info **session_info);
 };
 
+#define AUTHZ_TRANSPORT_PROTECTION_NONE "NONE"
+#define AUTHZ_TRANSPORT_PROTECTION_SMB "SMB"
+#define AUTHZ_TRANSPORT_PROTECTION_TLS "TLS"
+#define AUTHZ_TRANSPORT_PROTECTION_SEAL "SEAL"
+#define AUTHZ_TRANSPORT_PROTECTION_SIGN "SIGN"
+
 void log_authentication_event(const struct auth_usersupplied_info *ui,
 			      NTSTATUS status,
 			      const char *account_name,
@@ -157,5 +163,6 @@ void log_successful_authz_event(const struct tsocket_address *remote,
 				const struct tsocket_address *local,
 				const char *service_description,
 				const char *auth_type,
+				const char *transport_protection,
 				struct auth_session_info *session_info);
 #endif
diff --git a/auth/gensec/gensec.c b/auth/gensec/gensec.c
index d275976..14fd9f4 100644
--- a/auth/gensec/gensec.c
+++ b/auth/gensec/gensec.c
@@ -221,9 +221,22 @@ static void log_successful_gensec_authz_event(struct gensec_security *gensec_sec
 		= gensec_get_target_service_description(gensec_security);
 	const char *final_auth_type
 		= gensec_final_auth_type(gensec_security);
+	const char *transport_protection = NULL;
+	if (gensec_security->want_features & GENSEC_FEATURE_SMB_TRANSPORT) {
+		transport_protection = AUTHZ_TRANSPORT_PROTECTION_SMB;
+	} else if (gensec_security->want_features & GENSEC_FEATURE_LDAPS_TRANSPORT) {
+		transport_protection = AUTHZ_TRANSPORT_PROTECTION_TLS;
+	} else if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)) {
+		transport_protection = AUTHZ_TRANSPORT_PROTECTION_SEAL;
+	} else if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
+		transport_protection = AUTHZ_TRANSPORT_PROTECTION_SIGN;
+	} else {
+		transport_protection = AUTHZ_TRANSPORT_PROTECTION_NONE;
+	}
 	log_successful_authz_event(remote, local,
 				   service_description,
 				   final_auth_type,
+				   transport_protection,
 				   session_info);
 }
 
diff --git a/auth/gensec/gensec.h b/auth/gensec/gensec.h
index bc96e69..6764ee5 100644
--- a/auth/gensec/gensec.h
+++ b/auth/gensec/gensec.h
@@ -68,6 +68,8 @@ struct gensec_target {
 #define GENSEC_FEATURE_NTLM_CCACHE	0x00000200
 #define GENSEC_FEATURE_LDAP_STYLE	0x00000400
 #define GENSEC_FEATURE_NO_AUTHZ_LOG	0x00000800
+#define GENSEC_FEATURE_SMB_TRANSPORT	0x00001000
+#define GENSEC_FEATURE_LDAPS_TRANSPORT	0x00002000
 
 #define GENSEC_EXPIRE_TIME_INFINITY (NTTIME)0x8000000000000000LL
 
diff --git a/source3/auth/auth_generic.c b/source3/auth/auth_generic.c
index 4033996..2e429e8 100644
--- a/source3/auth/auth_generic.c
+++ b/source3/auth/auth_generic.c
@@ -437,6 +437,7 @@ NTSTATUS auth_check_password_session_info(struct auth4_context *auth_context,
 				   user_info->local_host,
 				   user_info->service_description,
 				   user_info->auth_description,
+				   AUTHZ_TRANSPORT_PROTECTION_SMB,
 				   *session_info);
 
 	return nt_status;
diff --git a/source3/rpc_server/srv_pipe.c b/source3/rpc_server/srv_pipe.c
index bd56be6..c8b0fdc 100644
--- a/source3/rpc_server/srv_pipe.c
+++ b/source3/rpc_server/srv_pipe.c
@@ -822,6 +822,11 @@ static bool api_pipe_bind_req(struct pipes_struct *p,
 			goto err_exit;
 		}
 	} else {
+		const char *transport_protection = AUTHZ_TRANSPORT_PROTECTION_NONE;
+		if (p->transport == NCACN_NP) {
+			transport_protection = AUTHZ_TRANSPORT_PROTECTION_SMB;
+		}
+
 		p->auth.auth_type = DCERPC_AUTH_TYPE_NONE;
 		p->auth.auth_level = DCERPC_AUTH_LEVEL_NONE;
 		p->auth.auth_context_id = 0;
@@ -835,6 +840,7 @@ static bool api_pipe_bind_req(struct pipes_struct *p,
 					   p->local_address,
 					   table->name,
 					   derpc_transport_string_by_transport(p->transport),
+					   transport_protection,
 					   p->session_info);
 	}
 
diff --git a/source3/smbd/sesssetup.c b/source3/smbd/sesssetup.c
index 0cc49d9..2ed5a4c 100644
--- a/source3/smbd/sesssetup.c
+++ b/source3/smbd/sesssetup.c
@@ -263,6 +263,7 @@ static void reply_sesssetup_and_X_spnego(struct smb_request *req)
 
 		gensec_want_feature(auth->gensec, GENSEC_FEATURE_SESSION_KEY);
 		gensec_want_feature(auth->gensec, GENSEC_FEATURE_UNIX_TOKEN);
+		gensec_want_feature(auth->gensec, GENSEC_FEATURE_SMB_TRANSPORT);
 
 		status = gensec_start_mech_by_oid(auth->gensec,
 						  GENSEC_OID_SPNEGO);
diff --git a/source3/smbd/smb2_sesssetup.c b/source3/smbd/smb2_sesssetup.c
index 5246288..53cd7de 100644
--- a/source3/smbd/smb2_sesssetup.c
+++ b/source3/smbd/smb2_sesssetup.c
@@ -864,6 +864,7 @@ auth:
 
 		gensec_want_feature(state->auth->gensec, GENSEC_FEATURE_SESSION_KEY);
 		gensec_want_feature(state->auth->gensec, GENSEC_FEATURE_UNIX_TOKEN);
+		gensec_want_feature(state->auth->gensec, GENSEC_FEATURE_SMB_TRANSPORT);
 
 		status = gensec_start_mech_by_oid(state->auth->gensec,
 						  GENSEC_OID_SPNEGO);
diff --git a/source4/auth/auth.h b/source4/auth/auth.h
index d4be60e..88f88a4 100644
--- a/source4/auth/auth.h
+++ b/source4/auth/auth.h
@@ -164,6 +164,7 @@ NTSTATUS authenticate_ldap_simple_bind(TALLOC_CTX *mem_ctx,
 				       struct loadparm_context *lp_ctx,
 				       struct tsocket_address *remote_address,
 				       struct tsocket_address *local_address,
+				       bool using_tls,
 				       const char *dn,
 				       const char *password,
 				       struct auth_session_info **session_info);
diff --git a/source4/auth/ntlm/auth_simple.c b/source4/auth/ntlm/auth_simple.c
index a14883d..4e5780f 100644
--- a/source4/auth/ntlm/auth_simple.c
+++ b/source4/auth/ntlm/auth_simple.c
@@ -35,6 +35,7 @@ _PUBLIC_ NTSTATUS authenticate_ldap_simple_bind(TALLOC_CTX *mem_ctx,
 						struct loadparm_context *lp_ctx,
 						struct tsocket_address *remote_address,
 						struct tsocket_address *local_address,
+						bool using_tls,
 						const char *dn,
 						const char *password,
 						struct auth_session_info **session_info)
@@ -47,6 +48,10 @@ _PUBLIC_ NTSTATUS authenticate_ldap_simple_bind(TALLOC_CTX *mem_ctx,
 	const char *nt4_domain;
 	const char *nt4_username;
 	uint32_t flags = 0;
+	const char *transport_protection = AUTHZ_TRANSPORT_PROTECTION_NONE;
+	if (using_tls) {
+		transport_protection = AUTHZ_TRANSPORT_PROTECTION_TLS;
+	}
 
 	if (!tmp_ctx) {
 		return NT_STATUS_NO_MEMORY;
@@ -87,7 +92,11 @@ _PUBLIC_ NTSTATUS authenticate_ldap_simple_bind(TALLOC_CTX *mem_ctx,
 
 	user_info->service_description = "LDAP";
 
-	user_info->auth_description = "simple bind";
+	if (using_tls) {
+		user_info->auth_description = "simple bind";
+	} else {
+		user_info->auth_description = "simple bind/TLS";
+	}
 
 	user_info->password_state = AUTH_PASSWORD_PLAIN;
 	user_info->password.plaintext = talloc_strdup(user_info, password);
@@ -126,6 +135,7 @@ _PUBLIC_ NTSTATUS authenticate_ldap_simple_bind(TALLOC_CTX *mem_ctx,
 				   local_address,
 				   "LDAP",
 				   "simple bind",
+				   transport_protection,
 				   *session_info);
 
 	talloc_free(tmp_ctx);
diff --git a/source4/ldap_server/ldap_backend.c b/source4/ldap_server/ldap_backend.c
index b023eb4..7aa51f2 100644
--- a/source4/ldap_server/ldap_backend.c
+++ b/source4/ldap_server/ldap_backend.c
@@ -1280,10 +1280,16 @@ NTSTATUS ldapsrv_do_call(struct ldapsrv_call *call)
 		}
 
 		if (log) {
+			const char *transport_protection = AUTHZ_TRANSPORT_PROTECTION_NONE;
+			if (call->conn->sockets.active == call->conn->sockets.tls) {
+				transport_protection = AUTHZ_TRANSPORT_PROTECTION_TLS;
+			}
+
 			log_successful_authz_event(call->conn->connection->remote_address,
 						   call->conn->connection->local_address,
 						   "LDAP",
 						   "no bind",
+						   transport_protection,
 						   call->conn->session_info);
 
 			call->conn->authz_logged = true;
diff --git a/source4/ldap_server/ldap_bind.c b/source4/ldap_server/ldap_bind.c
index 5fc50dc..986ecbf 100644
--- a/source4/ldap_server/ldap_bind.c
+++ b/source4/ldap_server/ldap_bind.c
@@ -73,6 +73,8 @@ static NTSTATUS ldapsrv_BindSimple(struct ldapsrv_call *call)
 
 	NTSTATUS status;
 
+	bool using_tls = call->conn->sockets.active == call->conn->sockets.tls;
+
 	DEBUG(10, ("BindSimple dn: %s\n",req->dn));
 
 	reply = ldapsrv_init_reply(call, LDAP_TAG_BindResponse);
@@ -83,7 +85,7 @@ static NTSTATUS ldapsrv_BindSimple(struct ldapsrv_call *call)
 	if (req->dn != NULL &&
 	    strlen(req->dn) != 0 &&
 	    call->conn->require_strong_auth > LDAP_SERVER_REQUIRE_STRONG_AUTH_NO &&
-	    call->conn->sockets.active != call->conn->sockets.tls)
+	    !using_tls)
 	{
 		status = NT_STATUS_NETWORK_ACCESS_DENIED;
 		result = LDAP_STRONG_AUTH_REQUIRED;
@@ -98,6 +100,7 @@ static NTSTATUS ldapsrv_BindSimple(struct ldapsrv_call *call)
 					       call->conn->lp_ctx,
 					       call->conn->connection->remote_address,
 					       call->conn->connection->local_address,
+					       using_tls,
 					       req->dn,
 					       req->creds.password,
 					       &session_info);
@@ -218,6 +221,10 @@ static NTSTATUS ldapsrv_setup_gensec(struct ldapsrv_connection *conn,
 	gensec_want_feature(gensec_security, GENSEC_FEATURE_ASYNC_REPLIES);
 	gensec_want_feature(gensec_security, GENSEC_FEATURE_LDAP_STYLE);
 
+	if (conn->sockets.active == conn->sockets.tls) {
+		gensec_want_feature(gensec_security, GENSEC_FEATURE_LDAPS_TRANSPORT);
+	}
+
 	status = gensec_start_mech_by_sasl_name(gensec_security, sasl_mech);
 
 	if (!NT_STATUS_IS_OK(status)) {
diff --git a/source4/rpc_server/dcesrv_auth.c b/source4/rpc_server/dcesrv_auth.c
index 4b0bfdf..1ebb514 100644
--- a/source4/rpc_server/dcesrv_auth.c
+++ b/source4/rpc_server/dcesrv_auth.c
@@ -49,6 +49,10 @@ bool dcesrv_auth_bind(struct dcesrv_call_state *call)
 		enum dcerpc_transport_t transport =
 			dcerpc_binding_get_transport(call->conn->endpoint->ep_description);
 		const char *auth_type = derpc_transport_string_by_transport(transport);
+		const char *transport_protection = AUTHZ_TRANSPORT_PROTECTION_NONE;
+		if (transport == NCACN_NP) {
+			transport_protection = AUTHZ_TRANSPORT_PROTECTION_SMB;
+		}
 		auth->auth_type = DCERPC_AUTH_TYPE_NONE;
 		auth->auth_level = DCERPC_AUTH_LEVEL_NONE;
 		auth->auth_context_id = 0;
@@ -62,6 +66,7 @@ bool dcesrv_auth_bind(struct dcesrv_call_state *call)
 					   call->conn->local_address,
 					   "DCE/RPC",
 					   auth_type,
+					   transport_protection,
 					   call->conn->auth_state.session_info);
 
 		return true;
diff --git a/source4/smb_server/smb/sesssetup.c b/source4/smb_server/smb/sesssetup.c
index ebe310a..ce73a02 100644
--- a/source4/smb_server/smb/sesssetup.c
+++ b/source4/smb_server/smb/sesssetup.c
@@ -58,6 +58,7 @@ void smbsrv_not_spengo_sesssetup_authz_log(struct smbsrv_request *req,
 				   local_address,
 				   "SMB",
 				   "bare-NTLM",
+				   AUTHZ_TRANSPORT_PROTECTION_SMB,
 				   session_info);
 
 	talloc_free(frame);
@@ -507,6 +508,7 @@ static void sesssetup_spnego(struct smbsrv_request *req, union smb_sesssetup *se
 		}
 
 		gensec_want_feature(gensec_ctx, GENSEC_FEATURE_SESSION_KEY);
+		gensec_want_feature(gensec_ctx, GENSEC_FEATURE_SMB_TRANSPORT);
 
 		remote_address = socket_get_remote_addr(req->smb_conn->connection->socket,
 							req);
diff --git a/source4/smb_server/smb2/sesssetup.c b/source4/smb_server/smb2/sesssetup.c
index 7d92aa2..d87651d 100644
--- a/source4/smb_server/smb2/sesssetup.c
+++ b/source4/smb_server/smb2/sesssetup.c
@@ -145,6 +145,7 @@ static void smb2srv_sesssetup_backend(struct smb2srv_request *req, union smb_ses
 		}
 
 		gensec_want_feature(gensec_ctx, GENSEC_FEATURE_SESSION_KEY);
+		gensec_want_feature(gensec_ctx, GENSEC_FEATURE_SMB_TRANSPORT);
 
 		remote_address = socket_get_remote_addr(req->smb_conn->connection->socket,
 							req);
-- 
2.7.4


From d70c7b3beeb2cd55451fe71bf926307f71068af0 Mon Sep 17 00:00:00 2001
From: Andrew Bartlett <abartlet at samba.org>
Date: Mon, 6 Mar 2017 12:11:18 +1300
Subject: [PATCH 41/43] auth: Add SID_NT_NTLM_AUTHENTICATION / S-1-5-64-10 to
 the token during NTLM auth

So far this is only on the AD DC

Signed-off-by: Andrew Bartlett <abartlet at samba.org>
Pair-Programmed: Gary Lockyer <gary at catalyst.net.nz>
---
 auth/common_auth.h                       |  1 +
 auth/ntlmssp/gensec_ntlmssp_server.c     |  1 +
 source3/auth/auth_generic.c              |  3 ++-
 source4/auth/pyauth.c                    |  1 +
 source4/auth/session.c                   |  9 +++++++++
 source4/dsdb/tests/python/token_group.py | 16 +++++++++++++++-
 source4/selftest/tests.py                |  3 ++-
 7 files changed, 31 insertions(+), 3 deletions(-)

diff --git a/auth/common_auth.h b/auth/common_auth.h
index 2568237..331f112 100644
--- a/auth/common_auth.h
+++ b/auth/common_auth.h
@@ -39,6 +39,7 @@ enum auth_password_state {
 #define AUTH_SESSION_INFO_AUTHENTICATED      0x02 /* Add the user to the 'authenticated users' group */
 #define AUTH_SESSION_INFO_SIMPLE_PRIVILEGES  0x04 /* Use a trivial map between users and privilages, rather than a DB */
 #define AUTH_SESSION_INFO_UNIX_TOKEN         0x08 /* The returned token must have the unix_token and unix_info elements provided */
+#define AUTH_SESSION_INFO_NTLM               0x10 /* The returned token must have authenticated-with-NTLM flag set */
 
 struct auth_usersupplied_info
 {
diff --git a/auth/ntlmssp/gensec_ntlmssp_server.c b/auth/ntlmssp/gensec_ntlmssp_server.c
index da0cd50..561c7cf 100644
--- a/auth/ntlmssp/gensec_ntlmssp_server.c
+++ b/auth/ntlmssp/gensec_ntlmssp_server.c
@@ -62,6 +62,7 @@ NTSTATUS gensec_ntlmssp_session_info(struct gensec_security *gensec_security,
 	}
 
 	session_info_flags |= AUTH_SESSION_INFO_DEFAULT_GROUPS;
+	session_info_flags |= AUTH_SESSION_INFO_NTLM;
 
 	if (gensec_security->auth_context && gensec_security->auth_context->generate_session_info) {
 		nt_status = gensec_security->auth_context->generate_session_info(gensec_security->auth_context, mem_ctx, 
diff --git a/source3/auth/auth_generic.c b/source3/auth/auth_generic.c
index 2e429e8..5631c85 100644
--- a/source3/auth/auth_generic.c
+++ b/source3/auth/auth_generic.c
@@ -423,7 +423,8 @@ NTSTATUS auth_check_password_session_info(struct auth4_context *auth_context,
 								server_info,
 								user_info->client.account_name,
 								AUTH_SESSION_INFO_UNIX_TOKEN |
-								AUTH_SESSION_INFO_DEFAULT_GROUPS,
+								AUTH_SESSION_INFO_DEFAULT_GROUPS |
+								AUTH_SESSION_INFO_NTLM,
 								session_info);
 		TALLOC_FREE(server_info);
 	}
diff --git a/source4/auth/pyauth.c b/source4/auth/pyauth.c
index 2d82760..4cb12f8 100644
--- a/source4/auth/pyauth.c
+++ b/source4/auth/pyauth.c
@@ -333,6 +333,7 @@ MODULE_INIT_FUNC(auth)
 	ADD_FLAG(AUTH_SESSION_INFO_DEFAULT_GROUPS);
 	ADD_FLAG(AUTH_SESSION_INFO_AUTHENTICATED);
 	ADD_FLAG(AUTH_SESSION_INFO_SIMPLE_PRIVILEGES);
+	ADD_FLAG(AUTH_SESSION_INFO_NTLM);
 
 	return m;
 }
diff --git a/source4/auth/session.c b/source4/auth/session.c
index 3d8714c..982d51d 100644
--- a/source4/auth/session.c
+++ b/source4/auth/session.c
@@ -154,6 +154,15 @@ _PUBLIC_ NTSTATUS auth_generate_session_info(TALLOC_CTX *mem_ctx,
 		num_sids++;
 	}
 
+	if (session_info_flags & AUTH_SESSION_INFO_NTLM) {
+		sids = talloc_realloc(tmp_ctx, sids, struct dom_sid, num_sids + 1);
+		NT_STATUS_HAVE_NO_MEMORY(sids);
+
+		if (!dom_sid_parse(SID_NT_NTLM_AUTHENTICATION, &sids[num_sids])) {
+			return NT_STATUS_INTERNAL_ERROR;
+		}
+		num_sids++;
+	}
 
 
 	if (num_sids > PRIMARY_USER_SID_INDEX && dom_sid_equal(anonymous_sid, &sids[PRIMARY_USER_SID_INDEX])) {
diff --git a/source4/dsdb/tests/python/token_group.py b/source4/dsdb/tests/python/token_group.py
index e3a7586..6a9c867 100755
--- a/source4/dsdb/tests/python/token_group.py
+++ b/source4/dsdb/tests/python/token_group.py
@@ -24,7 +24,7 @@ from samba.dsdb import GTYPE_SECURITY_GLOBAL_GROUP, GTYPE_SECURITY_UNIVERSAL_GRO
 import samba.tests
 from samba.tests import delete_force
 from samba.dcerpc import samr, security
-from samba.auth import AUTH_SESSION_INFO_DEFAULT_GROUPS, AUTH_SESSION_INFO_AUTHENTICATED, AUTH_SESSION_INFO_SIMPLE_PRIVILEGES
+from samba.auth import AUTH_SESSION_INFO_DEFAULT_GROUPS, AUTH_SESSION_INFO_AUTHENTICATED, AUTH_SESSION_INFO_SIMPLE_PRIVILEGES, AUTH_SESSION_INFO_NTLM
 
 
 parser = optparse.OptionParser("token_group.py [options] <host>")
@@ -71,6 +71,9 @@ class StaticTokenTest(samba.tests.TestCase):
         session_info_flags = ( AUTH_SESSION_INFO_DEFAULT_GROUPS |
                                AUTH_SESSION_INFO_AUTHENTICATED |
                                AUTH_SESSION_INFO_SIMPLE_PRIVILEGES)
+        if creds.get_kerberos_state() == DONT_USE_KERBEROS:
+            session_info_flags |= AUTH_SESSION_INFO_NTLM
+
         session = samba.auth.user_session(self.ldb, lp_ctx=lp, dn=self.user_sid_dn,
                                           session_info_flags=session_info_flags)
 
@@ -118,6 +121,9 @@ class StaticTokenTest(samba.tests.TestCase):
             self.fail(msg="calculated groups don't match against user DN tokenGroups")
 
     def test_pac_groups(self):
+        if creds.get_kerberos_state() == DONT_USE_KERBEROS:
+            self.skipTest("Kerberos disabled, skipping PAC test")
+
         settings = {}
         settings["lp_ctx"] = lp
         settings["target_hostname"] = lp.get("netbios name")
@@ -276,6 +282,10 @@ class DynamicTokenTest(samba.tests.TestCase):
         session_info_flags = ( AUTH_SESSION_INFO_DEFAULT_GROUPS |
                                AUTH_SESSION_INFO_AUTHENTICATED |
                                AUTH_SESSION_INFO_SIMPLE_PRIVILEGES)
+
+        if creds.get_kerberos_state() == DONT_USE_KERBEROS:
+            session_info_flags |= AUTH_SESSION_INFO_NTLM
+
         session = samba.auth.user_session(self.ldb, lp_ctx=lp, dn=self.user_sid_dn,
                                           session_info_flags=session_info_flags)
 
@@ -336,6 +346,10 @@ class DynamicTokenTest(samba.tests.TestCase):
 
         sidset1 = set(dn_tokengroups)
         sidset2 = set(self.user_sids)
+
+        # The SIDs on the DN do not include the NTLM authentication SID
+        sidset2.discard(samba.dcerpc.security.SID_NT_NTLM_AUTHENTICATION)
+
         if len(sidset1.difference(sidset2)):
             print("token sids don't match")
             print("difference : %s" % sidset1.difference(sidset2))
diff --git a/source4/selftest/tests.py b/source4/selftest/tests.py
index c2c5486..811bbcd 100755
--- a/source4/selftest/tests.py
+++ b/source4/selftest/tests.py
@@ -591,7 +591,8 @@ planoldpythontestsuite("ad_dc_ntvfs", "samba.tests.dcerpc.dnsserver", extra_args
 planoldpythontestsuite("ad_dc", "samba.tests.dcerpc.dnsserver", extra_args=['-U"$USERNAME%$PASSWORD"'])
 planoldpythontestsuite("ad_dc", "samba.tests.dcerpc.raw_protocol", extra_args=['-U"$USERNAME%$PASSWORD"'])
 plantestsuite_loadlist("samba4.ldap.python(ad_dc_ntvfs)", "ad_dc_ntvfs", [python, os.path.join(samba4srcdir, "dsdb/tests/python/ldap.py"), '$SERVER', '-U"$USERNAME%$PASSWORD"', '--workgroup=$DOMAIN', '$LOADLIST', '$LISTOPT'])
-plantestsuite_loadlist("samba4.tokengroups.python(ad_dc_ntvfs)", "ad_dc_ntvfs:local", [python, os.path.join(samba4srcdir, "dsdb/tests/python/token_group.py"), '$SERVER', '-U"$USERNAME%$PASSWORD"', '--workgroup=$DOMAIN', '$LOADLIST', '$LISTOPT'])
+plantestsuite_loadlist("samba4.tokengroups.krb5.python(ad_dc_ntvfs)", "ad_dc_ntvfs:local", [python, os.path.join(samba4srcdir, "dsdb/tests/python/token_group.py"), '$SERVER', '-U"$USERNAME%$PASSWORD"', '--workgroup=$DOMAIN', '-k', 'yes', '$LOADLIST', '$LISTOPT'])
+plantestsuite_loadlist("samba4.tokengroups.ntlm.python(ad_dc_ntvfs)", "ad_dc_ntvfs:local", [python, os.path.join(samba4srcdir, "dsdb/tests/python/token_group.py"), '$SERVER', '-U"$USERNAME%$PASSWORD"', '--workgroup=$DOMAIN', '-k', 'no', '$LOADLIST', '$LISTOPT'])
 plantestsuite("samba4.sam.python(fl2008r2dc)", "fl2008r2dc", [python, os.path.join(samba4srcdir, "dsdb/tests/python/sam.py"), '$SERVER', '-U"$USERNAME%$PASSWORD"', '--workgroup=$DOMAIN'])
 plantestsuite("samba4.sam.python(ad_dc_ntvfs)", "ad_dc_ntvfs", [python, os.path.join(samba4srcdir, "dsdb/tests/python/sam.py"), '$SERVER', '-U"$USERNAME%$PASSWORD"', '--workgroup=$DOMAIN'])
 plantestsuite("samba4.user_account_control.python(ad_dc_ntvfs)", "ad_dc_ntvfs", [python, os.path.join(samba4srcdir, "dsdb/tests/python/user_account_control.py"), '$SERVER', '-U"$USERNAME%$PASSWORD"', '--workgroup=$DOMAIN'])
-- 
2.7.4


From 3788857cd412291f783be425f124e7d34b6634c8 Mon Sep 17 00:00:00 2001
From: Gary Lockyer <gary at catalyst.net.nz>
Date: Mon, 6 Mar 2017 16:16:51 +1300
Subject: [PATCH 42/43] auth_log: Add JSON logging of Authorisation and
 Authentications

Signed-off-by: Gary Lockyer <gary at catalyst.net.nz>
Pair-Programmed: Andrew Bartlet <abartlet at samba.org>
---
 auth/auth_log.c        | 594 ++++++++++++++++++++++++++++++++++++++++++++-----
 auth/wscript_build     |   2 +-
 auth/wscript_configure |   7 +
 lib/util/debug.c       |   1 +
 lib/util/debug.h       |   2 +-
 wscript                |   1 +
 6 files changed, 552 insertions(+), 55 deletions(-)
 create mode 100644 auth/wscript_configure

diff --git a/auth/auth_log.c b/auth/auth_log.c
index e2512f7..54a3f3b 100644
--- a/auth/auth_log.c
+++ b/auth/auth_log.c
@@ -30,6 +30,21 @@
 #define AUTH_ANONYMOUS_LEVEL 5
 #define AUTHZ_ANONYMOUS_LEVEL 5
 
+#define AUTHZ_JSON_TYPE "Authorization"
+#define AUTH_JSON_TYPE  "Authentication"
+
+/*
+ * JSON message version numbers
+ *
+ * If adding a field increment the minor version
+ * If removing or changing the format/meaning of a field
+ * increment the major version.
+ */
+#define AUTH_MAJOR 1
+#define AUTH_MINOR 0
+#define AUTHZ_MAJOR 1
+#define AUTHZ_MINOR 0
+
 #include "includes.h"
 #include "../lib/tsocket/tsocket.h"
 #include "common_auth.h"
@@ -42,6 +57,411 @@
  * authorisation attempt.
  *
  */
+static const char* get_password_type(const struct auth_usersupplied_info *ui);
+
+#ifdef HAVE_JANSSON
+
+#include <jansson.h>
+#include "system/time.h"
+
+/*
+ * Context required by the JSON generation
+ *  routines
+ *
+ */
+struct json_context {
+	json_t *root;
+	bool error;
+};
+
+/*
+ * Write the json object to the debug lines.
+ *
+ */
+static void log_json( struct json_context *context,
+		     const char *type, int debug_class, int debug_level)
+{
+	char* json = NULL;
+
+	if( context->error) {
+		return;
+	}
+
+	json = json_dumps( context->root, 0);
+	if (json == NULL) {
+		DBG_ERR( "Unable to convert JSON object to string\n");
+		context->error = true;
+		return;
+	}
+
+	DEBUGC( debug_class, debug_level, ( "JSON %s: %s\n", type, json));
+
+	if (json) {
+		free(json);
+	}
+
+}
+
+/*
+ * Create a new json logging context.
+ *
+ * Free with a call to free_json_context
+ *
+ */
+static struct json_context get_json_context( void) {
+
+	struct json_context context;
+	context.error = false;
+
+	context.root = json_object();
+	if (context.root == NULL) {
+		context.error = true;
+		DBG_ERR("Unable to create json_object\n");
+	}
+	return context;
+}
+
+/*
+ * free a previously created json_context
+ *
+ */
+static void free_json_context(struct json_context *context)
+{
+	if (context->root) {
+		json_decref( context->root);
+	}
+}
+
+/*
+ * Output a JSON pair with name name and integer value value
+ *
+ */
+static void add_int(struct json_context *context,
+		    const char* name,
+		    const int value)
+{
+	int rc = 0;
+
+	if (context->error) {
+		return;
+	}
+
+	rc = json_object_set_new( context->root, name, json_integer( value));
+	if (rc) {
+		DBG_ERR("Unable to set name [%s] value [%d]\n", name, value);
+		context->error = true;
+	}
+
+}
+
+/*
+ * Output a JSON pair with name name and string value value
+ *
+ */
+static void add_string(struct json_context *context,
+		       const char* name,
+		       const char* value)
+{
+	int rc = 0;
+
+	if (context->error) {
+		return;
+	}
+
+	if (value) {
+		rc = json_object_set_new(context->root, name, json_string(value));
+	} else {
+		rc = json_object_set_new(context->root, name, json_null());
+	}
+	if (rc) {
+		DBG_ERR("Unable to set name [%s] value [%s]\n", name, value);
+		context->error = true;
+	}
+}
+
+
+/*
+ * Output a JSON pair with name name and object value
+ *
+ */
+static void add_object(struct json_context *context,
+		       const char* name,
+		       struct json_context *value)
+{
+	int rc = 0;
+
+	if (value->error) {
+		context->error = true;
+	}
+	if (context->error) {
+		return;
+	}
+	rc = json_object_set_new(context->root, name, value->root);
+	if (rc) {
+		DBG_ERR("Unable to add object [%s]\n", name);
+		context->error = true;
+	}
+}
+
+/*
+ * Output a version object
+ *
+ * "version":{"major":1,"minor":0}
+ *
+ */
+static void add_version( struct json_context *context, int major, int minor)
+{
+	struct json_context version = get_json_context();
+	add_int(&version, "major", major);
+	add_int(&version, "minor", minor);
+	add_object(context, "version", &version);
+}
+
+/*
+ * Output the current date and time as a timestamp in ISO 8601 format
+ *
+ * "timestamp":"2017-03-06T17:18:04.455081+1300"
+ *
+ */
+static void add_timestamp( struct json_context *context)
+{
+	char buffer[40];
+	char timestamp[50];
+	char tz[10];
+	struct tm* tm_info;
+	struct timeval tv;
+	int r;
+
+	if (context->error) {
+		return;
+	}
+
+	r = gettimeofday(&tv, NULL);
+	if (r) {
+		DBG_ERR("Unable to get time of day: (%d) %s\n",
+			errno,
+			strerror( errno));
+		context->error = true;
+		return;
+	}
+
+	tm_info = localtime(&tv.tv_sec);
+	if (tm_info == NULL) {
+		DBG_ERR("Unable to determine local time\n");
+		context->error = true;
+		return;
+	}
+
+	strftime(buffer, sizeof(buffer), "%Y-%m-%dT%T", tm_info);
+	strftime(tz, sizeof(tz), "%z", tm_info);
+	snprintf(timestamp, sizeof(timestamp),"%s.%06ld%s",
+		 buffer, tv.tv_usec, tz);
+	add_string(context,"timestamp", timestamp);
+}
+
+
+/*
+ * Output an address pair, with name name.
+ *
+ * "localAddress":"ipv6::::0"
+ *
+ */
+static void add_address(struct json_context *context,
+			const char *name,
+			const struct tsocket_address *address)
+{
+	char *s = NULL;
+	TALLOC_CTX *frame = talloc_stackframe();
+
+	if (context->error) {
+		return;
+	}
+
+	s = tsocket_address_string(address, frame);
+	add_string(context, name, s);
+	talloc_free(frame);
+
+}
+
+/*
+ * Output a SID with name name
+ *
+ * "sid":"S-1-5-18"
+ *
+ */
+static void add_sid(struct json_context *context,
+		    const char *name,
+		    const struct dom_sid *sid)
+{
+	char sid_buf[DOM_SID_STR_BUFLEN];
+
+	if (context->error) {
+		return;
+	}
+
+	dom_sid_string_buf(sid, sid_buf, sizeof(sid_buf));
+	add_string(context, name, sid_buf);
+}
+
+/*
+ * Write a machine parsable json formatted authentication log entry.
+ *
+ * IF removing or changing the format/meaning of a field please update the
+ *    major version number AUTH_MAJOR
+ *
+ * IF adding a new field please update the minor version number AUTH_MINOR
+ *
+ *  To process the resulting log lines from the commend line use jq to
+ *  parse the json.
+ *
+ *  grep "JSON Authentication" log file |
+ *  sed 's;^[^{]*;;' |
+ * jq -rc  '"\(.timestamp)\t\(.Authentication.status)\t
+ *           \(.Authentication.clientDomain)\t
+ *           \(.Authentication.clientAccount)
+ *           \t\(.Authentication.workstation)
+ *           \t\(.Authentication.remoteAddress)
+ *           \t\(.Authentication.localAddress)"'
+ */
+static void log_authentication_event_json(
+			const struct auth_usersupplied_info *ui,
+			NTSTATUS status,
+			const char *domain_name,
+			const char *account_name,
+			const char *unix_username,
+			struct dom_sid *sid,
+			int debug_level)
+{
+	struct json_context context = get_json_context();
+	struct json_context authentication;
+
+	add_timestamp(&context);
+	add_string(&context, "type", AUTH_JSON_TYPE);
+
+	authentication = get_json_context();
+	add_version(&authentication, AUTH_MAJOR, AUTH_MINOR);
+	add_string(&authentication, "status", nt_errstr( status));
+	add_address(&authentication, "localAddress", ui->local_host);
+	add_address(&authentication, "remoteAddress", ui->remote_host);
+	add_string(&authentication, "serviceDescription", ui->service_description);
+	add_string(&authentication, "authDescription", ui->auth_description);
+	add_string(&authentication, "clientDomain", ui->client.domain_name);
+	add_string(&authentication, "clientAccount", ui->client.account_name);
+	add_string(&authentication, "workstation", ui->workstation_name);
+	add_string(&authentication, "becameAccount", account_name);
+	add_string(&authentication, "becameDomain", domain_name);
+	add_string(&authentication, "mappedAccount", ui->mapped.account_name);
+	add_string(&authentication, "mappedDomain", ui->mapped.domain_name);
+	add_string(&authentication,
+		   "netlogonComputer",
+		   ui->netlogon_trust_account.computer_name);
+	add_string(&authentication,
+		   "trustAccount",
+		   ui->netlogon_trust_account.account_name);
+	add_string(&authentication, "passwordType", get_password_type( ui));
+	add_object(&context,AUTH_JSON_TYPE, &authentication);
+
+	log_json(&context, AUTH_JSON_TYPE, DBGC_AUTH_AUDIT, debug_level);
+	free_json_context(&context);
+}
+
+/*
+ * Log details of a successful authorization to a service,
+ * in a machine parsable json format
+ *
+ * IF removing or changing the format/meaning of a field please update the
+ *    major version number AUTHZ_MAJOR
+ *
+ * IF adding a new field please update the minor version number AUTHZ_MINOR
+ *
+ *  To process the resulting log lines from the commend line use jq to
+ *  parse the json.
+ *
+ *  grep "JSON Authentication" log_file |\
+ *  sed "s;^[^{]*;;" |\
+ *  jq -rc '"\(.timestamp)\t
+ *           \(.Authorization.domain)\t
+ *           \(.Authorization.account)\t
+ *           \(.Authorization.remoteAddress)"'
+ *
+ */
+static void log_successful_authz_event_json(
+				const struct tsocket_address *remote,
+				const struct tsocket_address *local,
+				const char *service_description,
+				const char *auth_type,
+				const char *transport_protection,
+				struct auth_session_info *session_info,
+				int debug_level)
+{
+	struct json_context context = get_json_context();
+	struct json_context authorization;
+	char account_flags[11];
+
+	//start_object(&context, NULL);
+	add_timestamp(&context);
+	add_string(&context, "type", AUTHZ_JSON_TYPE);
+	authorization = get_json_context();
+	add_version(&authorization, AUTHZ_MAJOR, AUTHZ_MINOR);
+	add_address(&authorization, "localAddress", local);
+	add_address(&authorization, "remoteAddress", remote);
+	add_string(&authorization, "serviceDescription", service_description);
+	add_string(&authorization, "authType", auth_type);
+	add_string(&authorization, "domain", session_info->info->domain_name);
+	add_string(&authorization, "account", session_info->info->account_name);
+	add_sid(&authorization, "sid", &session_info->security_token->sids[0]);
+	add_string(&authorization,
+		   "logonServer",
+		   session_info->info->logon_server);
+	add_string(&authorization, "transportProtection", transport_protection);
+
+	snprintf(account_flags,
+		 sizeof( account_flags),
+		 "0x%08X",
+		 session_info->info->acct_flags);
+	add_string(&authorization, "accountFlags", account_flags);
+	add_object(&context,AUTHZ_JSON_TYPE, &authorization);
+
+	log_json(&context,
+		 AUTHZ_JSON_TYPE,
+		 DBGC_AUTH_AUDIT,
+		 debug_level);
+	free_json_context(&context);
+}
+
+#else
+
+static void log_authentication_event_json(
+			const struct auth_usersupplied_info *ui,
+			NTSTATUS status,
+			const char *domain_name,
+			const char *account_name,
+			const char *unix_username,
+			struct dom_sid *sid,
+			int debug_level)
+{
+	return;
+}
+
+static void log_successful_authz_event_json(
+				const struct tsocket_address *remote,
+				const struct tsocket_address *local,
+				const char *service_description,
+				const char *auth_type,
+				const char *transport_protection,
+				struct auth_session_info *session_info,
+				int debug_level)
+{
+	return;
+}
+
+#endif
+
+/*
+ * Determine the type of the password supplied for the
+ * authorisation attempt.
+ *
+ */
 static const char* get_password_type(const struct auth_usersupplied_info *ui)
 {
 
@@ -74,19 +494,19 @@ static const char* get_password_type(const struct auth_usersupplied_info *ui)
 }
 
 /*
- * Log details of an authentication attempt.
- * Successful and unsuccessful attempts are logged.
+ * Write a human readable authentication log entry.
  *
  */
-void log_authentication_event(const struct auth_usersupplied_info *ui,
-			      NTSTATUS status,
-			      const char *domain_name,
-			      const char *account_name,
-			      const char *unix_username,
-			      struct dom_sid *sid)
+static void log_authentication_event_human_readable(
+			const struct auth_usersupplied_info *ui,
+			NTSTATUS status,
+			const char *domain_name,
+			const char *account_name,
+			const char *unix_username,
+			struct dom_sid *sid,
+			int debug_level)
 {
 	TALLOC_CTX *frame = NULL;
-
 	char *ts = NULL;         /* formatted current time      */
 	char *remote = NULL;     /* formatted remote host       */
 	char *local = NULL;      /* formatted local host        */
@@ -96,20 +516,6 @@ void log_authentication_event(const struct auth_usersupplied_info *ui,
 	char *logon_line = NULL;
 	const char *password_type = NULL;
 
-	/* set the log level */
-	int debug_level = AUTH_FAILURE_LEVEL;
-
-	if (NT_STATUS_IS_OK(status)) {
-		debug_level = AUTH_SUCCESS_LEVEL;
-		if (dom_sid_equal(sid, &global_sid_Anonymous)) {
-			debug_level = AUTH_ANONYMOUS_LEVEL;
-		}
-	}
-
-	if (!CHECK_DEBUGLVLC( DBGC_AUTH_AUDIT, debug_level)) {
-		return;
-	}
-
 	frame = talloc_stackframe();
 
 	password_type = get_password_type( ui);
@@ -135,16 +541,18 @@ void log_authentication_event(const struct auth_usersupplied_info *ui,
 		char sid_buf[DOM_SID_STR_BUFLEN];
 
 		dom_sid_string_buf(sid, sid_buf, sizeof(sid_buf));
-		logon_line = talloc_asprintf(frame,
-					     " became [%s]\\[%s] %s.",
-					     log_escape(frame, domain_name),
-					     log_escape(frame, account_name),
-					     sid_buf);
+		logon_line = talloc_asprintf(
+				frame,
+				" became [%s]\\[%s] %s.",
+				log_escape(frame, domain_name),
+				log_escape(frame, account_name),
+				sid_buf);
 	} else {
-		logon_line = talloc_asprintf(frame,
-					     " mapped to [%s]\\[%s].",
-					     log_escape(frame, ui->mapped.domain_name),
-					     log_escape(frame, ui->mapped.account_name));
+		logon_line = talloc_asprintf(
+				frame,
+				" mapped to [%s]\\[%s].",
+				log_escape(frame, ui->mapped.domain_name),
+				log_escape(frame, ui->mapped.account_name));
 	}
 
 	DEBUGC( DBGC_AUTH_AUDIT, debug_level, (
@@ -170,23 +578,65 @@ void log_authentication_event(const struct auth_usersupplied_info *ui,
 	talloc_free(frame);
 }
 
-
 /*
- * Log details of a successful authorization to a service.
- *
- * Only successful authorizations are logged.  For clarity:
- * - NTLM bad passwords will be recorded by the above
- * - Kerberos decrypt failures need to be logged in gensec_gssapi et al
+ * Log details of an authentication attempt.
+ * Successful and unsuccessful attempts are logged.
  *
- * The service may later refuse authorization due to an ACL.
+ * NOTE: msg_ctx and lp_ctx is optional, but when supplied allows streaming the
+ * authentication events over the message bus.
+ */
+void log_authentication_event( const struct auth_usersupplied_info *ui,
+			      NTSTATUS status,
+			      const char *domain_name,
+			      const char *account_name,
+			      const char *unix_username,
+			      struct dom_sid *sid)
+{
+	/* set the log level */
+	int debug_level = AUTH_FAILURE_LEVEL;
+
+	if (NT_STATUS_IS_OK(status)) {
+		debug_level = AUTH_SUCCESS_LEVEL;
+		if (dom_sid_equal(sid, &global_sid_Anonymous)) {
+			debug_level = AUTH_ANONYMOUS_LEVEL;
+		}
+	}
+
+	if (CHECK_DEBUGLVLC( DBGC_AUTH_AUDIT, debug_level)) {
+		log_authentication_event_human_readable(ui,
+							status,
+							domain_name,
+							account_name,
+							unix_username,
+							sid,
+							debug_level);
+	}
+	if (CHECK_DEBUGLVLC( DBGC_AUTH_AUDIT_JSON, debug_level)) {
+		log_authentication_event_json(ui,
+					      status,
+					      domain_name,
+					      account_name,
+					      unix_username,
+					      sid,
+					      debug_level);
+	}
+}
+
+
+
+/*
+ * Log details of a successful authorization to a service,
+ * in a human readable format.
  *
  */
-void log_successful_authz_event(const struct tsocket_address *remote,
+static void log_successful_authz_event_human_readable(
+				const struct tsocket_address *remote,
 				const struct tsocket_address *local,
 				const char *service_description,
 				const char *auth_type,
 				const char *transport_protection,
-				struct auth_session_info *session_info)
+				struct auth_session_info *session_info,
+				int debug_level)
 {
 	TALLOC_CTX *frame = NULL;
 
@@ -194,16 +644,6 @@ void log_successful_authz_event(const struct tsocket_address *remote,
 	char *remote_str = NULL;     /* formatted remote host       */
 	char *local_str = NULL;      /* formatted local host        */
 	char sid_buf[DOM_SID_STR_BUFLEN];
-	int debug_level = AUTHZ_SUCCESS_LEVEL;
-
-	if (security_token_is_anonymous(session_info->security_token)) {
-		debug_level = AUTH_ANONYMOUS_LEVEL;
-	}
-
-	/* set the log level */
-	if (!CHECK_DEBUGLVLC( DBGC_AUTH_AUDIT, debug_level)) {
-		return;
-	}
 
 	frame = talloc_stackframe();
 
@@ -213,9 +653,11 @@ void log_successful_authz_event(const struct tsocket_address *remote,
 	remote_str = tsocket_address_string(remote, frame);
 	local_str  = tsocket_address_string(local, frame);
 
-	dom_sid_string_buf(&session_info->security_token->sids[0], sid_buf, sizeof(sid_buf));
+	dom_sid_string_buf(&session_info->security_token->sids[0],
+			   sid_buf,
+			   sizeof(sid_buf));
 
-	DEBUGC( DBGC_AUTH_AUDIT, AUTHZ_SUCCESS_LEVEL, (
+	DEBUGC( DBGC_AUTH_AUDIT, debug_level, (
 		"Successful AuthZ: [%s,%s] user [%s]\\[%s] [%s]"
 		" at [%s]"
 		" Remote host [%s]"
@@ -231,3 +673,49 @@ void log_successful_authz_event(const struct tsocket_address *remote,
 
 	talloc_free(frame);
 }
+
+/*
+ * Log details of a successful authorization to a service.
+ *
+ * Only successful authorizations are logged.  For clarity:
+ * - NTLM bad passwords will be recorded by log_authentication_event
+ * - Kerberos decrypt failures need to be logged in gensec_gssapi et al
+ *
+ * The service may later refuse authorization due to an ACL.
+ *
+ * NOTE: msg_ctx and lp_ctx is optional, but when supplied allows streaming the
+ * authentication events over the message bus.
+ */
+void log_successful_authz_event(const struct tsocket_address *remote,
+				const struct tsocket_address *local,
+				const char *service_description,
+				const char *auth_type,
+				const char *transport_protection,
+				struct auth_session_info *session_info)
+{
+	int debug_level = AUTHZ_SUCCESS_LEVEL;
+
+	/* set the log level */
+	if (security_token_is_anonymous(session_info->security_token)) {
+		debug_level = AUTH_ANONYMOUS_LEVEL;
+	}
+
+	if (CHECK_DEBUGLVLC( DBGC_AUTH_AUDIT, debug_level)) {
+		log_successful_authz_event_human_readable(remote,
+							  local,
+							  service_description,
+							  auth_type,
+							  transport_protection,
+							  session_info,
+							  debug_level);
+	}
+	if (CHECK_DEBUGLVLC( DBGC_AUTH_AUDIT_JSON, debug_level)) {
+		log_successful_authz_event_json(remote,
+						local,
+						service_description,
+						auth_type,
+						transport_protection,
+						session_info,
+						debug_level);
+	}
+}
diff --git a/auth/wscript_build b/auth/wscript_build
index 732536d..30f8bf9 100644
--- a/auth/wscript_build
+++ b/auth/wscript_build
@@ -2,7 +2,7 @@
 
 bld.SAMBA_LIBRARY('common_auth',
                   source='auth_sam_reply.c wbc_auth_util.c auth_log.c',
-                  deps='talloc samba-security samba-util util_str_escape LIBTSOCKET',
+                  deps='talloc samba-security samba-util util_str_escape LIBTSOCKET jansson',
                   private_library=True
                   )
 
diff --git a/auth/wscript_configure b/auth/wscript_configure
new file mode 100644
index 0000000..47943fa
--- /dev/null
+++ b/auth/wscript_configure
@@ -0,0 +1,7 @@
+#!/usr/bin/env python
+
+conf.SET_TARGET_TYPE('jansson', 'EMPTY')
+
+if conf.CHECK_CFG(package='jansson', args='--cflags --libs',
+		  msg='Checking for jansson'):
+    conf.CHECK_FUNCS_IN('json_object', 'jansson')
diff --git a/lib/util/debug.c b/lib/util/debug.c
index 009f362..f48daf6 100644
--- a/lib/util/debug.c
+++ b/lib/util/debug.c
@@ -538,6 +538,7 @@ static const char *default_classname_table[] = {
 	[DBGC_LDB] =		"ldb",
 	[DBGC_TEVENT] =		"tevent",
 	[DBGC_AUTH_AUDIT] =	"auth_audit",
+	[DBGC_AUTH_AUDIT_JSON] = "auth_json_audit",
 };
 
 /*
diff --git a/lib/util/debug.h b/lib/util/debug.h
index 786c809..9d5f438 100644
--- a/lib/util/debug.h
+++ b/lib/util/debug.h
@@ -90,7 +90,7 @@ bool dbghdr( int level, const char *location, const char *func);
 #define DBGC_LDB		22
 #define DBGC_TEVENT		23
 #define DBGC_AUTH_AUDIT		24
-
+#define DBGC_AUTH_AUDIT_JSON	25
 /* So you can define DBGC_CLASS before including debug.h */
 #ifndef DBGC_CLASS
 #define DBGC_CLASS            0     /* override as shown above */
diff --git a/wscript b/wscript
index 4fd56ed..ba62697 100644
--- a/wscript
+++ b/wscript
@@ -203,6 +203,7 @@ def configure(conf):
         conf.RECURSE('ctdb')
     conf.RECURSE('lib/socket')
     conf.RECURSE('testsuite/unittests')
+    conf.RECURSE('auth')
 
     conf.SAMBA_CHECK_UNDEFINED_SYMBOL_FLAGS()
 
-- 
2.7.4


From bdb1a894c92c9dc9eac660901ea0e962939afef2 Mon Sep 17 00:00:00 2001
From: Andrew Bartlett <abartlet at samba.org>
Date: Tue, 7 Mar 2017 16:50:38 +1300
Subject: [PATCH 43/43] auth_log: Allow logging JSON events to a server over
 the message bus

This has required splitting up some of the messaging code to
remove a dependency loop.

Signed-off-by: Andrew Bartlett <abartlet at samba.org>
Pair-Programmed: Gary Lockyer <gary at catalyst.net.nz>
---
 auth/auth_log.c                                    | 140 +++++++++++++++++++--
 auth/common_auth.h                                 |  28 ++++-
 auth/gensec/gensec.c                               |   4 +-
 auth/wscript_build                                 |   2 +-
 .../smbdotconf/logon/autheventnotification.xml     |  17 +++
 source3/auth/auth.c                                |   5 +-
 source3/auth/auth_generic.c                        |   4 +-
 source3/rpc_server/srv_pipe.c                      |   3 +-
 source4/auth/ntlm/auth.c                           |   8 +-
 source4/auth/ntlm/auth_simple.c                    |   4 +-
 source4/ldap_server/ldap_backend.c                 |   4 +-
 source4/lib/messaging/messaging.c                  |  97 +-------------
 source4/lib/messaging/messaging_internal.h         |  36 ++++++
 source4/lib/messaging/messaging_send.c             | 115 +++++++++++++++++
 source4/lib/messaging/wscript_build                |   6 +
 source4/rpc_server/dcesrv_auth.c                   |   4 +-
 source4/smb_server/smb/sesssetup.c                 |   4 +-
 17 files changed, 361 insertions(+), 120 deletions(-)
 create mode 100644 docs-xml/smbdotconf/logon/autheventnotification.xml
 create mode 100644 source4/lib/messaging/messaging_internal.h
 create mode 100644 source4/lib/messaging/messaging_send.c

diff --git a/auth/auth_log.c b/auth/auth_log.c
index 54a3f3b..9f1cc8b 100644
--- a/auth/auth_log.c
+++ b/auth/auth_log.c
@@ -51,6 +51,11 @@
 #include "lib/util/util_str_escape.h"
 #include "libcli/security/dom_sid.h"
 #include "libcli/security/security_token.h"
+#include "librpc/gen_ndr/server_id.h"
+#include "source4/lib/messaging/messaging.h"
+#include "source4/lib/messaging/irpc.h"
+#include "lib/util/server_id_db.h"
+#include "lib/param/param.h"
 
 /*
  * Determine the type of the password supplied for the
@@ -74,11 +79,86 @@ struct json_context {
 	bool error;
 };
 
+static NTSTATUS get_auth_event_server(struct imessaging_context *msg_ctx,
+				      struct server_id *auth_event_server)
+{
+	NTSTATUS status;
+	TALLOC_CTX *frame = talloc_stackframe();
+	unsigned num_servers, i;
+	struct server_id *servers;
+
+	status = irpc_servers_byname(msg_ctx, frame,
+				     "auth_event",
+				     &num_servers, &servers);
+
+	if (!NT_STATUS_IS_OK(status)) {
+		DBG_NOTICE("Failed to find 'auth_event' registered on the "
+			   "message bus to send JSON authentication events to: %s\n",
+			   nt_errstr(status));
+		TALLOC_FREE(frame);
+		return status;
+	}
+
+	/*
+	 * Select the first server that is listening, because
+	 * we get connection refused as
+	 * NT_STATUS_OBJECT_NAME_NOT_FOUND without waiting
+	 */
+	for (i = 0; i < num_servers; i++) {
+		status = imessaging_send(msg_ctx, servers[i], MSG_PING,
+					 &data_blob_null);
+		if (NT_STATUS_IS_OK(status)) {
+			TALLOC_FREE(frame);
+			*auth_event_server = servers[i];
+		}
+	}
+	if (i == num_servers) {
+		DBG_NOTICE("Failed to find a running 'auth_event' server "
+			   "registered on the message bus to send JSON "
+			   "authentication events to\n");
+	}
+	TALLOC_FREE(frame);
+	return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+}
+
+static void auth_message_send(struct imessaging_context *msg_ctx,
+			      const char *json)
+{
+	static struct server_id	auth_event_server;
+	NTSTATUS status;
+	DATA_BLOB json_blob = data_blob_string_const(json);
+	if (msg_ctx == NULL) {
+		return;
+	}
+
+	if (auth_event_server.pid == 0) {
+		status = get_auth_event_server(msg_ctx, &auth_event_server);
+		if (!NT_STATUS_IS_OK(status)) {
+			return;
+		}
+	}
+
+	status = imessaging_send(msg_ctx, auth_event_server, MSG_AUTH_LOG,
+				 &json_blob);
+
+	/* If the server crashed, try to find it again */
+	if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
+		status = get_auth_event_server(msg_ctx, &auth_event_server);
+		if (!NT_STATUS_IS_OK(status)) {
+			return;
+		}
+		imessaging_send(msg_ctx, auth_event_server, MSG_AUTH_LOG,
+				&json_blob);
+
+	}
+}
+
 /*
- * Write the json object to the debug lines.
+ * Write the json object to the debug logs.
  *
  */
-static void log_json( struct json_context *context,
+static void log_json(struct imessaging_context *msg_ctx,
+		     struct json_context *context,
 		     const char *type, int debug_class, int debug_level)
 {
 	char* json = NULL;
@@ -95,6 +175,7 @@ static void log_json( struct json_context *context,
 	}
 
 	DEBUGC( debug_class, debug_level, ( "JSON %s: %s\n", type, json));
+	auth_message_send(msg_ctx, json);
 
 	if (json) {
 		free(json);
@@ -324,6 +405,8 @@ static void add_sid(struct json_context *context,
  *           \t\(.Authentication.localAddress)"'
  */
 static void log_authentication_event_json(
+	                struct imessaging_context *msg_ctx,
+			struct loadparm_context *lp_ctx,
 			const struct auth_usersupplied_info *ui,
 			NTSTATUS status,
 			const char *domain_name,
@@ -361,7 +444,7 @@ static void log_authentication_event_json(
 	add_string(&authentication, "passwordType", get_password_type( ui));
 	add_object(&context,AUTH_JSON_TYPE, &authentication);
 
-	log_json(&context, AUTH_JSON_TYPE, DBGC_AUTH_AUDIT, debug_level);
+	log_json(msg_ctx, &context, AUTH_JSON_TYPE, DBGC_AUTH_AUDIT, debug_level);
 	free_json_context(&context);
 }
 
@@ -386,6 +469,8 @@ static void log_authentication_event_json(
  *
  */
 static void log_successful_authz_event_json(
+				struct imessaging_context *msg_ctx,
+				struct loadparm_context *lp_ctx,
 				const struct tsocket_address *remote,
 				const struct tsocket_address *local,
 				const char *service_description,
@@ -422,7 +507,8 @@ static void log_successful_authz_event_json(
 	add_string(&authorization, "accountFlags", account_flags);
 	add_object(&context,AUTHZ_JSON_TYPE, &authorization);
 
-	log_json(&context,
+	log_json(msg_ctx,
+		 &context,
 		 AUTHZ_JSON_TYPE,
 		 DBGC_AUTH_AUDIT,
 		 debug_level);
@@ -431,7 +517,29 @@ static void log_successful_authz_event_json(
 
 #else
 
+static void log_no_json(struct imessaging_context *msg_ctx,
+                        struct loadparm_context *lp_ctx)
+{
+	if (msg_ctx && lp_ctx && lpcfg_auth_event_notification(lp_ctx)) {
+		static bool auth_event_logged = false;
+		if (auth_event_logged == false) {
+			auth_event_logged = true;
+			DBG_ERR("auth event notification = true but Samba was not compiled with jansson\n");
+		}
+	} else {
+		static bool json_logged = false;
+		if (json_logged == false) {
+			json_logged = true;
+			DBG_NOTICE("JSON auth logs not available unless compiled with jansson\n");
+		}
+	}
+
+	return;
+}
+
 static void log_authentication_event_json(
+	                struct imessaging_context *msg_ctx,
+			struct loadparm_context *lp_ctx,
 			const struct auth_usersupplied_info *ui,
 			NTSTATUS status,
 			const char *domain_name,
@@ -440,10 +548,13 @@ static void log_authentication_event_json(
 			struct dom_sid *sid,
 			int debug_level)
 {
+	log_no_json(msg_ctx, lp_ctx);
 	return;
 }
 
 static void log_successful_authz_event_json(
+				struct imessaging_context *msg_ctx,
+				struct loadparm_context *lp_ctx,
 				const struct tsocket_address *remote,
 				const struct tsocket_address *local,
 				const char *service_description,
@@ -452,6 +563,7 @@ static void log_successful_authz_event_json(
 				struct auth_session_info *session_info,
 				int debug_level)
 {
+	log_no_json(msg_ctx, lp_ctx);
 	return;
 }
 
@@ -585,7 +697,9 @@ static void log_authentication_event_human_readable(
  * NOTE: msg_ctx and lp_ctx is optional, but when supplied allows streaming the
  * authentication events over the message bus.
  */
-void log_authentication_event( const struct auth_usersupplied_info *ui,
+void log_authentication_event(struct imessaging_context *msg_ctx,
+			      struct loadparm_context *lp_ctx,
+			      const struct auth_usersupplied_info *ui,
 			      NTSTATUS status,
 			      const char *domain_name,
 			      const char *account_name,
@@ -611,8 +725,10 @@ void log_authentication_event( const struct auth_usersupplied_info *ui,
 							sid,
 							debug_level);
 	}
-	if (CHECK_DEBUGLVLC( DBGC_AUTH_AUDIT_JSON, debug_level)) {
-		log_authentication_event_json(ui,
+	if (CHECK_DEBUGLVLC( DBGC_AUTH_AUDIT_JSON, debug_level) ||
+	    (msg_ctx && lp_ctx && lpcfg_auth_event_notification(lp_ctx))) {
+		log_authentication_event_json(msg_ctx, lp_ctx,
+					      ui,
 					      status,
 					      domain_name,
 					      account_name,
@@ -686,7 +802,9 @@ static void log_successful_authz_event_human_readable(
  * NOTE: msg_ctx and lp_ctx is optional, but when supplied allows streaming the
  * authentication events over the message bus.
  */
-void log_successful_authz_event(const struct tsocket_address *remote,
+void log_successful_authz_event(struct imessaging_context *msg_ctx,
+				struct loadparm_context *lp_ctx,
+				const struct tsocket_address *remote,
 				const struct tsocket_address *local,
 				const char *service_description,
 				const char *auth_type,
@@ -709,8 +827,10 @@ void log_successful_authz_event(const struct tsocket_address *remote,
 							  session_info,
 							  debug_level);
 	}
-	if (CHECK_DEBUGLVLC( DBGC_AUTH_AUDIT_JSON, debug_level)) {
-		log_successful_authz_event_json(remote,
+	if (CHECK_DEBUGLVLC( DBGC_AUTH_AUDIT_JSON, debug_level) ||
+	    (msg_ctx && lp_ctx && lpcfg_auth_event_notification(lp_ctx))) {
+		log_successful_authz_event_json(msg_ctx, lp_ctx,
+						remote,
 						local,
 						service_description,
 						auth_type,
diff --git a/auth/common_auth.h b/auth/common_auth.h
index 331f112..2fc687e 100644
--- a/auth/common_auth.h
+++ b/auth/common_auth.h
@@ -153,14 +153,38 @@ struct auth4_context {
 #define AUTHZ_TRANSPORT_PROTECTION_SEAL "SEAL"
 #define AUTHZ_TRANSPORT_PROTECTION_SIGN "SIGN"
 
-void log_authentication_event(const struct auth_usersupplied_info *ui,
+/*
+ * Log details of an authentication attempt.
+ * Successful and unsuccessful attempts are logged.
+ *
+ * NOTE: msg_ctx and lp_ctx is optional, but when supplied allows streaming the
+ * authentication events over the message bus.
+ */
+void log_authentication_event(struct imessaging_context *msg_ctx,
+			      struct loadparm_context *lp_ctx,
+			      const struct auth_usersupplied_info *ui,
 			      NTSTATUS status,
 			      const char *account_name,
 			      const char *domain_name,
 			      const char *unix_username,
 			      struct dom_sid *sid);
 
-void log_successful_authz_event(const struct tsocket_address *remote,
+/*
+ * Log details of a successful authorization to a service.
+ *
+ * Only successful authorizations are logged.  For clarity:
+ * - NTLM bad passwords will be recorded by log_authentication_event
+ * - Kerberos decrypt failures need to be logged in gensec_gssapi et al
+ *
+ * The service may later refuse authorization due to an ACL.
+ *
+ *
+ * NOTE: msg_ctx and lp_ctx is optional, but when supplied allows streaming the
+ * authorization events over the message bus.
+ */
+void log_successful_authz_event(struct imessaging_context *msg_ctx,
+				struct loadparm_context *lp_ctx,
+				const struct tsocket_address *remote,
 				const struct tsocket_address *local,
 				const char *service_description,
 				const char *auth_type,
diff --git a/auth/gensec/gensec.c b/auth/gensec/gensec.c
index 14fd9f4..48ccea1 100644
--- a/auth/gensec/gensec.c
+++ b/auth/gensec/gensec.c
@@ -233,7 +233,9 @@ static void log_successful_gensec_authz_event(struct gensec_security *gensec_sec
 	} else {
 		transport_protection = AUTHZ_TRANSPORT_PROTECTION_NONE;
 	}
-	log_successful_authz_event(remote, local,
+	log_successful_authz_event(gensec_security->auth_context->msg_ctx,
+				   gensec_security->auth_context->lp_ctx,
+				   remote, local,
 				   service_description,
 				   final_auth_type,
 				   transport_protection,
diff --git a/auth/wscript_build b/auth/wscript_build
index 30f8bf9..d110626 100644
--- a/auth/wscript_build
+++ b/auth/wscript_build
@@ -2,7 +2,7 @@
 
 bld.SAMBA_LIBRARY('common_auth',
                   source='auth_sam_reply.c wbc_auth_util.c auth_log.c',
-                  deps='talloc samba-security samba-util util_str_escape LIBTSOCKET jansson',
+                  deps='talloc samba-security samba-util util_str_escape LIBTSOCKET jansson MESSAGING_SEND server_id_db ',
                   private_library=True
                   )
 
diff --git a/docs-xml/smbdotconf/logon/autheventnotification.xml b/docs-xml/smbdotconf/logon/autheventnotification.xml
new file mode 100644
index 0000000..a42d98c
--- /dev/null
+++ b/docs-xml/smbdotconf/logon/autheventnotification.xml
@@ -0,0 +1,17 @@
+<samba:parameter name="auth event notification"
+                 context="G"
+                 type="boolean"
+                 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
+<description>
+	<para>When enabled, this option causes Samba (acting as an
+	Active Directory Domain Controller) to stream authentication
+	events across the internal message bus.  Scripts built using
+	Samba's python bindings can listen to these events by
+	registering as the service
+	<filename moreinfo="none">auth_event</filename>.</para>
+
+	<para>Samba must be compiled with glib-json support for this option to be effective</para>
+</description>
+
+<value type="default">no</value>
+</samba:parameter>
diff --git a/source3/auth/auth.c b/source3/auth/auth.c
index 19115e8..682e34c 100644
--- a/source3/auth/auth.c
+++ b/source3/auth/auth.c
@@ -306,7 +306,8 @@ NTSTATUS auth_check_ntlm_password(TALLOC_CTX *mem_ctx,
 		sid = (struct dom_sid) {0};
 	}
 
-	log_authentication_event(user_info, nt_status,
+	log_authentication_event(NULL, NULL,
+				 user_info, nt_status,
 				 server_info->info3->base.logon_domain.string,
 				 server_info->info3->base.account_name.string,
 				 unix_username, &sid);
@@ -336,7 +337,7 @@ fail:
 		  user_info->client.account_name, user_info->mapped.account_name,
 		  nt_errstr(nt_status)));
 
-	log_authentication_event(user_info, nt_status, NULL, NULL, NULL, NULL);
+	log_authentication_event(NULL, NULL, user_info, nt_status, NULL, NULL, NULL, NULL);
 
 	ZERO_STRUCTP(pserver_info);
 
diff --git a/source3/auth/auth_generic.c b/source3/auth/auth_generic.c
index 5631c85..477c2a8 100644
--- a/source3/auth/auth_generic.c
+++ b/source3/auth/auth_generic.c
@@ -434,7 +434,9 @@ NTSTATUS auth_check_password_session_info(struct auth4_context *auth_context,
 	 * authorizations consistently (be they NLTM, NTLMSSP or
 	 * krb5) we log this info again.
 	 */
-	log_successful_authz_event(user_info->remote_host,
+	log_successful_authz_event(auth_context->msg_ctx,
+				   auth_context->lp_ctx,
+				   user_info->remote_host,
 				   user_info->local_host,
 				   user_info->service_description,
 				   user_info->auth_description,
diff --git a/source3/rpc_server/srv_pipe.c b/source3/rpc_server/srv_pipe.c
index c8b0fdc..95e2ceb 100644
--- a/source3/rpc_server/srv_pipe.c
+++ b/source3/rpc_server/srv_pipe.c
@@ -836,7 +836,8 @@ static bool api_pipe_bind_req(struct pipes_struct *p,
 		 * covered ncacn_np pass-through auth, and anonymous
 		 * DCE/RPC (eg epmapper, netlogon etc)
 		 */
-		log_successful_authz_event(p->remote_address,
+		log_successful_authz_event(NULL, NULL,
+					   p->remote_address,
 					   p->local_address,
 					   table->name,
 					   derpc_transport_string_by_transport(p->transport),
diff --git a/source4/auth/ntlm/auth.c b/source4/auth/ntlm/auth.c
index 9a0345c..fddb512 100644
--- a/source4/auth/ntlm/auth.c
+++ b/source4/auth/ntlm/auth.c
@@ -445,7 +445,9 @@ _PUBLIC_ NTSTATUS auth_check_password_recv(struct tevent_req *req,
 			 state->user_info->mapped.account_name,
 			 nt_errstr(status)));
 
-		log_authentication_event(state->user_info, status,
+		log_authentication_event(state->auth_ctx->msg_ctx,
+					 state->auth_ctx->lp_ctx,
+					 state->user_info, status,
 					 NULL, NULL, NULL, NULL);
 		tevent_req_received(req);
 		return status;
@@ -457,7 +459,9 @@ _PUBLIC_ NTSTATUS auth_check_password_recv(struct tevent_req *req,
 		 state->user_info_dc->info->domain_name,
 		 state->user_info_dc->info->account_name));
 
-	log_authentication_event(state->user_info, status,
+	log_authentication_event(state->auth_ctx->msg_ctx,
+				 state->auth_ctx->lp_ctx,
+				 state->user_info, status,
 				 state->user_info_dc->info->domain_name,
 				 state->user_info_dc->info->account_name,
 				 NULL,
diff --git a/source4/auth/ntlm/auth_simple.c b/source4/auth/ntlm/auth_simple.c
index 4e5780f..3d2dbb9 100644
--- a/source4/auth/ntlm/auth_simple.c
+++ b/source4/auth/ntlm/auth_simple.c
@@ -131,7 +131,9 @@ _PUBLIC_ NTSTATUS authenticate_ldap_simple_bind(TALLOC_CTX *mem_ctx,
 		talloc_steal(mem_ctx, *session_info);
 	}
 
-	log_successful_authz_event(remote_address,
+	log_successful_authz_event(auth_context->msg_ctx,
+				   auth_context->lp_ctx,
+				   remote_address,
 				   local_address,
 				   "LDAP",
 				   "simple bind",
diff --git a/source4/ldap_server/ldap_backend.c b/source4/ldap_server/ldap_backend.c
index 7aa51f2..d20d586 100644
--- a/source4/ldap_server/ldap_backend.c
+++ b/source4/ldap_server/ldap_backend.c
@@ -1285,7 +1285,9 @@ NTSTATUS ldapsrv_do_call(struct ldapsrv_call *call)
 				transport_protection = AUTHZ_TRANSPORT_PROTECTION_TLS;
 			}
 
-			log_successful_authz_event(call->conn->connection->remote_address,
+			log_successful_authz_event(call->conn->connection->msg_ctx,
+						   call->conn->connection->lp_ctx,
+						   call->conn->connection->remote_address,
 						   call->conn->connection->local_address,
 						   "LDAP",
 						   "no bind",
diff --git a/source4/lib/messaging/messaging.c b/source4/lib/messaging/messaging.c
index 84df934..80ef597 100644
--- a/source4/lib/messaging/messaging.c
+++ b/source4/lib/messaging/messaging.c
@@ -24,6 +24,7 @@
 #include "lib/util/server_id.h"
 #include "system/filesys.h"
 #include "messaging/messaging.h"
+#include "messaging/messaging_internal.h"
 #include "../lib/util/dlinklist.h"
 #include "lib/socket/socket.h"
 #include "librpc/gen_ndr/ndr_irpc.h"
@@ -55,22 +56,6 @@ struct irpc_request {
 	} incoming;
 };
 
-struct imessaging_context {
-	struct imessaging_context *prev, *next;
-	struct tevent_context *ev;
-	struct server_id server_id;
-	const char *sock_dir;
-	const char *lock_dir;
-	struct dispatch_fn **dispatch;
-	uint32_t num_types;
-	struct idr_context *dispatch_tree;
-	struct irpc_list *irpc;
-	struct idr_context *idr;
-	struct server_id_db *names;
-	struct timeval start_time;
-	void *msg_dgm_ref;
-};
-
 /* we have a linked list of dispatch handlers for each msg_type that
    this messaging server can deal with */
 struct dispatch_fn {
@@ -246,68 +231,6 @@ void imessaging_deregister(struct imessaging_context *msg, uint32_t msg_type, vo
 }
 
 /*
-  Send a message to a particular server
-*/
-NTSTATUS imessaging_send(struct imessaging_context *msg, struct server_id server,
-			uint32_t msg_type, const DATA_BLOB *data)
-{
-	uint8_t hdr[MESSAGE_HDR_LENGTH];
-	struct iovec iov[2];
-	int num_iov, ret;
-	pid_t pid;
-	void *priv;
-
-	if (!cluster_node_equal(&msg->server_id, &server)) {
-		/* No cluster in source4... */
-		return NT_STATUS_OK;
-	}
-
-	message_hdr_put(hdr, msg_type, msg->server_id, server);
-
-	iov[0] = (struct iovec) { .iov_base = &hdr, .iov_len = sizeof(hdr) };
-	num_iov = 1;
-
-	if (data != NULL) {
-		iov[1] = (struct iovec) { .iov_base = data->data,
-					  .iov_len = data->length };
-		num_iov += 1;
-	}
-
-	pid = server.pid;
-	if (pid == 0) {
-		pid = getpid();
-	}
-
-	ret = messaging_dgm_send(pid, iov, num_iov, NULL, 0);
-
-	if (ret == EACCES) {
-		priv = root_privileges();
-		ret = messaging_dgm_send(pid, iov, num_iov, NULL, 0);
-		TALLOC_FREE(priv);
-	}
-
-	if (ret != 0) {
-		return map_nt_error_from_unix_common(ret);
-	}
-	return NT_STATUS_OK;
-}
-
-/*
-  Send a message to a particular server, with the message containing a single pointer
-*/
-NTSTATUS imessaging_send_ptr(struct imessaging_context *msg, struct server_id server,
-			    uint32_t msg_type, void *ptr)
-{
-	DATA_BLOB blob;
-
-	blob.data = (uint8_t *)&ptr;
-	blob.length = sizeof(void *);
-
-	return imessaging_send(msg, server, msg_type, &blob);
-}
-
-
-/*
 */
 int imessaging_cleanup(struct imessaging_context *msg)
 {
@@ -793,24 +716,6 @@ NTSTATUS irpc_add_name(struct imessaging_context *msg_ctx, const char *name)
 	return NT_STATUS_OK;
 }
 
-/*
-  return a list of server ids for a server name
-*/
-NTSTATUS irpc_servers_byname(struct imessaging_context *msg_ctx,
-			     TALLOC_CTX *mem_ctx, const char *name,
-			     unsigned *num_servers,
-			     struct server_id **servers)
-{
-	int ret;
-
-	ret = server_id_db_lookup(msg_ctx->names, name, mem_ctx,
-				  num_servers, servers);
-	if (ret != 0) {
-		return map_nt_error_from_unix_common(ret);
-	}
-	return NT_STATUS_OK;
-}
-
 static int all_servers_func(const char *name, unsigned num_servers,
 			    const struct server_id *servers,
 			    void *private_data)
diff --git a/source4/lib/messaging/messaging_internal.h b/source4/lib/messaging/messaging_internal.h
new file mode 100644
index 0000000..93c5c4b
--- /dev/null
+++ b/source4/lib/messaging/messaging_internal.h
@@ -0,0 +1,36 @@
+/*
+   Unix SMB/CIFS implementation.
+
+   Samba internal messaging functions
+
+   Copyright (C) Andrew Tridgell 2004
+
+   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/>.
+*/
+
+struct imessaging_context {
+	struct imessaging_context *prev, *next;
+	struct tevent_context *ev;
+	struct server_id server_id;
+	const char *sock_dir;
+	const char *lock_dir;
+	struct dispatch_fn **dispatch;
+	uint32_t num_types;
+	struct idr_context *dispatch_tree;
+	struct irpc_list *irpc;
+	struct idr_context *idr;
+	struct server_id_db *names;
+	struct timeval start_time;
+	void *msg_dgm_ref;
+};
diff --git a/source4/lib/messaging/messaging_send.c b/source4/lib/messaging/messaging_send.c
new file mode 100644
index 0000000..a4f8281
--- /dev/null
+++ b/source4/lib/messaging/messaging_send.c
@@ -0,0 +1,115 @@
+/*
+   Unix SMB/CIFS implementation.
+
+   Samba internal messaging functions (send).
+
+   Copyright (C) Andrew Tridgell 2004
+
+   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 "messaging/messaging.h"
+#include "messaging/irpc.h"
+#include "../source3/lib/messages_dgm.h"
+#include "../source3/lib/messages_dgm_ref.h"
+#include "../source3/lib/messages_util.h"
+#include "messaging/messaging_internal.h"
+#include "lib/util/server_id_db.h"
+#include "cluster/cluster.h"
+#include "../lib/util/unix_privs.h"
+
+/*
+ * This file is for functions that can be called from auth_log without
+ * depending on all of dcerpc and so cause dep loops.
+ */
+
+/*
+  return a list of server ids for a server name
+*/
+NTSTATUS irpc_servers_byname(struct imessaging_context *msg_ctx,
+			     TALLOC_CTX *mem_ctx, const char *name,
+			     unsigned *num_servers,
+			     struct server_id **servers)
+{
+	int ret;
+
+	ret = server_id_db_lookup(msg_ctx->names, name, mem_ctx,
+				  num_servers, servers);
+	if (ret != 0) {
+		return map_nt_error_from_unix_common(ret);
+	}
+	return NT_STATUS_OK;
+}
+
+/*
+  Send a message to a particular server
+*/
+NTSTATUS imessaging_send(struct imessaging_context *msg, struct server_id server,
+			uint32_t msg_type, const DATA_BLOB *data)
+{
+	uint8_t hdr[MESSAGE_HDR_LENGTH];
+	struct iovec iov[2];
+	int num_iov, ret;
+	pid_t pid;
+	void *priv;
+
+	if (!cluster_node_equal(&msg->server_id, &server)) {
+		/* No cluster in source4... */
+		return NT_STATUS_OK;
+	}
+
+	message_hdr_put(hdr, msg_type, msg->server_id, server);
+
+	iov[0] = (struct iovec) { .iov_base = &hdr, .iov_len = sizeof(hdr) };
+	num_iov = 1;
+
+	if (data != NULL) {
+		iov[1] = (struct iovec) { .iov_base = data->data,
+					  .iov_len = data->length };
+		num_iov += 1;
+	}
+
+	pid = server.pid;
+	if (pid == 0) {
+		pid = getpid();
+	}
+
+	ret = messaging_dgm_send(pid, iov, num_iov, NULL, 0);
+
+	if (ret == EACCES) {
+		priv = root_privileges();
+		ret = messaging_dgm_send(pid, iov, num_iov, NULL, 0);
+		TALLOC_FREE(priv);
+	}
+
+	if (ret != 0) {
+		return map_nt_error_from_unix_common(ret);
+	}
+	return NT_STATUS_OK;
+}
+
+/*
+  Send a message to a particular server, with the message containing a single pointer
+*/
+NTSTATUS imessaging_send_ptr(struct imessaging_context *msg, struct server_id server,
+			    uint32_t msg_type, void *ptr)
+{
+	DATA_BLOB blob;
+
+	blob.data = (uint8_t *)&ptr;
+	blob.length = sizeof(void *);
+
+	return imessaging_send(msg, server, msg_type, &blob);
+}
diff --git a/source4/lib/messaging/wscript_build b/source4/lib/messaging/wscript_build
index 86877af..2b6cf81 100644
--- a/source4/lib/messaging/wscript_build
+++ b/source4/lib/messaging/wscript_build
@@ -1,6 +1,12 @@
 #!/usr/bin/env python
 
 
+bld.SAMBA_LIBRARY('MESSAGING_SEND',
+	source='messaging_send.c',
+	public_deps='messages_util messages_dgm UNIX_PRIVS cluster server_id_db',
+	private_library=True
+	)
+
 bld.SAMBA_LIBRARY('MESSAGING',
 	source='messaging.c',
 	public_deps='samba-util NDR_IRPC UNIX_PRIVS cluster ndr dcerpc messages_util server_id_db talloc_report',
diff --git a/source4/rpc_server/dcesrv_auth.c b/source4/rpc_server/dcesrv_auth.c
index 1ebb514..efcb586 100644
--- a/source4/rpc_server/dcesrv_auth.c
+++ b/source4/rpc_server/dcesrv_auth.c
@@ -62,7 +62,9 @@ bool dcesrv_auth_bind(struct dcesrv_call_state *call)
 		 * covered ncacn_np pass-through auth, and anonymous
 		 * DCE/RPC (eg epmapper, netlogon etc)
 		 */
-		log_successful_authz_event(call->conn->remote_address,
+		log_successful_authz_event(call->conn->msg_ctx,
+					   call->conn->dce_ctx->lp_ctx,
+					   call->conn->remote_address,
 					   call->conn->local_address,
 					   "DCE/RPC",
 					   auth_type,
diff --git a/source4/smb_server/smb/sesssetup.c b/source4/smb_server/smb/sesssetup.c
index ce73a02..4d223f0 100644
--- a/source4/smb_server/smb/sesssetup.c
+++ b/source4/smb_server/smb/sesssetup.c
@@ -54,7 +54,9 @@ void smbsrv_not_spengo_sesssetup_authz_log(struct smbsrv_request *req,
 	local_address = socket_get_local_addr(req->smb_conn->connection->socket,
 					      frame);
 
-	log_successful_authz_event(remote_address,
+	log_successful_authz_event(req->smb_conn->connection->msg_ctx,
+				   req->smb_conn->lp_ctx,
+				   remote_address,
 				   local_address,
 				   "SMB",
 				   "bare-NTLM",
-- 
2.7.4

-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 473 bytes
Desc: OpenPGP digital signature
URL: <http://lists.samba.org/pipermail/samba-technical/attachments/20170313/c53ec8f8/signature-0001.sig>


More information about the samba-technical mailing list