[Patches] Windows 10 cannot logon on Samba NT4 domain (bug #13328)

Stefan Metzmacher metze at samba.org
Thu Mar 15 19:40:07 UTC 2018


Hi,

here are Patches to make sure we don't report the
SMB2_SESSION_FLAG_IS_GUEST (and SMB_SETUP_GUEST)
for anonymous authentication (username="").

Windows 10/Server 2016 1709 got more picky on the (SMB2/3) client side
regarding accepting guest authentication.
As a result it's not possible to use a Windows 10 client in
a Samba NT4 (classic) domain, if SMB2/3 is enabled.
The 2nd problem is that SMB1 is not installed on Windows 10 by default.

While it seems to be a trivial to remove the GUEST bits
for anonymous authentication it turns out to be quite tricky
because of all the legacy in the source3/auth stack.

The largest problem is that auth_serversupplied_info contains
some unix token/name elements and there are a lot of code pathes
to the final auth_session_info.

The source4 and common auth stack uses auth_user_info_dc instead
of auth_serversupplied_info and the has a central place to
construct the auth_session_info including the optional unix_token.

This patchset introduces auth3_user_info_dc_add_hints() and
auth3_session_info_create():

    These functions make it possible to construct a full
    auth_session_info
    from the information available from an auth_user_info_dc structure.

    This has all the logic from create_local_token() that is used
    to transform a auth_serversupplied_info to a full auth_session_info.

    In order to workarround the restriction that auth_user_info_dc
    doesn't contain hints for the unix token/name, we use
    the special S-1-5-88 (Unix_NFS) sids:

     - S-1-5-88-1-Y gives the uid=Y
     - S-1-5-88-2-Y gives the gid=Y
     - S-1-5-88-3-Y gives flags=Y AUTH3_UNIX_HINT_*

    The currently implemented flags are:

    - AUTH3_UNIX_HINT_QUALIFIED_NAME
      unix_name = DOMAIN+ACCOUNT

    - AUTH3_UNIX_HINT_ISLOLATED_NAME
      unix_name = ACCOUNT

    - AUTH3_UNIX_HINT_DONT_TRANSLATE_FROM_SIDS
      Don't translate the nt token SIDS into uid/gids
      using sid mapping.

    - AUTH3_UNIX_HINT_DONT_TRANSLATE_TO_SIDS
      Don't translate the unix token uid/gids to S-1-22-X-Y SIDS

    - AUTH3_UNIX_HINT_DONT_EXPAND_UNIX_GROUPS
      The unix token won't get expanded gid values
      from getgroups_unix_user()

This makes it possible to use the common auth_system_user_info_dc() and
auth_anonymous_user_info_dc(). It will also make further improvements
possible in order to get rid of auth_serversupplied_info while still
keeping most of the current logic.

Most of it is already reviewed by Ralph, but the regression test is missing.

Please review and push :-)

Thanks!
metze
-------------- next part --------------
From 85df9e5ee4a365e01a3538325441c7f357a16c53 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Thu, 15 Mar 2018 17:40:07 +0100
Subject: [PATCH 01/19] s3:torture: add SMB2-ANONYMOUS which asserts no GUEST
 bit for anonymous

BUG: https://bugzilla.samba.org/show_bug.cgi?id=13328

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 source3/torture/proto.h     |  1 +
 source3/torture/test_smb2.c | 42 ++++++++++++++++++++++++++++++++++++++++++
 source3/torture/torture.c   |  1 +
 3 files changed, 44 insertions(+)

diff --git a/source3/torture/proto.h b/source3/torture/proto.h
index 7ab2fe1..45870c9 100644
--- a/source3/torture/proto.h
+++ b/source3/torture/proto.h
@@ -95,6 +95,7 @@ bool run_nttrans_create(int dummy);
 bool run_nttrans_fsctl(int dummy);
 bool run_smb2_basic(int dummy);
 bool run_smb2_negprot(int dummy);
+bool run_smb2_anonymous(int dummy);
 bool run_smb2_session_reconnect(int dummy);
 bool run_smb2_tcon_dependence(int dummy);
 bool run_smb2_multi_channel(int dummy);
diff --git a/source3/torture/test_smb2.c b/source3/torture/test_smb2.c
index 297c3ab..897d034 100644
--- a/source3/torture/test_smb2.c
+++ b/source3/torture/test_smb2.c
@@ -24,6 +24,7 @@
 #include "../libcli/smb/smbXcli_base.h"
 #include "libcli/security/security.h"
 #include "libsmb/proto.h"
+#include "auth/credentials/credentials.h"
 #include "auth/gensec/gensec.h"
 #include "auth_generic.h"
 #include "../librpc/ndr/libndr.h"
@@ -274,6 +275,47 @@ bool run_smb2_negprot(int dummy)
 	return true;
 }
 
+bool run_smb2_anonymous(int dummy)
+{
+	struct cli_state *cli = NULL;
+	NTSTATUS status;
+	struct cli_credentials *anon_creds = NULL;
+	bool guest = false;
+
+	printf("Starting SMB2-ANONYMOUS\n");
+
+	if (!torture_init_connection(&cli)) {
+		return false;
+	}
+
+	status = smbXcli_negprot(cli->conn, cli->timeout,
+				 PROTOCOL_SMB2_02, PROTOCOL_LATEST);
+	if (!NT_STATUS_IS_OK(status)) {
+		printf("smbXcli_negprot returned %s\n", nt_errstr(status));
+		return false;
+	}
+
+	anon_creds = cli_credentials_init_anon(talloc_tos());
+	if (anon_creds == NULL) {
+		printf("cli_credentials_init_anon failed\n");
+		return false;
+	}
+
+	status = cli_session_setup_creds(cli, anon_creds);
+	if (!NT_STATUS_IS_OK(status)) {
+		printf("cli_session_setup returned %s\n", nt_errstr(status));
+		return false;
+	}
+
+	guest = smbXcli_session_is_guest(cli->smb2.session);
+	if (guest) {
+		printf("anonymous session should not have guest authentication\n");
+		return false;
+	}
+
+	return true;
+}
+
 bool run_smb2_session_reconnect(int dummy)
 {
 	struct cli_state *cli1;
diff --git a/source3/torture/torture.c b/source3/torture/torture.c
index ae502f28..df6604d 100644
--- a/source3/torture/torture.c
+++ b/source3/torture/torture.c
@@ -11588,6 +11588,7 @@ static struct {
 	{ "NOTIFY-ONLINE", run_notify_online },
 	{ "SMB2-BASIC", run_smb2_basic },
 	{ "SMB2-NEGPROT", run_smb2_negprot },
+	{ "SMB2-ANONYMOUS", run_smb2_anonymous },
 	{ "SMB2-SESSION-RECONNECT", run_smb2_session_reconnect },
 	{ "SMB2-TCON-DEPENDENCE", run_smb2_tcon_dependence },
 	{ "SMB2-MULTI-CHANNEL", run_smb2_multi_channel },
-- 
1.9.1


From 03d4bf77f6d5209054bbab86927aa0e307ecd9b7 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Thu, 15 Mar 2018 18:04:21 +0100
Subject: [PATCH 02/19] s3:selftest: run SMB2-ANONYMOUS

This fails against a non AD DC smbd.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=13328

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 selftest/knownfail.d/anonymous-guest | 1 +
 source3/selftest/tests.py            | 1 +
 2 files changed, 2 insertions(+)
 create mode 100644 selftest/knownfail.d/anonymous-guest

diff --git a/selftest/knownfail.d/anonymous-guest b/selftest/knownfail.d/anonymous-guest
new file mode 100644
index 0000000..a134cec
--- /dev/null
+++ b/selftest/knownfail.d/anonymous-guest
@@ -0,0 +1 @@
+^samba3.smbtorture_s3.*nt4_dc.*.SMB2-ANONYMOUS.smbtorture
diff --git a/source3/selftest/tests.py b/source3/selftest/tests.py
index 5232aec..402f44f 100755
--- a/source3/selftest/tests.py
+++ b/source3/selftest/tests.py
@@ -78,6 +78,7 @@ tests = ["FDPASS", "LOCK1", "LOCK2", "LOCK3", "LOCK4", "LOCK5", "LOCK6", "LOCK7"
         "UID-REGRESSION-TEST", "SHORTNAME-TEST",
         "CASE-INSENSITIVE-CREATE", "SMB2-BASIC", "NTTRANS-FSCTL", "SMB2-NEGPROT",
         "SMB2-SESSION-REAUTH", "SMB2-SESSION-RECONNECT", "SMB2-FTRUNCATE",
+        "SMB2-ANONYMOUS",
         "CLEANUP1",
         "CLEANUP2",
         "CLEANUP4",
-- 
1.9.1


From 80236944d18916bff9f253d6e804b328a82c370d Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Wed, 14 Mar 2018 11:44:49 +0100
Subject: [PATCH 03/19] libcli/security: only announce a session as GUEST if
 'Builtin\Guests' is there without 'Authenticated User'

BUG: https://bugzilla.samba.org/show_bug.cgi?id=13328

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 libcli/security/session.c | 18 +++++++++++-------
 1 file changed, 11 insertions(+), 7 deletions(-)

diff --git a/libcli/security/session.c b/libcli/security/session.c
index 0fbb87d..f17e884 100644
--- a/libcli/security/session.c
+++ b/libcli/security/session.c
@@ -26,6 +26,9 @@
 enum security_user_level security_session_user_level(struct auth_session_info *session_info,
 						     const struct dom_sid *domain_sid)
 {
+	bool authenticated = false;
+	bool guest = false;
+
 	if (!session_info) {
 		return SECURITY_ANONYMOUS;
 	}
@@ -38,8 +41,13 @@ enum security_user_level security_session_user_level(struct auth_session_info *s
 		return SECURITY_ANONYMOUS;
 	}
 
-	if (security_token_has_builtin_guests(session_info->security_token)) {
-		return SECURITY_GUEST;
+	authenticated = security_token_has_nt_authenticated_users(session_info->security_token);
+	guest = security_token_has_builtin_guests(session_info->security_token);
+	if (!authenticated) {
+		if (guest) {
+			return SECURITY_GUEST;
+		}
+		return SECURITY_ANONYMOUS;
 	}
 
 	if (security_token_has_builtin_administrators(session_info->security_token)) {
@@ -60,9 +68,5 @@ enum security_user_level security_session_user_level(struct auth_session_info *s
 		return SECURITY_DOMAIN_CONTROLLER;
 	}
 
-	if (security_token_has_nt_authenticated_users(session_info->security_token)) {
-		return SECURITY_USER;
-	}
-
-	return SECURITY_ANONYMOUS;
+	return SECURITY_USER;
 }
-- 
1.9.1


From 47ef4903ac20d5ea86e1f15ea2611d09e59a3bdb Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Thu, 1 Mar 2018 18:05:28 +0100
Subject: [PATCH 04/19] s3:auth: remove unused auth_serversupplied_info->system

BUG: https://bugzilla.samba.org/show_bug.cgi?id=13328

Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Ralph Boehme <slow at samba.org>
---
 source3/auth/auth_util.c | 1 -
 source3/include/auth.h   | 1 -
 2 files changed, 2 deletions(-)

diff --git a/source3/auth/auth_util.c b/source3/auth/auth_util.c
index 4b20261..adc3bc2 100644
--- a/source3/auth/auth_util.c
+++ b/source3/auth/auth_util.c
@@ -1024,7 +1024,6 @@ static struct auth_serversupplied_info *copy_session_info_serverinfo_guest(TALLO
 	SMB_ASSERT(src->unix_info);
 
 	dst->guest = true;
-	dst->system = false;
 
 	/* This element must be provided to convert back to an
 	 * auth_serversupplied_info.  This needs to be from the
diff --git a/source3/include/auth.h b/source3/include/auth.h
index b7223c1..d305537 100644
--- a/source3/include/auth.h
+++ b/source3/include/auth.h
@@ -30,7 +30,6 @@ struct extra_auth_info {
 
 struct auth_serversupplied_info {
 	bool guest;
-	bool system;
 
 	struct security_unix_token utok;
 
-- 
1.9.1


From 1d5ef7cf7e5f6e61af19698d4e40469f163cbea0 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Fri, 2 Mar 2018 16:37:58 +0100
Subject: [PATCH 05/19] s3:auth: add the "Unix Groups" sid for the primary gid

The primary gid might not be in the gid array.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=13328

Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Ralph Boehme <slow at samba.org>
---
 source3/auth/auth_util.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/source3/auth/auth_util.c b/source3/auth/auth_util.c
index adc3bc2..24d2e7d 100644
--- a/source3/auth/auth_util.c
+++ b/source3/auth/auth_util.c
@@ -633,7 +633,11 @@ NTSTATUS create_local_token(TALLOC_CTX *mem_ctx,
 	 */
 
 	uid_to_unix_users_sid(session_info->unix_token->uid, &tmp_sid);
+	add_sid_to_array_unique(session_info->security_token, &tmp_sid,
+				&session_info->security_token->sids,
+				&session_info->security_token->num_sids);
 
+	gid_to_unix_groups_sid(session_info->unix_token->gid, &tmp_sid);
 	add_sid_to_array_unique(session_info->security_token, &tmp_sid,
 				&session_info->security_token->sids,
 				&session_info->security_token->num_sids);
-- 
1.9.1


From 04e1f3603e661e087ec79761dd3028360aa10ce8 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Tue, 6 Mar 2018 17:14:34 +0100
Subject: [PATCH 06/19] s3:auth: move add_local_groups() out of
 finalize_local_nt_token()

finalize_local_nt_token() will be used in another place,
were we don't want to add local groups in a following commit.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=13328

Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Ralph Boehme <slow at samba.org>
---
 source3/auth/token_util.c | 22 +++++++++++++++-------
 1 file changed, 15 insertions(+), 7 deletions(-)

diff --git a/source3/auth/token_util.c b/source3/auth/token_util.c
index 03c4b64..e5a12db 100644
--- a/source3/auth/token_util.c
+++ b/source3/auth/token_util.c
@@ -208,6 +208,8 @@ static NTSTATUS add_builtin_administrators(struct security_token *token,
 	return NT_STATUS_OK;
 }
 
+static NTSTATUS add_local_groups(struct security_token *result,
+				 bool is_guest);
 static NTSTATUS finalize_local_nt_token(struct security_token *result,
 					bool is_guest);
 
@@ -323,6 +325,13 @@ NTSTATUS create_local_nt_token_from_info3(TALLOC_CTX *mem_ctx,
 		}
 	}
 
+	status = add_local_groups(usrtok, is_guest);
+	if (!NT_STATUS_IS_OK(status)) {
+		DEBUG(3, ("Failed to add local groups\n"));
+		TALLOC_FREE(usrtok);
+		return status;
+	}
+
 	status = finalize_local_nt_token(usrtok, is_guest);
 	if (!NT_STATUS_IS_OK(status)) {
 		DEBUG(3, ("Failed to finalize nt token\n"));
@@ -392,6 +401,12 @@ struct security_token *create_local_nt_token(TALLOC_CTX *mem_ctx,
 		}
 	}
 
+	status = add_local_groups(result, is_guest);
+	if (!NT_STATUS_IS_OK(status)) {
+		TALLOC_FREE(result);
+		return NULL;
+	}
+
 	status = finalize_local_nt_token(result, is_guest);
 	if (!NT_STATUS_IS_OK(status)) {
 		TALLOC_FREE(result);
@@ -502,13 +517,6 @@ static NTSTATUS finalize_local_nt_token(struct security_token *result,
 	NTSTATUS status;
 	struct acct_info *info;
 
-	/* Add any local groups. */
-
-	status = add_local_groups(result, is_guest);
-	if (!NT_STATUS_IS_OK(status)) {
-		return status;
-	}
-
 	/* Add in BUILTIN sids */
 
 	status = add_sid_to_array(result, &global_sid_World,
-- 
1.9.1


From 8d2748095a27eab2eb18ac011a83e3ec14f4bd61 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Tue, 13 Mar 2018 21:35:48 +0100
Subject: [PATCH 07/19] s3:passdb: handle dom_sid=NULL in
 create_builtin_{users,administrators}()

We should not crash if we're called with NULL.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=13328

Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Ralph Boehme <slow at samba.org>
---
 source3/passdb/pdb_util.c | 10 ++++++----
 1 file changed, 6 insertions(+), 4 deletions(-)

diff --git a/source3/passdb/pdb_util.c b/source3/passdb/pdb_util.c
index bf7b2b8..309eb89 100644
--- a/source3/passdb/pdb_util.c
+++ b/source3/passdb/pdb_util.c
@@ -130,8 +130,9 @@ NTSTATUS create_builtin_users(const struct dom_sid *dom_sid)
 	}
 
 	/* add domain users */
-	if ((IS_DC || (lp_server_role() == ROLE_DOMAIN_MEMBER))
-		&& sid_compose(&dom_users, dom_sid, DOMAIN_RID_USERS))
+	if ((IS_DC || (lp_server_role() == ROLE_DOMAIN_MEMBER)) &&
+	    (dom_sid != NULL) &&
+	    sid_compose(&dom_users, dom_sid, DOMAIN_RID_USERS))
 	{
 		status = add_sid_to_builtin(&global_sid_Builtin_Users,
 					    &dom_users);
@@ -159,8 +160,9 @@ NTSTATUS create_builtin_administrators(const struct dom_sid *dom_sid)
 	}
 
 	/* add domain admins */
-	if ((IS_DC || (lp_server_role() == ROLE_DOMAIN_MEMBER))
-		&& sid_compose(&dom_admins, dom_sid, DOMAIN_RID_ADMINS))
+	if ((IS_DC || (lp_server_role() == ROLE_DOMAIN_MEMBER)) &&
+	    (dom_sid != NULL) &&
+	    sid_compose(&dom_admins, dom_sid, DOMAIN_RID_ADMINS))
 	{
 		status = add_sid_to_builtin(&global_sid_Builtin_Administrators,
 					    &dom_admins);
-- 
1.9.1


From cfd20daac90fa11bf7077c642402b4e425334e09 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Tue, 13 Mar 2018 21:38:27 +0100
Subject: [PATCH 08/19] s3:auth: only call secrets_fetch_domain_sid() once in
 finalize_local_nt_token()

BUG: https://bugzilla.samba.org/show_bug.cgi?id=13328

Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Ralph Boehme <slow at samba.org>
---
 source3/auth/token_util.c | 35 +++++++++++++++++++----------------
 1 file changed, 19 insertions(+), 16 deletions(-)

diff --git a/source3/auth/token_util.c b/source3/auth/token_util.c
index e5a12db..f3d24cd 100644
--- a/source3/auth/token_util.c
+++ b/source3/auth/token_util.c
@@ -190,6 +190,9 @@ static NTSTATUS add_builtin_administrators(struct security_token *token,
 	if ( IS_DC ) {
 		sid_copy( &domadm, get_global_sam_sid() );
 	} else {
+		if (dom_sid == NULL) {
+			return NT_STATUS_INVALID_PARAMETER_MIX;
+		}
 		sid_copy(&domadm, dom_sid);
 	}
 	sid_append_rid( &domadm, DOMAIN_RID_ADMINS );
@@ -513,9 +516,11 @@ static NTSTATUS add_local_groups(struct security_token *result,
 static NTSTATUS finalize_local_nt_token(struct security_token *result,
 					bool is_guest)
 {
-	struct dom_sid dom_sid;
+	struct dom_sid _dom_sid = { 0, };
+	struct dom_sid *domain_sid = NULL;
 	NTSTATUS status;
 	struct acct_info *info;
+	bool ok;
 
 	/* Add in BUILTIN sids */
 
@@ -547,6 +552,16 @@ static NTSTATUS finalize_local_nt_token(struct security_token *result,
 		}
 	}
 
+	become_root();
+	ok = secrets_fetch_domain_sid(lp_workgroup(), &_dom_sid);
+	if (ok) {
+		domain_sid = &_dom_sid;
+	} else {
+		DEBUG(3, ("Failed to fetch domain sid for %s\n",
+			  lp_workgroup()));
+	}
+	unbecome_root();
+
 	info = talloc_zero(talloc_tos(), struct acct_info);
 	if (info == NULL) {
 		DEBUG(0, ("talloc failed!\n"));
@@ -561,18 +576,12 @@ static NTSTATUS finalize_local_nt_token(struct security_token *result,
 	if (!NT_STATUS_IS_OK(status)) {
 
 		become_root();
-		if (!secrets_fetch_domain_sid(lp_workgroup(), &dom_sid)) {
-			status = NT_STATUS_OK;
-			DEBUG(3, ("Failed to fetch domain sid for %s\n",
-				  lp_workgroup()));
-		} else {
-			status = create_builtin_administrators(&dom_sid);
-		}
+		status = create_builtin_administrators(domain_sid);
 		unbecome_root();
 
 		if (NT_STATUS_EQUAL(status, NT_STATUS_PROTOCOL_UNREACHABLE)) {
 			/* Add BUILTIN\Administrators directly to token. */
-			status = add_builtin_administrators(result, &dom_sid);
+			status = add_builtin_administrators(result, domain_sid);
 			if ( !NT_STATUS_IS_OK(status) ) {
 				DEBUG(3, ("Failed to check for local "
 					  "Administrators membership (%s)\n",
@@ -593,13 +602,7 @@ static NTSTATUS finalize_local_nt_token(struct security_token *result,
 	if (!NT_STATUS_IS_OK(status)) {
 
 		become_root();
-		if (!secrets_fetch_domain_sid(lp_workgroup(), &dom_sid)) {
-			status = NT_STATUS_OK;
-			DEBUG(3, ("Failed to fetch domain sid for %s\n",
-				  lp_workgroup()));
-		} else {
-			status = create_builtin_users(&dom_sid);
-		}
+		status = create_builtin_users(domain_sid);
 		unbecome_root();
 
 		if (!NT_STATUS_EQUAL(status, NT_STATUS_PROTOCOL_UNREACHABLE) &&
-- 
1.9.1


From 9832e272f87d030b33069637ac9c8fb79c432f88 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Tue, 6 Mar 2018 23:26:28 +0100
Subject: [PATCH 09/19] s3:auth: add add_builtin_guests() handling to
 finalize_local_nt_token()

We should add Builtin_Guests depending on the current token
not based on 'is_guest'. Even authenticated users can be member
a guest related group and therefore get Builtin_Guests.

Sadly we still need to use 'is_guest' within create_local_nt_token()
as we only have S-1-22-* SIDs there and still need to
add Builtin_Guests.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=13328

Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Ralph Boehme <slow at samba.org>
---
 source3/auth/token_util.c | 122 +++++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 114 insertions(+), 8 deletions(-)

diff --git a/source3/auth/token_util.c b/source3/auth/token_util.c
index f3d24cd..30f2f8d3 100644
--- a/source3/auth/token_util.c
+++ b/source3/auth/token_util.c
@@ -211,6 +211,74 @@ static NTSTATUS add_builtin_administrators(struct security_token *token,
 	return NT_STATUS_OK;
 }
 
+static NTSTATUS add_builtin_guests(struct security_token *token,
+				   const struct dom_sid *dom_sid)
+{
+	struct dom_sid tmp_sid;
+	NTSTATUS status;
+
+	/*
+	 * First check the local GUEST account.
+	 */
+	sid_copy(&tmp_sid, get_global_sam_sid());
+	sid_append_rid(&tmp_sid, DOMAIN_RID_GUEST);
+
+	if (nt_token_check_sid(&tmp_sid, token)) {
+		status = add_sid_to_array_unique(token,
+					&global_sid_Builtin_Guests,
+					&token->sids, &token->num_sids);
+		if (!NT_STATUS_IS_OK(status)) {
+			return status;
+		}
+
+		return NT_STATUS_OK;
+	}
+
+	/*
+	 * First check the local GUESTS group.
+	 */
+	sid_copy(&tmp_sid, get_global_sam_sid());
+	sid_append_rid(&tmp_sid, DOMAIN_RID_GUESTS);
+
+	if (nt_token_check_sid(&tmp_sid, token)) {
+		status = add_sid_to_array_unique(token,
+					&global_sid_Builtin_Guests,
+					&token->sids, &token->num_sids);
+		if (!NT_STATUS_IS_OK(status)) {
+			return status;
+		}
+
+		return NT_STATUS_OK;
+	}
+
+	if (lp_server_role() != ROLE_DOMAIN_MEMBER) {
+		return NT_STATUS_OK;
+	}
+
+	if (dom_sid == NULL) {
+		return NT_STATUS_INVALID_PARAMETER_MIX;
+	}
+
+	/*
+	 * First check the domain GUESTS group.
+	 */
+	sid_copy(&tmp_sid, dom_sid);
+	sid_append_rid(&tmp_sid, DOMAIN_RID_GUESTS);
+
+	if (nt_token_check_sid(&tmp_sid, token)) {
+		status = add_sid_to_array_unique(token,
+					&global_sid_Builtin_Guests,
+					&token->sids, &token->num_sids);
+		if (!NT_STATUS_IS_OK(status)) {
+			return status;
+		}
+
+		return NT_STATUS_OK;
+	}
+
+	return NT_STATUS_OK;
+}
+
 static NTSTATUS add_local_groups(struct security_token *result,
 				 bool is_guest);
 static NTSTATUS finalize_local_nt_token(struct security_token *result,
@@ -416,6 +484,29 @@ struct security_token *create_local_nt_token(TALLOC_CTX *mem_ctx,
 		return NULL;
 	}
 
+	if (is_guest) {
+		/*
+		 * It's ugly, but for now it's
+		 * needed to add Builtin_Guests
+		 * here, the "local" token only
+		 * consist of S-1-22-* SIDs
+		 * and finalize_local_nt_token()
+		 * doesn't have the chance to
+		 * to detect it need to
+		 * add Builtin_Guests via
+		 * add_builtin_guests().
+		 */
+		status = add_sid_to_array_unique(result,
+						 &global_sid_Builtin_Guests,
+						 &result->sids,
+						 &result->num_sids);
+		if (!NT_STATUS_IS_OK(status)) {
+			DEBUG(3, ("Failed to add SID to nt token\n"));
+			TALLOC_FREE(result);
+			return NULL;
+		}
+	}
+
 	return result;
 }
 
@@ -535,14 +626,7 @@ static NTSTATUS finalize_local_nt_token(struct security_token *result,
 		return status;
 	}
 
-	if (is_guest) {
-		status = add_sid_to_array(result, &global_sid_Builtin_Guests,
-					  &result->sids,
-					  &result->num_sids);
-		if (!NT_STATUS_IS_OK(status)) {
-			return status;
-		}
-	} else {
+	if (!is_guest) {
 		status = add_sid_to_array(result,
 					  &global_sid_Authenticated_Users,
 					  &result->sids,
@@ -613,6 +697,28 @@ static NTSTATUS finalize_local_nt_token(struct security_token *result,
 		}
 	}
 
+	/*
+	 * Add BUILTIN\Guests directly to token.
+	 * But only if the token already indicates
+	 * real guest access by:
+	 * - local GUEST account
+	 * - local GUESTS group
+	 * - domain GUESTS group
+	 *
+	 * Even if a user was authenticated, it
+	 * can be member of a guest related group.
+	 */
+	status = add_builtin_guests(result, domain_sid);
+	if (!NT_STATUS_IS_OK(status)) {
+		DEBUG(3, ("Failed to check for local "
+			  "Guests membership (%s)\n",
+			  nt_errstr(status)));
+		/*
+		 * This is a hard error.
+		 */
+		return status;
+	}
+
 	TALLOC_FREE(info);
 
 	/* Deal with local groups */
-- 
1.9.1


From 19e4e387dc1ce5b320c696920d3d2aa227523bbd Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Tue, 6 Mar 2018 23:36:03 +0100
Subject: [PATCH 10/19] s3:auth: don't try to expand system or anonymous tokens
 in finalize_local_nt_token()

BUG: https://bugzilla.samba.org/show_bug.cgi?id=13328

Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Ralph Boehme <slow at samba.org>
---
 source3/auth/token_util.c | 24 ++++++++++++++++++++++++
 1 file changed, 24 insertions(+)

diff --git a/source3/auth/token_util.c b/source3/auth/token_util.c
index 30f2f8d3..6ebfa54 100644
--- a/source3/auth/token_util.c
+++ b/source3/auth/token_util.c
@@ -613,6 +613,13 @@ static NTSTATUS finalize_local_nt_token(struct security_token *result,
 	struct acct_info *info;
 	bool ok;
 
+	result->privilege_mask = 0;
+	result->rights_mask = 0;
+
+	if (result->num_sids == 0) {
+		return NT_STATUS_INVALID_TOKEN;
+	}
+
 	/* Add in BUILTIN sids */
 
 	status = add_sid_to_array(result, &global_sid_World,
@@ -626,6 +633,23 @@ static NTSTATUS finalize_local_nt_token(struct security_token *result,
 		return status;
 	}
 
+	/*
+	 * Don't expand nested groups of system, anonymous etc
+	 *
+	 * Note that they still get SID_WORLD and SID_NETWORK
+	 * for now in order let existing tests pass.
+	 *
+	 * But SYSTEM doesn't get AUTHENTICATED_USERS
+	 * and ANONYMOUS doesn't get BUILTIN GUESTS anymore.
+	 */
+	if (security_token_is_anonymous(result)) {
+		return NT_STATUS_OK;
+	}
+	if (security_token_is_system(result)) {
+		result->privilege_mask = ~0;
+		return NT_STATUS_OK;
+	}
+
 	if (!is_guest) {
 		status = add_sid_to_array(result,
 					  &global_sid_Authenticated_Users,
-- 
1.9.1


From e3feab98e6630945b606d37b9d450ae776f6e6c7 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Tue, 6 Mar 2018 23:40:10 +0100
Subject: [PATCH 11/19] s3:auth: pass AUTH_SESSION_INFO_* flags to
 finalize_local_nt_token()

BUG: https://bugzilla.samba.org/show_bug.cgi?id=13328

Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Ralph Boehme <slow at samba.org>
---
 source3/auth/token_util.c | 58 +++++++++++++++++++++++++++++++----------------
 1 file changed, 39 insertions(+), 19 deletions(-)

diff --git a/source3/auth/token_util.c b/source3/auth/token_util.c
index 6ebfa54..acb916a 100644
--- a/source3/auth/token_util.c
+++ b/source3/auth/token_util.c
@@ -282,7 +282,7 @@ static NTSTATUS add_builtin_guests(struct security_token *token,
 static NTSTATUS add_local_groups(struct security_token *result,
 				 bool is_guest);
 static NTSTATUS finalize_local_nt_token(struct security_token *result,
-					bool is_guest);
+					uint32_t session_info_flags);
 
 NTSTATUS get_user_sid_info3_and_extra(const struct netr_SamInfo3 *info3,
 				      const struct extra_auth_info *extra,
@@ -313,6 +313,7 @@ NTSTATUS create_local_nt_token_from_info3(TALLOC_CTX *mem_ctx,
 					  struct security_token **ntok)
 {
 	struct security_token *usrtok = NULL;
+	uint32_t session_info_flags = 0;
 	NTSTATUS status;
 	int i;
 
@@ -403,7 +404,12 @@ NTSTATUS create_local_nt_token_from_info3(TALLOC_CTX *mem_ctx,
 		return status;
 	}
 
-	status = finalize_local_nt_token(usrtok, is_guest);
+	session_info_flags |= AUTH_SESSION_INFO_DEFAULT_GROUPS;
+	if (!is_guest) {
+		session_info_flags |= AUTH_SESSION_INFO_AUTHENTICATED;
+	}
+
+	status = finalize_local_nt_token(usrtok, session_info_flags);
 	if (!NT_STATUS_IS_OK(status)) {
 		DEBUG(3, ("Failed to finalize nt token\n"));
 		TALLOC_FREE(usrtok);
@@ -427,6 +433,7 @@ struct security_token *create_local_nt_token(TALLOC_CTX *mem_ctx,
 	struct security_token *result = NULL;
 	int i;
 	NTSTATUS status;
+	uint32_t session_info_flags = 0;
 
 	DEBUG(10, ("Create local NT token for %s\n",
 		   sid_string_dbg(user_sid)));
@@ -478,7 +485,12 @@ struct security_token *create_local_nt_token(TALLOC_CTX *mem_ctx,
 		return NULL;
 	}
 
-	status = finalize_local_nt_token(result, is_guest);
+	session_info_flags |= AUTH_SESSION_INFO_DEFAULT_GROUPS;
+	if (!is_guest) {
+		session_info_flags |= AUTH_SESSION_INFO_AUTHENTICATED;
+	}
+
+	status = finalize_local_nt_token(result, session_info_flags);
 	if (!NT_STATUS_IS_OK(status)) {
 		TALLOC_FREE(result);
 		return NULL;
@@ -605,7 +617,7 @@ static NTSTATUS add_local_groups(struct security_token *result,
 }
 
 static NTSTATUS finalize_local_nt_token(struct security_token *result,
-					bool is_guest)
+					uint32_t session_info_flags)
 {
 	struct dom_sid _dom_sid = { 0, };
 	struct dom_sid *domain_sid = NULL;
@@ -620,17 +632,17 @@ static NTSTATUS finalize_local_nt_token(struct security_token *result,
 		return NT_STATUS_INVALID_TOKEN;
 	}
 
-	/* Add in BUILTIN sids */
-
-	status = add_sid_to_array(result, &global_sid_World,
-				  &result->sids, &result->num_sids);
-	if (!NT_STATUS_IS_OK(status)) {
-		return status;
-	}
-	status = add_sid_to_array(result, &global_sid_Network,
-				  &result->sids, &result->num_sids);
-	if (!NT_STATUS_IS_OK(status)) {
-		return status;
+	if (session_info_flags & AUTH_SESSION_INFO_DEFAULT_GROUPS) {
+		status = add_sid_to_array(result, &global_sid_World,
+					  &result->sids, &result->num_sids);
+		if (!NT_STATUS_IS_OK(status)) {
+			return status;
+		}
+		status = add_sid_to_array(result, &global_sid_Network,
+					  &result->sids, &result->num_sids);
+		if (!NT_STATUS_IS_OK(status)) {
+			return status;
+		}
 	}
 
 	/*
@@ -650,7 +662,7 @@ static NTSTATUS finalize_local_nt_token(struct security_token *result,
 		return NT_STATUS_OK;
 	}
 
-	if (!is_guest) {
+	if (session_info_flags & AUTH_SESSION_INFO_AUTHENTICATED) {
 		status = add_sid_to_array(result,
 					  &global_sid_Authenticated_Users,
 					  &result->sids,
@@ -660,6 +672,8 @@ static NTSTATUS finalize_local_nt_token(struct security_token *result,
 		}
 	}
 
+	/* Add in BUILTIN sids */
+
 	become_root();
 	ok = secrets_fetch_domain_sid(lp_workgroup(), &_dom_sid);
 	if (ok) {
@@ -772,10 +786,16 @@ static NTSTATUS finalize_local_nt_token(struct security_token *result,
 		unbecome_root();
 	}
 
-	/* Add privileges based on current user sids */
 
-	get_privileges_for_sids(&result->privilege_mask, result->sids,
-				result->num_sids);
+	if (session_info_flags & AUTH_SESSION_INFO_SIMPLE_PRIVILEGES) {
+		if (security_token_has_builtin_administrators(result)) {
+			result->privilege_mask = ~0;
+		}
+	} else {
+		/* Add privileges based on current user sids */
+		get_privileges_for_sids(&result->privilege_mask, result->sids,
+					result->num_sids);
+	}
 
 	return NT_STATUS_OK;
 }
-- 
1.9.1


From 5b626ba67c167c61e381dd0cdcddff4a494df606 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Tue, 6 Mar 2018 23:45:30 +0100
Subject: [PATCH 12/19] s3:auth: remove static from finalize_local_nt_token()

BUG: https://bugzilla.samba.org/show_bug.cgi?id=13328

Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Ralph Boehme <slow at samba.org>
---
 source3/auth/proto.h      | 2 ++
 source3/auth/token_util.c | 6 ++----
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/source3/auth/proto.h b/source3/auth/proto.h
index bdefeaf..e47a347 100644
--- a/source3/auth/proto.h
+++ b/source3/auth/proto.h
@@ -357,6 +357,8 @@ struct security_token *create_local_nt_token(TALLOC_CTX *mem_ctx,
 					    bool is_guest,
 					    int num_groupsids,
 					    const struct dom_sid *groupsids);
+NTSTATUS finalize_local_nt_token(struct security_token *result,
+				 uint32_t session_info_flags);
 NTSTATUS get_user_sid_info3_and_extra(const struct netr_SamInfo3 *info3,
 				      const struct extra_auth_info *extra,
 				      struct dom_sid *sid);
diff --git a/source3/auth/token_util.c b/source3/auth/token_util.c
index acb916a..f015f8d 100644
--- a/source3/auth/token_util.c
+++ b/source3/auth/token_util.c
@@ -281,8 +281,6 @@ static NTSTATUS add_builtin_guests(struct security_token *token,
 
 static NTSTATUS add_local_groups(struct security_token *result,
 				 bool is_guest);
-static NTSTATUS finalize_local_nt_token(struct security_token *result,
-					uint32_t session_info_flags);
 
 NTSTATUS get_user_sid_info3_and_extra(const struct netr_SamInfo3 *info3,
 				      const struct extra_auth_info *extra,
@@ -616,8 +614,8 @@ static NTSTATUS add_local_groups(struct security_token *result,
 	return NT_STATUS_OK;
 }
 
-static NTSTATUS finalize_local_nt_token(struct security_token *result,
-					uint32_t session_info_flags)
+NTSTATUS finalize_local_nt_token(struct security_token *result,
+				 uint32_t session_info_flags)
 {
 	struct dom_sid _dom_sid = { 0, };
 	struct dom_sid *domain_sid = NULL;
-- 
1.9.1


From 420343fe3f5df2565b57a9cf28cba91ff14fa897 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Tue, 6 Mar 2018 16:38:10 +0100
Subject: [PATCH 13/19] auth: add auth_user_info_copy() function

BUG: https://bugzilla.samba.org/show_bug.cgi?id=13328

Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Ralph Boehme <slow at samba.org>
---
 auth/auth_sam_reply.c | 35 +++++++++++++++++++++++++++++++++++
 auth/auth_sam_reply.h |  3 +++
 2 files changed, 38 insertions(+)

diff --git a/auth/auth_sam_reply.c b/auth/auth_sam_reply.c
index 15d17b0..bd69515 100644
--- a/auth/auth_sam_reply.c
+++ b/auth/auth_sam_reply.c
@@ -333,6 +333,41 @@ NTSTATUS make_user_info_SamBaseInfo(TALLOC_CTX *mem_ctx,
 	return NT_STATUS_OK;
 }
 
+struct auth_user_info *auth_user_info_copy(TALLOC_CTX *mem_ctx,
+					   const struct auth_user_info *src)
+{
+	struct auth_user_info *dst = NULL;
+
+	dst = talloc_zero(mem_ctx, struct auth_user_info);
+	if (dst == NULL) {
+		return NULL;
+	}
+
+	*dst = *src;
+#define _COPY_STRING(_mem, _str) do { \
+	if ((_str) != NULL) { \
+		(_str) = talloc_strdup((_mem), (_str)); \
+		if ((_str) == NULL) { \
+			TALLOC_FREE(dst); \
+			return NULL; \
+		} \
+	} \
+} while(0)
+	_COPY_STRING(dst, dst->account_name);
+	_COPY_STRING(dst, dst->user_principal_name);
+	_COPY_STRING(dst, dst->domain_name);
+	_COPY_STRING(dst, dst->dns_domain_name);
+	_COPY_STRING(dst, dst->full_name);
+	_COPY_STRING(dst, dst->logon_script);
+	_COPY_STRING(dst, dst->profile_path);
+	_COPY_STRING(dst, dst->home_directory);
+	_COPY_STRING(dst, dst->home_drive);
+	_COPY_STRING(dst, dst->logon_server);
+#undef _COPY_STRING
+
+	return dst;
+}
+
 /**
  * Make a user_info_dc struct from the info3 returned by a domain logon
  */
diff --git a/auth/auth_sam_reply.h b/auth/auth_sam_reply.h
index 4aa3096..e4b26e9 100644
--- a/auth/auth_sam_reply.h
+++ b/auth/auth_sam_reply.h
@@ -38,6 +38,9 @@ NTSTATUS make_user_info_SamBaseInfo(TALLOC_CTX *mem_ctx,
 				    bool authenticated,
 				    struct auth_user_info **_user_info);
 
+struct auth_user_info *auth_user_info_copy(TALLOC_CTX *mem_ctx,
+					   const struct auth_user_info *src);
+
 NTSTATUS auth_convert_user_info_dc_saminfo6(TALLOC_CTX *mem_ctx,
 					   const struct auth_user_info_dc *user_info_dc,
 					   struct netr_SamInfo6 **_sam6);
-- 
1.9.1


From 86fa274327c6c5b6858de8b8dacead002565efba Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Wed, 7 Mar 2018 00:21:13 +0100
Subject: [PATCH 14/19] s3:auth: add auth3_user_info_dc_add_hints() and
 auth3_session_info_create()

These functions make it possible to construct a full auth_session_info
from the information available from an auth_user_info_dc structure.

This has all the logic from create_local_token() that is used
to transform a auth_serversupplied_info to a full auth_session_info.

In order to workarround the restriction that auth_user_info_dc
doesn't contain hints for the unix token/name, we use
the special S-1-5-88 (Unix_NFS) sids:

 - S-1-5-88-1-Y gives the uid=Y
 - S-1-5-88-2-Y gives the gid=Y
 - S-1-5-88-3-Y gives flags=Y AUTH3_UNIX_HINT_*

The currently implemented flags are:

- AUTH3_UNIX_HINT_QUALIFIED_NAME
  unix_name = DOMAIN+ACCOUNT

- AUTH3_UNIX_HINT_ISLOLATED_NAME
  unix_name = ACCOUNT

- AUTH3_UNIX_HINT_DONT_TRANSLATE_FROM_SIDS
  Don't translate the nt token SIDS into uid/gids
  using sid mapping.

- AUTH3_UNIX_HINT_DONT_TRANSLATE_TO_SIDS
  Don't translate the unix token uid/gids to S-1-22-X-Y SIDS

- AUTH3_UNIX_HINT_DONT_EXPAND_UNIX_GROUPS
  The unix token won't get expanded gid values
  from getgroups_unix_user()

By using the hints it is possible to keep the current logic
where an authentication backend provides uid/gid values and
the unix name.

Note the S-1-5-88-* SIDS never appear in the final security_token.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=13328

Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Ralph Boehme <slow at samba.org>
---
 source3/auth/auth_util.c | 552 +++++++++++++++++++++++++++++++++++++++++++++++
 source3/auth/proto.h     |  32 +++
 2 files changed, 584 insertions(+)

diff --git a/source3/auth/auth_util.c b/source3/auth/auth_util.c
index 24d2e7d..e146ac3 100644
--- a/source3/auth/auth_util.c
+++ b/source3/auth/auth_util.c
@@ -665,6 +665,558 @@ NTSTATUS create_local_token(TALLOC_CTX *mem_ctx,
 	return NT_STATUS_OK;
 }
 
+NTSTATUS auth3_user_info_dc_add_hints(struct auth_user_info_dc *user_info_dc,
+				      uid_t uid,
+				      gid_t gid,
+				      uint32_t flags)
+{
+	uint32_t orig_num_sids = user_info_dc->num_sids;
+	struct dom_sid tmp_sid = { 0, };
+	NTSTATUS status;
+
+	/*
+	 * We add S-5-88-1-X in order to pass the uid
+	 * for the unix token.
+	 */
+	sid_compose(&tmp_sid,
+		    &global_sid_Unix_NFS_Users,
+		    (uint32_t)uid);
+	status = add_sid_to_array_unique(user_info_dc->sids,
+					 &tmp_sid,
+					 &user_info_dc->sids,
+					 &user_info_dc->num_sids);
+	if (!NT_STATUS_IS_OK(status)) {
+		DEBUG(0, ("add_sid_to_array_unique failed: %s\n",
+			  nt_errstr(status)));
+		goto fail;
+	}
+
+	/*
+	 * We add S-5-88-2-X in order to pass the gid
+	 * for the unix token.
+	 */
+	sid_compose(&tmp_sid,
+		    &global_sid_Unix_NFS_Groups,
+		    (uint32_t)gid);
+	status = add_sid_to_array_unique(user_info_dc->sids,
+					 &tmp_sid,
+					 &user_info_dc->sids,
+					 &user_info_dc->num_sids);
+	if (!NT_STATUS_IS_OK(status)) {
+		DEBUG(0, ("add_sid_to_array_unique failed: %s\n",
+			  nt_errstr(status)));
+		goto fail;
+	}
+
+	/*
+	 * We add S-5-88-3-X in order to pass some flags
+	 * (AUTH3_UNIX_HINT_*) to auth3_create_session_info().
+	 */
+	sid_compose(&tmp_sid,
+		    &global_sid_Unix_NFS_Mode,
+		    flags);
+	status = add_sid_to_array_unique(user_info_dc->sids,
+					 &tmp_sid,
+					 &user_info_dc->sids,
+					 &user_info_dc->num_sids);
+	if (!NT_STATUS_IS_OK(status)) {
+		DEBUG(0, ("add_sid_to_array_unique failed: %s\n",
+			  nt_errstr(status)));
+		goto fail;
+	}
+
+	return NT_STATUS_OK;
+
+fail:
+	user_info_dc->num_sids = orig_num_sids;
+	return status;
+}
+
+NTSTATUS auth3_session_info_create(TALLOC_CTX *mem_ctx,
+				   const struct auth_user_info_dc *user_info_dc,
+				   const char *original_user_name,
+				   uint32_t session_info_flags,
+				   struct auth_session_info **session_info_out)
+{
+	TALLOC_CTX *frame = talloc_stackframe();
+	struct auth_session_info *session_info = NULL;
+	uid_t hint_uid = -1;
+	bool found_hint_uid = false;
+	uid_t hint_gid = -1;
+	bool found_hint_gid = false;
+	uint32_t hint_flags = 0;
+	bool found_hint_flags = false;
+	bool need_getpwuid = false;
+	struct unixid *ids = NULL;
+	uint32_t num_gids = 0;
+	gid_t *gids = NULL;
+	struct dom_sid tmp_sid = { 0, };
+	fstring tmp = { 0, };
+	NTSTATUS status;
+	size_t i;
+	bool ok;
+
+	*session_info_out = NULL;
+
+	if (user_info_dc->num_sids == 0) {
+		TALLOC_FREE(frame);
+		return NT_STATUS_INVALID_TOKEN;
+	}
+
+	if (user_info_dc->info == NULL) {
+		TALLOC_FREE(frame);
+		return NT_STATUS_INVALID_TOKEN;
+	}
+
+	if (user_info_dc->info->account_name == NULL) {
+		TALLOC_FREE(frame);
+		return NT_STATUS_INVALID_TOKEN;
+	}
+
+	session_info = talloc_zero(mem_ctx, struct auth_session_info);
+	if (session_info == NULL) {
+		TALLOC_FREE(frame);
+		return NT_STATUS_NO_MEMORY;
+	}
+	/* keep this under frame for easier cleanup */
+	talloc_reparent(mem_ctx, frame, session_info);
+
+	session_info->info = auth_user_info_copy(session_info,
+						 user_info_dc->info);
+	if (session_info->info == NULL) {
+		TALLOC_FREE(frame);
+		return NT_STATUS_NO_MEMORY;
+	}
+
+	session_info->security_token = talloc_zero(session_info,
+						   struct security_token);
+	if (session_info->security_token == NULL) {
+		TALLOC_FREE(frame);
+		return NT_STATUS_NO_MEMORY;
+	}
+
+	/*
+	 * Avoid a lot of reallocations and allocate what we'll
+	 * use in most cases.
+	 */
+	session_info->security_token->sids = talloc_zero_array(
+						session_info->security_token,
+						struct dom_sid,
+						user_info_dc->num_sids);
+	if (session_info->security_token->sids == NULL) {
+		TALLOC_FREE(frame);
+		return NT_STATUS_NO_MEMORY;
+	}
+
+	for (i = PRIMARY_USER_SID_INDEX; i < user_info_dc->num_sids; i++) {
+		struct security_token *nt_token = session_info->security_token;
+		int cmp;
+
+		/*
+		 * S-1-5-88-X-Y sids are only used to give hints
+		 * to the unix token construction.
+		 *
+		 * S-1-5-88-1-Y gives the uid=Y
+		 * S-1-5-88-2-Y gives the gid=Y
+		 * S-1-5-88-3-Y gives flags=Y: AUTH3_UNIX_HINT_*
+		 */
+		cmp = dom_sid_compare_domain(&global_sid_Unix_NFS,
+					     &user_info_dc->sids[i]);
+		if (cmp == 0) {
+			bool match;
+			uint32_t hint = 0;
+
+			match = sid_peek_rid(&user_info_dc->sids[i], &hint);
+			if (!match) {
+				continue;
+			}
+
+			match = dom_sid_in_domain(&global_sid_Unix_NFS_Users,
+						  &user_info_dc->sids[i]);
+			if (match) {
+				if (found_hint_uid) {
+					TALLOC_FREE(frame);
+					return NT_STATUS_INVALID_TOKEN;
+				}
+				found_hint_uid = true;
+				hint_uid = (uid_t)hint;
+				continue;
+			}
+
+			match = dom_sid_in_domain(&global_sid_Unix_NFS_Groups,
+						  &user_info_dc->sids[i]);
+			if (match) {
+				if (found_hint_gid) {
+					TALLOC_FREE(frame);
+					return NT_STATUS_INVALID_TOKEN;
+				}
+				found_hint_gid = true;
+				hint_gid = (gid_t)hint;
+				continue;
+			}
+
+			match = dom_sid_in_domain(&global_sid_Unix_NFS_Mode,
+						  &user_info_dc->sids[i]);
+			if (match) {
+				if (found_hint_flags) {
+					TALLOC_FREE(frame);
+					return NT_STATUS_INVALID_TOKEN;
+				}
+				found_hint_flags = true;
+				hint_flags = hint;
+				continue;
+			}
+
+			continue;
+		}
+
+		status = add_sid_to_array_unique(nt_token->sids,
+						 &user_info_dc->sids[i],
+						 &nt_token->sids,
+						 &nt_token->num_sids);
+		if (!NT_STATUS_IS_OK(status)) {
+			TALLOC_FREE(frame);
+			return status;
+		}
+	}
+
+	/*
+	 * We need at least one usable SID
+	 */
+	if (session_info->security_token->num_sids == 0) {
+		TALLOC_FREE(frame);
+		return NT_STATUS_INVALID_TOKEN;
+	}
+
+	/*
+	 * We need all tree hints: uid, gid, flags
+	 * or none of them.
+	 */
+	if (found_hint_uid || found_hint_gid || found_hint_flags) {
+		if (!found_hint_uid) {
+			TALLOC_FREE(frame);
+			return NT_STATUS_INVALID_TOKEN;
+		}
+
+		if (!found_hint_gid) {
+			TALLOC_FREE(frame);
+			return NT_STATUS_INVALID_TOKEN;
+		}
+
+		if (!found_hint_flags) {
+			TALLOC_FREE(frame);
+			return NT_STATUS_INVALID_TOKEN;
+		}
+	}
+
+	if (session_info->info->authenticated) {
+		session_info_flags |= AUTH_SESSION_INFO_AUTHENTICATED;
+	}
+
+	status = finalize_local_nt_token(session_info->security_token,
+					 session_info_flags);
+	if (!NT_STATUS_IS_OK(status)) {
+		TALLOC_FREE(frame);
+		return status;
+	}
+
+	/*
+	 * unless set otherwise, the session key is the user session
+	 * key from the auth subsystem
+	 */
+	if (user_info_dc->user_session_key.length != 0) {
+		session_info->session_key = data_blob_dup_talloc(session_info,
+						user_info_dc->user_session_key);
+		if (session_info->session_key.data == NULL) {
+			TALLOC_FREE(frame);
+			return NT_STATUS_NO_MEMORY;
+		}
+	}
+
+	if (!(session_info_flags & AUTH_SESSION_INFO_UNIX_TOKEN)) {
+		goto done;
+	}
+
+	session_info->unix_token = talloc_zero(session_info, struct security_unix_token);
+	if (session_info->unix_token == NULL) {
+		TALLOC_FREE(frame);
+		return NT_STATUS_NO_MEMORY;
+	}
+	session_info->unix_token->uid = -1;
+	session_info->unix_token->gid = -1;
+
+	session_info->unix_info = talloc_zero(session_info, struct auth_user_info_unix);
+	if (session_info->unix_info == NULL) {
+		TALLOC_FREE(frame);
+		return NT_STATUS_NO_MEMORY;
+	}
+
+	/* Convert the SIDs to uid/gids. */
+
+	ids = talloc_zero_array(frame, struct unixid,
+				session_info->security_token->num_sids);
+	if (ids == NULL) {
+		TALLOC_FREE(frame);
+		return NT_STATUS_NO_MEMORY;
+	}
+
+	if (!(hint_flags & AUTH3_UNIX_HINT_DONT_TRANSLATE_FROM_SIDS)) {
+		ok = sids_to_unixids(session_info->security_token->sids,
+				     session_info->security_token->num_sids,
+				     ids);
+		if (!ok) {
+			TALLOC_FREE(frame);
+			return NT_STATUS_NO_MEMORY;
+		}
+	}
+
+	if (found_hint_uid) {
+		session_info->unix_token->uid = hint_uid;
+	} else if (ids[0].type == ID_TYPE_UID) {
+		/*
+		 * The primary SID resolves to a UID only.
+		 */
+		session_info->unix_token->uid = ids[0].id;
+	} else if (ids[0].type == ID_TYPE_BOTH) {
+		/*
+		 * The primary SID resolves to a UID and GID,
+		 * use it as uid and add it as first element
+		 * to the groups array.
+		 */
+		session_info->unix_token->uid = ids[0].id;
+
+		ok = add_gid_to_array_unique(session_info->unix_token,
+					     session_info->unix_token->uid,
+					     &session_info->unix_token->groups,
+					     &session_info->unix_token->ngroups);
+		if (!ok) {
+			TALLOC_FREE(frame);
+			return NT_STATUS_NO_MEMORY;
+		}
+	} else {
+		/*
+		 * It we can't get a uid, we can't imporsonate
+		 * the user.
+		 */
+		TALLOC_FREE(frame);
+		return NT_STATUS_INVALID_TOKEN;
+	}
+
+	if (found_hint_gid) {
+		session_info->unix_token->gid = hint_gid;
+	} else {
+		need_getpwuid = true;
+	}
+
+	if (hint_flags & AUTH3_UNIX_HINT_QUALIFIED_NAME) {
+		session_info->unix_info->unix_name =
+			talloc_asprintf(session_info->unix_info,
+					"%s%c%s",
+					session_info->info->domain_name,
+					*lp_winbind_separator(),
+					session_info->info->account_name);
+		if (session_info->unix_info->unix_name == NULL) {
+			TALLOC_FREE(frame);
+			return NT_STATUS_NO_MEMORY;
+		}
+	} else if (hint_flags & AUTH3_UNIX_HINT_ISLOLATED_NAME) {
+		session_info->unix_info->unix_name =
+			talloc_strdup(session_info->unix_info,
+				      session_info->info->account_name);
+		if (session_info->unix_info->unix_name == NULL) {
+			TALLOC_FREE(frame);
+			return NT_STATUS_NO_MEMORY;
+		}
+	} else {
+		need_getpwuid = true;
+	}
+
+	if (need_getpwuid) {
+		struct passwd *pwd = NULL;
+
+		/*
+		 * Ask the system for the primary gid
+		 * and the real unix name.
+		 */
+		pwd = getpwuid_alloc(frame, session_info->unix_token->uid);
+		if (pwd == NULL) {
+			TALLOC_FREE(frame);
+			return NT_STATUS_INVALID_TOKEN;
+		}
+		if (!found_hint_gid) {
+			session_info->unix_token->gid = pwd->pw_gid;
+		}
+
+		session_info->unix_info->unix_name =
+			talloc_strdup(session_info->unix_info, pwd->pw_name);
+		if (session_info->unix_info->unix_name == NULL) {
+			TALLOC_FREE(frame);
+			return NT_STATUS_NO_MEMORY;
+		}
+
+		TALLOC_FREE(pwd);
+	}
+
+	ok = add_gid_to_array_unique(session_info->unix_token,
+				     session_info->unix_token->gid,
+				     &session_info->unix_token->groups,
+				     &session_info->unix_token->ngroups);
+	if (!ok) {
+		TALLOC_FREE(frame);
+		return NT_STATUS_NO_MEMORY;
+	}
+
+	/* This is a potentially untrusted username for use in %U */
+	alpha_strcpy(tmp, original_user_name, ". _-$", sizeof(tmp));
+	session_info->unix_info->sanitized_username =
+				talloc_strdup(session_info->unix_info, tmp);
+	if (session_info->unix_info->sanitized_username == NULL) {
+		TALLOC_FREE(frame);
+		return NT_STATUS_NO_MEMORY;
+	}
+
+	for (i=0; i < session_info->security_token->num_sids; i++) {
+
+		if (ids[i].type != ID_TYPE_GID &&
+		    ids[i].type != ID_TYPE_BOTH) {
+			struct security_token *nt_token =
+				session_info->security_token;
+
+			DEBUG(10, ("Could not convert SID %s to gid, "
+				   "ignoring it\n",
+				   sid_string_dbg(&nt_token->sids[i])));
+			continue;
+		}
+
+		ok = add_gid_to_array_unique(session_info->unix_token,
+					     ids[i].id,
+					     &session_info->unix_token->groups,
+					     &session_info->unix_token->ngroups);
+		if (!ok) {
+			TALLOC_FREE(frame);
+			return NT_STATUS_NO_MEMORY;
+		}
+	}
+	TALLOC_FREE(ids);
+
+	/*
+	 * Now we must get any groups this user has been
+	 * added to in /etc/group and merge them in.
+	 * This has to be done in every code path
+	 * that creates an NT token, as remote users
+	 * may have been added to the local /etc/group
+	 * database. Tokens created merely from the
+	 * info3 structs (via the DC or via the krb5 PAC)
+	 * won't have these local groups. Note the
+	 * groups added here will only be UNIX groups
+	 * (S-1-22-2-XXXX groups) as getgroups_unix_user()
+	 * turns off winbindd before calling getgroups().
+	 *
+	 * NB. This is duplicating work already
+	 * done in the 'unix_user:' case of
+	 * create_token_from_sid() but won't
+	 * do anything other than be inefficient
+	 * in that case.
+	 */
+	if (!(hint_flags & AUTH3_UNIX_HINT_DONT_EXPAND_UNIX_GROUPS)) {
+		ok = getgroups_unix_user(frame,
+					 session_info->unix_info->unix_name,
+					 session_info->unix_token->gid,
+					 &gids, &num_gids);
+		if (!ok) {
+			TALLOC_FREE(frame);
+			return NT_STATUS_INVALID_TOKEN;
+		}
+	}
+
+	for (i=0; i < num_gids; i++) {
+
+		ok = add_gid_to_array_unique(session_info->unix_token,
+					     gids[i],
+					     &session_info->unix_token->groups,
+					     &session_info->unix_token->ngroups);
+		if (!ok) {
+			TALLOC_FREE(frame);
+			return NT_STATUS_NO_MEMORY;
+		}
+	}
+	TALLOC_FREE(gids);
+
+	if (hint_flags & AUTH3_UNIX_HINT_DONT_TRANSLATE_TO_SIDS) {
+		/*
+		 * We should not translate the unix token uid/gids
+		 * to S-1-22-X-Y SIDs.
+		 */
+		goto done;
+	}
+
+	/*
+	 * Add the "Unix Group" SID for each gid to catch mapped groups
+	 * and their Unix equivalent.  This is to solve the backwards
+	 * compatibility problem of 'valid users = +ntadmin' where
+	 * ntadmin has been paired with "Domain Admins" in the group
+	 * mapping table.  Otherwise smb.conf would need to be changed
+	 * to 'valid user = "Domain Admins"'.  --jerry
+	 *
+	 * For consistency we also add the "Unix User" SID,
+	 * so that the complete unix token is represented within
+	 * the nt token.
+	 */
+
+	uid_to_unix_users_sid(session_info->unix_token->uid, &tmp_sid);
+	status = add_sid_to_array_unique(session_info->security_token, &tmp_sid,
+					 &session_info->security_token->sids,
+					 &session_info->security_token->num_sids);
+	if (!NT_STATUS_IS_OK(status)) {
+		TALLOC_FREE(frame);
+		return status;
+	}
+
+	gid_to_unix_groups_sid(session_info->unix_token->gid, &tmp_sid);
+	status = add_sid_to_array_unique(session_info->security_token, &tmp_sid,
+					 &session_info->security_token->sids,
+					 &session_info->security_token->num_sids);
+	if (!NT_STATUS_IS_OK(status)) {
+		TALLOC_FREE(frame);
+		return status;
+	}
+
+	for (i=0; i < session_info->unix_token->ngroups; i++ ) {
+		struct security_token *nt_token = session_info->security_token;
+
+		gid_to_unix_groups_sid(session_info->unix_token->groups[i],
+				       &tmp_sid);
+		status = add_sid_to_array_unique(nt_token->sids,
+						 &tmp_sid,
+						 &nt_token->sids,
+						 &nt_token->num_sids);
+		if (!NT_STATUS_IS_OK(status)) {
+			TALLOC_FREE(frame);
+			return status;
+		}
+	}
+
+done:
+	security_token_debug(DBGC_AUTH, 10, session_info->security_token);
+	if (session_info->unix_token != NULL) {
+		debug_unix_user_token(DBGC_AUTH, 10,
+				      session_info->unix_token->uid,
+				      session_info->unix_token->gid,
+				      session_info->unix_token->ngroups,
+				      session_info->unix_token->groups);
+	}
+
+	status = log_nt_token(session_info->security_token);
+	if (!NT_STATUS_IS_OK(status)) {
+		TALLOC_FREE(frame);
+		return status;
+	}
+
+	*session_info_out = talloc_move(mem_ctx, &session_info);
+	TALLOC_FREE(frame);
+	return NT_STATUS_OK;
+}
+
 /***************************************************************************
  Make (and fill) a server_info struct from a 'struct passwd' by conversion
  to a struct samu
diff --git a/source3/auth/proto.h b/source3/auth/proto.h
index e47a347..dc59fa9 100644
--- a/source3/auth/proto.h
+++ b/source3/auth/proto.h
@@ -221,6 +221,38 @@ NTSTATUS create_local_token(TALLOC_CTX *mem_ctx,
 			    DATA_BLOB *session_key,
 			    const char *smb_name,
 			    struct auth_session_info **session_info_out);
+
+/*
+ * The unix name should be constructed as DOMAIN+ACCOUNT,
+ * while '+' will be the "winbind separator" character.
+ */
+#define AUTH3_UNIX_HINT_QUALIFIED_NAME             0x00000001
+/*
+ * The unix name will be just ACCOUNT
+ */
+#define AUTH3_UNIX_HINT_ISLOLATED_NAME             0x00000002
+/*
+ * Don't translate the nt token SIDS into uid/gids
+ */
+#define AUTH3_UNIX_HINT_DONT_TRANSLATE_FROM_SIDS   0x00000004
+/*
+ * Don't translate the unix token uid/gids to S-1-22-X-Y SIDS
+ */
+#define AUTH3_UNIX_HINT_DONT_TRANSLATE_TO_SIDS     0x00000008
+/*
+ * The unix token won't get expanded gid values
+ * from getgroups_unix_user()
+ */
+#define AUTH3_UNIX_HINT_DONT_EXPAND_UNIX_GROUPS    0x00000010
+NTSTATUS auth3_user_info_dc_add_hints(struct auth_user_info_dc *user_info_dc,
+				      uid_t uid,
+				      gid_t gid,
+				      uint32_t flags);
+NTSTATUS auth3_session_info_create(TALLOC_CTX *mem_ctx,
+				   const struct auth_user_info_dc *user_info_dc,
+				   const char *original_user_name,
+				   uint32_t session_info_flags,
+				   struct auth_session_info **session_info_out);
 NTSTATUS create_token_from_username(TALLOC_CTX *mem_ctx, const char *username,
 				    bool is_guest,
 				    uid_t *uid, gid_t *gid,
-- 
1.9.1


From e79af82800f055789c2f3fb848319633a0381690 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Wed, 7 Mar 2018 00:51:51 +0100
Subject: [PATCH 15/19] s3:auth: base make_new_session_info_system() on
 auth_system_user_info_dc() and auth3_create_session_info()

The changes in the resulting token look like this:

           unix_token               : *
               unix_token: struct security_unix_token
                   uid                      : 0x0000000000000000 (0)
                   gid                      : 0x0000000000000000 (0)
-                  ngroups                  : 0x00000000 (0)
-                  groups: ARRAY(0)
+                  ngroups                  : 0x00000001 (1)
+                  groups: ARRAY(1)
+                      groups                   : 0x0000000000000000 (0)

...

                   domain_name              : *
                       domain_name              : 'NT AUTHORITY'
                   dns_domain_name          : NULL
-                  full_name                : NULL
-                  logon_script             : NULL
-                  profile_path             : NULL
-                  home_directory           : NULL
-                  home_drive               : NULL
-                  logon_server             : NULL
+                  full_name                : *
+                      full_name                : 'System'
+                  logon_script             : *
+                      logon_script             : ''
+                  profile_path             : *
+                      profile_path             : ''
+                  home_directory           : *
+                      home_directory           : ''
+                  home_drive               : *
+                      home_drive               : ''
+                  logon_server             : *
+                      logon_server             : 'SLOWSERVER'
                   last_logon               : NTTIME(0)
                   last_logoff              : NTTIME(0)
                   acct_expiry              : NTTIME(0)
                   last_password_change     : NTTIME(0)
                   allow_password_change    : NTTIME(0)
                   force_password_change    : NTTIME(0)
                   logon_count              : 0x0000 (0)
                   bad_password_count       : 0x0000 (0)
-                  acct_flags               : 0x00000000 (0)
+                  acct_flags               : 0x00000010 (16)
                   authenticated            : 0x01 (1)
           unix_info                : *

BUG: https://bugzilla.samba.org/show_bug.cgi?id=13328

Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Ralph Boehme <slow at samba.org>
---
 source3/auth/auth_util.c | 123 +++++++++++++++++------------------------------
 1 file changed, 43 insertions(+), 80 deletions(-)

diff --git a/source3/auth/auth_util.c b/source3/auth/auth_util.c
index e146ac3..ad14cf6 100644
--- a/source3/auth/auth_util.c
+++ b/source3/auth/auth_util.c
@@ -37,6 +37,7 @@
 #include "lib/param/loadparm.h"
 #include "../lib/tsocket/tsocket.h"
 #include "rpc_client/util_netlogon.h"
+#include "source4/auth/auth.h"
 
 #undef DBGC_CLASS
 #define DBGC_CLASS DBGC_AUTH
@@ -1268,31 +1269,6 @@ done:
 	return status;
 }
 
-static NTSTATUS get_system_info3(TALLOC_CTX *mem_ctx,
-				 struct netr_SamInfo3 *info3)
-{
-	NTSTATUS status;
-
-	/* Set account name */
-	init_lsa_String(&info3->base.account_name, "SYSTEM");
-
-	/* Set domain name */
-	init_lsa_StringLarge(&info3->base.logon_domain, "NT AUTHORITY");
-
-
-	status = dom_sid_split_rid(mem_ctx, &global_sid_System,
-				   &info3->base.domain_sid,
-				   &info3->base.rid);
-	if (!NT_STATUS_IS_OK(status)) {
-		return status;
-	}
-
-	/* Primary gid is the same */
-	info3->base.primary_gid = info3->base.rid;
-
-	return NT_STATUS_OK;
-}
-
 static NTSTATUS get_guest_info3(TALLOC_CTX *mem_ctx,
 				struct netr_SamInfo3 *info3)
 {
@@ -1426,80 +1402,67 @@ done:
 static NTSTATUS make_new_session_info_system(TALLOC_CTX *mem_ctx,
 					    struct auth_session_info **session_info)
 {
+	TALLOC_CTX *frame = talloc_stackframe();
+	struct auth_user_info_dc *user_info_dc = NULL;
+	uid_t uid = -1;
+	gid_t gid = -1;
+	uint32_t hint_flags = 0;
+	uint32_t session_info_flags = 0;
 	NTSTATUS status;
-	struct auth_serversupplied_info *server_info;
-	TALLOC_CTX *tmp_ctx;
-
-	tmp_ctx = talloc_stackframe();
-	if (tmp_ctx == NULL) {
-		return NT_STATUS_NO_MEMORY;
-	}
-
-	server_info = make_server_info(tmp_ctx);
-	if (!server_info) {
-		status = NT_STATUS_NO_MEMORY;
-		DEBUG(0, ("failed making server_info\n"));
-		goto done;
-	}
 
-	server_info->info3 = talloc_zero(server_info, struct netr_SamInfo3);
-	if (!server_info->info3) {
-		status = NT_STATUS_NO_MEMORY;
-		DEBUG(0, ("talloc failed setting info3\n"));
-		goto done;
-	}
-
-	status = get_system_info3(server_info, server_info->info3);
+	status = auth_system_user_info_dc(frame, lp_netbios_name(),
+					  &user_info_dc);
 	if (!NT_STATUS_IS_OK(status)) {
-		DEBUG(0, ("Failed creating system info3 with %s\n",
+		DEBUG(0, ("auth_system_user_info_dc failed: %s\n",
 			  nt_errstr(status)));
 		goto done;
 	}
 
-	server_info->utok.uid = sec_initial_uid();
-	server_info->utok.gid = sec_initial_gid();
-	server_info->unix_name = talloc_asprintf(server_info,
-						 "NT AUTHORITY%cSYSTEM",
-						 *lp_winbind_separator());
-
-	if (!server_info->unix_name) {
-		status = NT_STATUS_NO_MEMORY;
-		DEBUG(0, ("talloc_asprintf failed setting unix_name\n"));
-		goto done;
-	}
+	/*
+	 * Just get the initial uid/gid
+	 * and don't expand the unix groups.
+	 */
+	uid = sec_initial_uid();
+	gid = sec_initial_gid();
+	hint_flags |= AUTH3_UNIX_HINT_DONT_EXPAND_UNIX_GROUPS;
 
-	server_info->security_token = talloc_zero(server_info, struct security_token);
-	if (!server_info->security_token) {
-		status = NT_STATUS_NO_MEMORY;
-		DEBUG(0, ("talloc failed setting security token\n"));
-		goto done;
-	}
+	/*
+	 * Also avoid sid mapping to gids,
+	 * as well as adding the unix_token uid/gids as
+	 * S-1-22-X-Y SIDs to the nt token.
+	 */
+	hint_flags |= AUTH3_UNIX_HINT_DONT_TRANSLATE_FROM_SIDS;
+	hint_flags |= AUTH3_UNIX_HINT_DONT_TRANSLATE_TO_SIDS;
 
-	status = add_sid_to_array_unique(server_info->security_token->sids,
-					 &global_sid_System,
-					 &server_info->security_token->sids,
-					 &server_info->security_token->num_sids);
+	/*
+	 * The unix name will be "NT AUTHORITY+SYSTEM",
+	 * where '+' is the "winbind separator" character.
+	 */
+	hint_flags |= AUTH3_UNIX_HINT_QUALIFIED_NAME;
+	status = auth3_user_info_dc_add_hints(user_info_dc,
+					      uid,
+					      gid,
+					      hint_flags);
 	if (!NT_STATUS_IS_OK(status)) {
+		DEBUG(0, ("auth3_user_info_dc_add_hints failed: %s\n",
+			  nt_errstr(status)));
 		goto done;
 	}
 
-	/* SYSTEM has all privilages */
-	server_info->security_token->privilege_mask = ~0;
-
-	/* Now turn the server_info into a session_info with the full token etc */
-	status = create_local_token(mem_ctx, server_info, NULL, "SYSTEM", session_info);
-	talloc_free(server_info);
-
+	session_info_flags |= AUTH_SESSION_INFO_SIMPLE_PRIVILEGES;
+	session_info_flags |= AUTH_SESSION_INFO_UNIX_TOKEN;
+	status = auth3_session_info_create(mem_ctx, user_info_dc,
+					   user_info_dc->info->account_name,
+					   session_info_flags,
+					   session_info);
 	if (!NT_STATUS_IS_OK(status)) {
-		DEBUG(0, ("create_local_token failed: %s\n",
+		DEBUG(0, ("auth3_session_info_create failed: %s\n",
 			  nt_errstr(status)));
 		goto done;
 	}
 
-	talloc_steal(mem_ctx, *session_info);
-
 done:
-	TALLOC_FREE(tmp_ctx);
+	TALLOC_FREE(frame);
 	return status;
 }
 
-- 
1.9.1


From f3e19679b5863ebeb7fe81de0bb6501b800e354c Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Fri, 2 Mar 2018 17:07:11 +0100
Subject: [PATCH 16/19] s3:auth: pass the whole auth_session_info from
 copy_session_info_serverinfo_guest() to create_local_token()

We only need to adjust sanitized_username in order to keep the same behaviour.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=13328

Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Ralph Boehme <slow at samba.org>
---
 source3/auth/auth_util.c | 51 ++++++++++++++++++++----------------------------
 source3/include/auth.h   |  5 ++---
 2 files changed, 23 insertions(+), 33 deletions(-)

diff --git a/source3/auth/auth_util.c b/source3/auth/auth_util.c
index ad14cf6..8b7630f 100644
--- a/source3/auth/auth_util.c
+++ b/source3/auth/auth_util.c
@@ -472,6 +472,26 @@ NTSTATUS create_local_token(TALLOC_CTX *mem_ctx,
 		return NT_STATUS_LOGON_FAILURE;
 	}
 
+	if (server_info->cached_session_info != NULL) {
+		session_info = copy_session_info(mem_ctx,
+				server_info->cached_session_info);
+		if (session_info == NULL) {
+			return NT_STATUS_NO_MEMORY;
+		}
+
+		/* This is a potentially untrusted username for use in %U */
+		alpha_strcpy(tmp, smb_username, ". _-$", sizeof(tmp));
+		session_info->unix_info->sanitized_username =
+				talloc_strdup(session_info->unix_info, tmp);
+		if (session_info->unix_info->sanitized_username == NULL) {
+			TALLOC_FREE(session_info);
+			return NT_STATUS_NO_MEMORY;
+		}
+
+		*session_info_out = session_info;
+		return NT_STATUS_OK;
+	}
+
 	session_info = talloc_zero(mem_ctx, struct auth_session_info);
 	if (!session_info) {
 		return NT_STATUS_NO_MEMORY;
@@ -526,30 +546,6 @@ NTSTATUS create_local_token(TALLOC_CTX *mem_ctx,
 		return status;
 	}
 
-	if (server_info->security_token) {
-		/* Just copy the token, it has already been finalised
-		 * (nasty hack to support a cached guest/system session_info
-		 */
-
-		session_info->security_token = dup_nt_token(session_info, server_info->security_token);
-		if (!session_info->security_token) {
-			TALLOC_FREE(session_info);
-			return NT_STATUS_NO_MEMORY;
-		}
-
-		session_info->unix_token->ngroups = server_info->utok.ngroups;
-		if (server_info->utok.ngroups != 0) {
-			session_info->unix_token->groups = (gid_t *)talloc_memdup(
-				session_info->unix_token, server_info->utok.groups,
-				sizeof(gid_t)*session_info->unix_token->ngroups);
-		} else {
-			session_info->unix_token->groups = NULL;
-		}
-
-		*session_info_out = session_info;
-		return NT_STATUS_OK;
-	}
-
 	/*
 	 * If winbind is not around, we can not make much use of the SIDs the
 	 * domain controller provided us with. Likewise if the user name was
@@ -1565,12 +1561,6 @@ static struct auth_serversupplied_info *copy_session_info_serverinfo_guest(TALLO
 	 * to take the wrong path */
 	SMB_ASSERT(src->security_token);
 
-	dst->security_token = dup_nt_token(dst, src->security_token);
-	if (!dst->security_token) {
-		TALLOC_FREE(dst);
-		return NULL;
-	}
-
 	dst->session_key = data_blob_talloc( dst, src->session_key.data,
 						src->session_key.length);
 
@@ -1593,6 +1583,7 @@ static struct auth_serversupplied_info *copy_session_info_serverinfo_guest(TALLO
 		return NULL;
 	}
 
+	dst->cached_session_info = src;
 	return dst;
 }
 
diff --git a/source3/include/auth.h b/source3/include/auth.h
index d305537..31a1f20 100644
--- a/source3/include/auth.h
+++ b/source3/include/auth.h
@@ -34,15 +34,14 @@ struct auth_serversupplied_info {
 	struct security_unix_token utok;
 
 	/*
-	 * NT group information taken from the info3 structure
+	 * A complete auth_session_info
 	 *
 	 * 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;
+	const struct auth_session_info *cached_session_info;
 
 	/* These are the intermediate session keys, as provided by a
 	 * NETLOGON server and used by NTLMSSP to negotiate key
-- 
1.9.1


From 7879b0391839aac70ec6d29a3d30e3fb80d63422 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Fri, 2 Mar 2018 14:39:44 +0100
Subject: [PATCH 17/19] s3:auth: add make_{server,session}_info_anonymous()

It's important to have them separated from make_{server,session}_info_guest(),
because there's a fundamental difference between anonymous (the client requested
no authentication) and guest (the server lies about the authentication failure).

The following is the difference between guest and anonymous token:

             security_token: struct security_token
-                num_sids                 : 0x0000000a (10)
-                sids: ARRAY(10)
-                    sids                     : S-1-5-21-3793881525-3372187982-3724979742-501
-                    sids                     : S-1-5-21-3793881525-3372187982-3724979742-514
-                    sids                     : S-1-22-2-65534
-                    sids                     : S-1-22-2-65533
+                num_sids                 : 0x00000009 (9)
+                sids: ARRAY(9)
+                    sids                     : S-1-5-7
                     sids                     : S-1-1-0
                     sids                     : S-1-5-2
-                    sids                     : S-1-5-32-546
                     sids                     : S-1-22-1-65533
+                    sids                     : S-1-22-2-65534
+                    sids                     : S-1-22-2-100004
                     sids                     : S-1-22-2-100002
                     sids                     : S-1-22-2-100003
+                    sids                     : S-1-22-2-65533
                 privilege_mask           : 0x0000000000000000 (0)

...

         unix_token               : *
             unix_token: struct security_unix_token
                 uid                      : 0x000000000000fffd (65533)
                 gid                      : 0x000000000000fffe (65534)
-                ngroups                  : 0x00000004 (4)
-                groups: ARRAY(4)
+                ngroups                  : 0x00000005 (5)
+                groups: ARRAY(5)
                     groups                   : 0x000000000000fffe (65534)
-                    groups                   : 0x000000000000fffd (65533)
+                    groups                   : 0x00000000000186a4 (100004)
                     groups                   : 0x00000000000186a2 (100002)
                     groups                   : 0x00000000000186a3 (100003)
+                    groups                   : 0x000000000000fffd (65533)

             info: struct auth_user_info
                 account_name             : *
-                    account_name             : 'nobody'
+                    account_name             : 'ANONYMOUS LOGON'
                 user_principal_name      : NULL
                 user_principal_constructed: 0x00 (0)
                 domain_name              : *
-                    domain_name              : 'SAMBA-TEST'
+                    domain_name              : 'NT AUTHORITY'
                 dns_domain_name          : NULL
-                full_name                : NULL
-                logon_script             : NULL
-                profile_path             : NULL
-                home_directory           : NULL
-                home_drive               : NULL
-                logon_server             : NULL
+                full_name                : *
+                    full_name                : 'Anonymous Logon'
+                logon_script             : *
+                    logon_script             : ''
+                profile_path             : *
+                    profile_path             : ''
+                home_directory           : *
+                    home_directory           : ''
+                home_drive               : *
+                    home_drive               : ''
+                logon_server             : *
+                    logon_server             : 'LOCALNT4DC2'
                 last_logon               : NTTIME(0)
                 last_logoff              : NTTIME(0)
                 acct_expiry              : NTTIME(0)
                 last_password_change     : NTTIME(0)
                 allow_password_change    : NTTIME(0)
                 force_password_change    : NTTIME(0)
                 logon_count              : 0x0000 (0)
                 bad_password_count       : 0x0000 (0)
-                acct_flags               : 0x00000000 (0)
+                acct_flags               : 0x00000010 (16)
                 authenticated            : 0x00 (0)
             security_token: struct security_token
                 num_sids                 : 0x00000006 (6)
                 sids: ARRAY(6)
+                    sids                     : S-1-5-7
+                    sids                     : S-1-1-0
+                    sids                     : S-1-5-2
                     sids                     : S-1-22-1-65533
                     sids                     : S-1-22-2-65534
                     sids                     : S-1-22-2-65533
-                    sids                     : S-1-1-0
-                    sids                     : S-1-5-2
-                    sids                     : S-1-5-32-546
                 privilege_mask           : 0x0000000000000000 (0)

BUG: https://bugzilla.samba.org/show_bug.cgi?id=13328

Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Ralph Boehme <slow at samba.org>
---
 source3/auth/auth_util.c | 139 ++++++++++++++++++++++++++++++++++++++++++++++-
 source3/auth/proto.h     |   4 ++
 2 files changed, 142 insertions(+), 1 deletion(-)

diff --git a/source3/auth/auth_util.c b/source3/auth/auth_util.c
index 8b7630f..3b951e7 100644
--- a/source3/auth/auth_util.c
+++ b/source3/auth/auth_util.c
@@ -1462,6 +1462,87 @@ done:
 	return status;
 }
 
+static NTSTATUS make_new_session_info_anonymous(TALLOC_CTX *mem_ctx,
+					struct auth_session_info **session_info)
+{
+	TALLOC_CTX *frame = talloc_stackframe();
+	const char *guest_account = lp_guest_account();
+	struct auth_user_info_dc *user_info_dc = NULL;
+	struct passwd *pwd = NULL;
+	uint32_t hint_flags = 0;
+	uint32_t session_info_flags = 0;
+	NTSTATUS status;
+
+	/*
+	 * We use the guest account for the unix token
+	 * while we use a true anonymous nt token.
+	 *
+	 * It's very important to have a separate
+	 * nt token for anonymous.
+	 */
+
+	pwd = Get_Pwnam_alloc(frame, guest_account);
+	if (pwd == NULL) {
+		DBG_ERR("Unable to locate guest account [%s]!\n",
+			guest_account);
+		status = NT_STATUS_NO_SUCH_USER;
+		goto done;
+	}
+
+	status = auth_anonymous_user_info_dc(frame, lp_netbios_name(),
+					     &user_info_dc);
+	if (!NT_STATUS_IS_OK(status)) {
+		DEBUG(0, ("auth_anonymous_user_info_dc failed: %s\n",
+			  nt_errstr(status)));
+		goto done;
+	}
+
+	/*
+	 * Note we don't pass AUTH3_UNIX_HINT_QUALIFIED_NAME
+	 * nor AUTH3_UNIX_HINT_ISOLATED_NAME here
+	 * as we want the unix name be found by getpwuid_alloc().
+	 */
+
+	status = auth3_user_info_dc_add_hints(user_info_dc,
+					      pwd->pw_uid,
+					      pwd->pw_gid,
+					      hint_flags);
+	if (!NT_STATUS_IS_OK(status)) {
+		DEBUG(0, ("auth3_user_info_dc_add_hints failed: %s\n",
+			  nt_errstr(status)));
+		goto done;
+	}
+
+	/*
+	 * In future we may want to remove
+	 * AUTH_SESSION_INFO_DEFAULT_GROUPS.
+	 *
+	 * Similar to Windows with EveryoneIncludesAnonymous
+	 * and RestrictAnonymous.
+	 *
+	 * We may introduce AUTH_SESSION_INFO_ANON_WORLD...
+	 *
+	 * But for this is required to keep the existing tests
+	 * working.
+	 */
+	session_info_flags |= AUTH_SESSION_INFO_DEFAULT_GROUPS;
+	session_info_flags |= AUTH_SESSION_INFO_SIMPLE_PRIVILEGES;
+	session_info_flags |= AUTH_SESSION_INFO_UNIX_TOKEN;
+	status = auth3_session_info_create(mem_ctx, user_info_dc,
+					   "",
+					   session_info_flags,
+					   session_info);
+	if (!NT_STATUS_IS_OK(status)) {
+		DEBUG(0, ("auth3_session_info_create failed: %s\n",
+			  nt_errstr(status)));
+		goto done;
+	}
+
+done:
+	TALLOC_FREE(frame);
+	return status;
+}
+
 /****************************************************************************
   Fake a auth_session_info just from a username (as a
   session_info structure, with create_local_token() already called on
@@ -1642,6 +1723,7 @@ bool session_info_set_session_key(struct auth_session_info *info,
 }
 
 static struct auth_session_info *guest_info = NULL;
+static struct auth_session_info *anonymous_info = NULL;
 
 static struct auth_serversupplied_info *guest_server_info = NULL;
 
@@ -1655,7 +1737,17 @@ bool init_guest_session_info(TALLOC_CTX *mem_ctx)
 	status = make_new_session_info_guest(mem_ctx,
 					     &guest_info,
 					     &guest_server_info);
-	return NT_STATUS_IS_OK(status);
+	if (!NT_STATUS_IS_OK(status)) {
+		return false;
+	}
+
+	status = make_new_session_info_anonymous(mem_ctx,
+						 &anonymous_info);
+	if (!NT_STATUS_IS_OK(status)) {
+		return false;
+	}
+
+	return true;
 }
 
 NTSTATUS make_server_info_guest(TALLOC_CTX *mem_ctx,
@@ -1676,6 +1768,51 @@ NTSTATUS make_session_info_guest(TALLOC_CTX *mem_ctx,
 	return (*session_info != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY;
 }
 
+NTSTATUS make_server_info_anonymous(TALLOC_CTX *mem_ctx,
+				    struct auth_serversupplied_info **server_info)
+{
+	if (anonymous_info == NULL) {
+		return NT_STATUS_UNSUCCESSFUL;
+	}
+
+	/*
+	 * This is trickier than it would appear to need to be because
+	 * we are trying to avoid certain costly operations when the
+	 * structure is converted to a 'auth_session_info' again in
+	 * create_local_token()
+	 *
+	 * We use a guest server_info, but with the anonymous session info,
+	 * which means create_local_token() will return a copy
+	 * of the anonymous token.
+	 *
+	 * The server info is just used as legacy in order to
+	 * keep existing code working. Maybe some debug messages
+	 * will still refer to guest instead of anonymous.
+	 */
+	*server_info = copy_session_info_serverinfo_guest(mem_ctx, anonymous_info,
+							  guest_server_info);
+	if (*server_info == NULL) {
+		return NT_STATUS_NO_MEMORY;
+	}
+
+	return NT_STATUS_OK;
+}
+
+NTSTATUS make_session_info_anonymous(TALLOC_CTX *mem_ctx,
+				     struct auth_session_info **session_info)
+{
+	if (anonymous_info == NULL) {
+		return NT_STATUS_UNSUCCESSFUL;
+	}
+
+	*session_info = copy_session_info(mem_ctx, anonymous_info);
+	if (*session_info == NULL) {
+		return NT_STATUS_NO_MEMORY;
+	}
+
+	return NT_STATUS_OK;
+}
+
 static struct auth_session_info *system_info = NULL;
 
 NTSTATUS init_system_session_info(TALLOC_CTX *mem_ctx)
diff --git a/source3/auth/proto.h b/source3/auth/proto.h
index dc59fa9..e4a6830 100644
--- a/source3/auth/proto.h
+++ b/source3/auth/proto.h
@@ -280,6 +280,10 @@ NTSTATUS make_server_info_guest(TALLOC_CTX *mem_ctx,
 				struct auth_serversupplied_info **server_info);
 NTSTATUS make_session_info_guest(TALLOC_CTX *mem_ctx,
 				struct auth_session_info **server_info);
+NTSTATUS make_server_info_anonymous(TALLOC_CTX *mem_ctx,
+				    struct auth_serversupplied_info **server_info);
+NTSTATUS make_session_info_anonymous(TALLOC_CTX *mem_ctx,
+				     struct auth_session_info **psession_info);
 NTSTATUS make_session_info_system(TALLOC_CTX *mem_ctx,
 				 struct auth_session_info **session_info);
 const struct auth_session_info *get_session_info_system(void);
-- 
1.9.1


From 2712bca6ec5ac7754e8009eca2e5e81ea84afb3e Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Fri, 2 Mar 2018 14:40:19 +0100
Subject: [PATCH 18/19] s3:rpc_server: make use of
 make_session_info_anonymous()

For unauthenticated connections we should default to a
session info with an anonymous nt token.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=13328

Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Ralph Boehme <slow at samba.org>
---
 source3/rpc_server/rpc_server.c | 9 +++------
 1 file changed, 3 insertions(+), 6 deletions(-)

diff --git a/source3/rpc_server/rpc_server.c b/source3/rpc_server/rpc_server.c
index 2327e43..a2bcf85 100644
--- a/source3/rpc_server/rpc_server.c
+++ b/source3/rpc_server/rpc_server.c
@@ -1108,14 +1108,11 @@ void dcerpc_ncacn_accept(struct tevent_context *ev_ctx,
 	}
 
 	if (ncacn_conn->session_info == NULL) {
-		/*
-		 * TODO: use auth_anonymous_session_info() here?
-		 */
-		status = make_session_info_guest(ncacn_conn,
-						 &ncacn_conn->session_info);
+		status = make_session_info_anonymous(ncacn_conn,
+						     &ncacn_conn->session_info);
 		if (!NT_STATUS_IS_OK(status)) {
 			DEBUG(2, ("Failed to create "
-				  "make_session_info_guest - %s\n",
+				  "make_session_info_anonymous - %s\n",
 				  nt_errstr(status)));
 			talloc_free(ncacn_conn);
 			return;
-- 
1.9.1


From 06f7abaca6a582c1cab51b8185afde5d90c846c0 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Fri, 2 Mar 2018 14:40:19 +0100
Subject: [PATCH 19/19] s3:auth: make use of
 make_{server,session}_info_anonymous()

It's important to have them separated from make_{server,session}_info_guest(),
because there's a fundamental difference between anonymous (the client requested
no authentication) and guest (the server lies about the authentication failure).

When it's really an anonymous connection, we should reflect that in the
resulting session info.

This should fix a problem where Windows 10 tries to join
a Samba hosted NT4 domain and has SMB2/3 enabled.

We no longer return SMB_SETUP_GUEST or SMB2_SESSION_FLAG_IS_GUEST
for true anonymous connections.

The commit message from a few commit before shows the resulting
auth_session_info change.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=13328

Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Ralph Boehme <slow at samba.org>
---
 selftest/knownfail.d/anonymous-guest | 1 -
 source3/auth/auth_builtin.c          | 2 +-
 source3/auth/auth_ntlmssp.c          | 5 +----
 3 files changed, 2 insertions(+), 6 deletions(-)
 delete mode 100644 selftest/knownfail.d/anonymous-guest

diff --git a/selftest/knownfail.d/anonymous-guest b/selftest/knownfail.d/anonymous-guest
deleted file mode 100644
index a134cec..0000000
--- a/selftest/knownfail.d/anonymous-guest
+++ /dev/null
@@ -1 +0,0 @@
-^samba3.smbtorture_s3.*nt4_dc.*.SMB2-ANONYMOUS.smbtorture
diff --git a/source3/auth/auth_builtin.c b/source3/auth/auth_builtin.c
index 0fa95d9..a2d95a7 100644
--- a/source3/auth/auth_builtin.c
+++ b/source3/auth/auth_builtin.c
@@ -81,7 +81,7 @@ static NTSTATUS check_guest_security(const struct auth_context *auth_context,
 		break;
 	}
 
-	return make_server_info_guest(NULL, server_info);
+	return make_server_info_anonymous(NULL, server_info);
 }
 
 /* Guest modules initialisation */
diff --git a/source3/auth/auth_ntlmssp.c b/source3/auth/auth_ntlmssp.c
index fd629fd..2e345e1 100644
--- a/source3/auth/auth_ntlmssp.c
+++ b/source3/auth/auth_ntlmssp.c
@@ -65,10 +65,7 @@ NTSTATUS auth3_generate_session_info(struct auth4_context *auth_context,
 
 		cmp = dom_sid_compare(sid, &global_sid_Anonymous);
 		if (cmp == 0) {
-			/*
-			 * TODO: use auth_anonymous_session_info() here?
-			 */
-			return make_session_info_guest(mem_ctx, session_info);
+			return make_session_info_anonymous(mem_ctx, session_info);
 		}
 
 		return NT_STATUS_INTERNAL_ERROR;
-- 
1.9.1

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


More information about the samba-technical mailing list