RFC impersonation and substitution

Stefan Metzmacher metze at samba.org
Wed Oct 16 15:47:19 UTC 2019


Hi,

some of you already saw my SDC presentation:
https://www.samba.org/~metze/presentations/2019/SDC/

Now I want to start the discussion regarding our impersonation model
here.

We try to get more things (including path based calls) in the smb_vfs
layer async.

I started with tevent_wrapper based impersonation, but that got reverted
as it got too complex, more details can be found here:
https://lists.samba.org/archive/samba-technical/2018-December/131731.html

Currently our impersonation happens per incoming SMB request.
We change 3 things:
A) the unix token (uid, gid, groups)
B) the global state in order to do smb.conf substitutions like %U
C) we change to the share root directory

The future idea would be that we no longer do impersonation at the
SMB layer. Instead we would explicitly pass down enough information
through the SMB_VFS layer, that vfs modules can do impersonation
just around the raw syscall (or in other required places).
The module write should know where it is required!
Userspace filesystems may do impersonation differently.
Of course we'll provide helper functions to make it
easy for the module writers.

In order to catch problem C) (relying on the correct current
working directory) Jeremy and others are working
hard to convert our SMB_VFS layer to *at() based syscalls.
See https://git.samba.org/?p=samba.git;a=history;f=source3/include/vfs.h

For problems A) and B) I have the idea to pass down
a 'const struct samba_impersonation' as explicit argument
to each SMB_VFS call. Note I called i 'smb_vfs_impersonation'
in my presentation, but I realized that we need the same
for the DCEPRC servers and changed the name.

Regarding problem B) I'm introducing a
'struct loadparm_substitution' that needs tobe passed explicitly
to each lp_*(), lpcfg_*() function that needs substitutions.

struct samba_impersonation will wrap
struct auth_session_info as well as struct loadparm_substitution.
We could add more later if needed.

I started with the struct loadparm_substitution infrastructure
and created some draft patches for struct samba_impersonation.
Before I continue I'd like to get some feedback.

Please have a look and tell me if you are happy with
that approach or if we need to find a better solution.

Thanks!
metze
-------------- next part --------------
From 13f0d5da9b151fdedf9656f9f4cd18b422a17247 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Tue, 15 Oct 2019 10:15:14 +0200
Subject: [PATCH 01/18] s3:lib: remove unused str_list_sub_basic()

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 source3/include/proto.h  |  2 --
 source3/lib/substitute.c | 29 -----------------------------
 2 files changed, 31 deletions(-)

diff --git a/source3/include/proto.h b/source3/include/proto.h
index c98f7cfa351b..f8b41f838789 100644
--- a/source3/include/proto.h
+++ b/source3/include/proto.h
@@ -620,8 +620,6 @@ size_t strlen_m(const char *s);
 size_t strlen_m_term(const char *s);
 size_t strlen_m_term_null(const char *s);
 int fstr_sprintf(fstring s, const char *fmt, ...);
-bool str_list_sub_basic( char **list, const char *smb_name,
-			 const char *domain_name );
 bool str_list_substitute(char **list, const char *pattern, const char *insert);
 
 char *ipstr_list_make(char **ipstr_list,
diff --git a/source3/lib/substitute.c b/source3/lib/substitute.c
index f8ca6f41cc1a..82fa995f6cae 100644
--- a/source3/lib/substitute.c
+++ b/source3/lib/substitute.c
@@ -878,32 +878,3 @@ void standard_sub_advanced(const char *servicename, const char *user,
 	strlcpy( str, s, len );
 	TALLOC_FREE( s );
 }
-
-/******************************************************************************
- version of standard_sub_basic() for string lists; uses talloc_sub_basic()
- for the work
- *****************************************************************************/
-
-bool str_list_sub_basic( char **list, const char *smb_name,
-			 const char *domain_name )
-{
-	TALLOC_CTX *ctx = list;
-	char *s, *tmpstr;
-
-	while ( *list ) {
-		s = *list;
-		tmpstr = talloc_sub_basic(ctx, smb_name, domain_name, s);
-		if ( !tmpstr ) {
-			DEBUG(0,("str_list_sub_basic: "
-				"talloc_sub_basic() return NULL!\n"));
-			return false;
-		}
-
-		TALLOC_FREE(*list);
-		*list = tmpstr;
-
-		list++;
-	}
-
-	return true;
-}
-- 
2.17.1


From 020c7c40e65107401abd90238ee99f22f1e5cfde Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Tue, 15 Oct 2019 10:15:41 +0200
Subject: [PATCH 02/18] s3:lib: remove unused str_list_substitute()

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 source3/include/proto.h |  1 -
 source3/lib/util_str.c  | 74 -----------------------------------------
 2 files changed, 75 deletions(-)

diff --git a/source3/include/proto.h b/source3/include/proto.h
index f8b41f838789..81ddb2a673a3 100644
--- a/source3/include/proto.h
+++ b/source3/include/proto.h
@@ -620,7 +620,6 @@ size_t strlen_m(const char *s);
 size_t strlen_m_term(const char *s);
 size_t strlen_m_term_null(const char *s);
 int fstr_sprintf(fstring s, const char *fmt, ...);
-bool str_list_substitute(char **list, const char *pattern, const char *insert);
 
 char *ipstr_list_make(char **ipstr_list,
 			const struct ip_service *ip_list,
diff --git a/source3/lib/util_str.c b/source3/lib/util_str.c
index e660e295c339..5d1d1291011a 100644
--- a/source3/lib/util_str.c
+++ b/source3/lib/util_str.c
@@ -570,80 +570,6 @@ int fstr_sprintf(fstring s, const char *fmt, ...)
 	return ret;
 }
 
-/**
- List of Strings manipulation functions
-**/
-
-#define S_LIST_ABS 16 /* List Allocation Block Size */
-
-/******************************************************************************
- substitute a specific pattern in a string list
- *****************************************************************************/
-
-bool str_list_substitute(char **list, const char *pattern, const char *insert)
-{
-	TALLOC_CTX *ctx = list;
-	char *p, *s, *t;
-	ssize_t ls, lp, li, ld, i, d;
-
-	if (!list)
-		return false;
-	if (!pattern)
-		return false;
-	if (!insert)
-		return false;
-
-	lp = (ssize_t)strlen(pattern);
-	li = (ssize_t)strlen(insert);
-	ld = li -lp;
-
-	while (*list) {
-		s = *list;
-		ls = (ssize_t)strlen(s);
-
-		while ((p = strstr_m(s, pattern))) {
-			t = *list;
-			d = p -t;
-			if (ld) {
-				t = talloc_array(ctx, char, ls +ld +1);
-				if (!t) {
-					DEBUG(0,("str_list_substitute: "
-						"Unable to allocate memory"));
-					return false;
-				}
-				memcpy(t, *list, d);
-				memcpy(t +d +li, p +lp, ls -d -lp +1);
-				TALLOC_FREE(*list);
-				*list = t;
-				ls += ld;
-				s = t +d +li;
-			}
-
-			for (i = 0; i < li; i++) {
-				switch (insert[i]) {
-					case '`':
-					case '"':
-					case '\'':
-					case ';':
-					case '$':
-					case '%':
-					case '\r':
-					case '\n':
-						t[d +i] = '_';
-						break;
-					default:
-						t[d +i] = insert[i];
-				}
-			}
-		}
-
-		list++;
-	}
-
-	return true;
-}
-
-
 #define IPSTR_LIST_SEP	","
 #define IPSTR_LIST_CHAR	','
 
-- 
2.17.1


From 58384e4dfb5bd6817feb9a325830ca20e0e06b02 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Tue, 15 Oct 2019 12:07:17 +0200
Subject: [PATCH 03/18] s3:param: introduce lp_substituted_string()

The idea is to get rid of the global state that's
currently used for the substitution in lp_string().

In the end all callers need to pass an explicit
const struct loadparm_substitution *sub_ctx,
which contains all relevant information
for the substitution.

For now we introduce loadparm_s3_global_substitution()
as a placeholder for a valid pointer, but still unchanged
behavior.

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 source3/include/proto.h  |  6 ++++++
 source3/param/loadparm.c | 34 +++++++++++++++++++++++++++++++---
 2 files changed, 37 insertions(+), 3 deletions(-)

diff --git a/source3/include/proto.h b/source3/include/proto.h
index 81ddb2a673a3..acb7e95966c1 100644
--- a/source3/include/proto.h
+++ b/source3/include/proto.h
@@ -731,6 +731,12 @@ NTSTATUS trust_pw_change(struct netlogon_creds_cli_context *context,
 
 /* The following definitions come from param/loadparm.c  */
 
+struct loadparm_substitution;
+const struct loadparm_substitution *loadparm_s3_global_substitution(void);
+char *lp_substituted_string(TALLOC_CTX *mem_ctx,
+			    const struct loadparm_substitution *lp_sub,
+			    const char *s);
+
 #include "source3/param/param_proto.h"
 
 char *lp_servicename(TALLOC_CTX *ctx, int);
diff --git a/source3/param/loadparm.c b/source3/param/loadparm.c
index b1a52055ade7..97adf9885aec 100644
--- a/source3/param/loadparm.c
+++ b/source3/param/loadparm.c
@@ -986,16 +986,31 @@ static struct loadparm_context *setup_lp_context(TALLOC_CTX *mem_ctx)
 	return lp_ctx;
 }
 
+struct loadparm_substitution {
+	uint8_t dummy;
+};
+
+static const struct loadparm_substitution s3_global_substitution;
+
+const struct loadparm_substitution *loadparm_s3_global_substitution(void)
+{
+	return &s3_global_substitution;
+}
+
 /*******************************************************************
  Convenience routine to grab string parameters into talloced memory
  and run standard_sub_basic on them. The buffers can be written to by
  callers without affecting the source string.
 ********************************************************************/
 
-char *lp_string(TALLOC_CTX *ctx, const char *s)
+char *lp_substituted_string(TALLOC_CTX *mem_ctx,
+			    const struct loadparm_substitution *lp_sub,
+			    const char *s)
 {
 	char *ret;
 
+	SMB_ASSERT(lp_sub != NULL);
+
 	/* The follow debug is useful for tracking down memory problems
 	   especially if you have an inner loop that is calling a lp_*()
 	   function that returns a string.  Perhaps this debug should be
@@ -1008,14 +1023,22 @@ char *lp_string(TALLOC_CTX *ctx, const char *s)
 		return NULL;
 	}
 
-	ret = talloc_sub_basic(ctx,
+	if (lp_sub != &s3_global_substitution) {
+		/*
+		 * Keep it simple for now, until
+		 * all callers pass something useful.
+		 */
+		return talloc_strdup(mem_ctx, s);
+	}
+
+	ret = talloc_sub_basic(mem_ctx,
 			get_current_username(),
 			current_user_info.domain,
 			s);
 	if (trim_char(ret, '\"', '\"')) {
 		if (strchr(ret,'\"') != NULL) {
 			TALLOC_FREE(ret);
-			ret = talloc_sub_basic(ctx,
+			ret = talloc_sub_basic(mem_ctx,
 					get_current_username(),
 					current_user_info.domain,
 					s);
@@ -1024,6 +1047,11 @@ char *lp_string(TALLOC_CTX *ctx, const char *s)
 	return ret;
 }
 
+char *lp_string(TALLOC_CTX *ctx, const char *s)
+{
+	return lp_substituted_string(ctx, &s3_global_substitution, s);
+}
+
 /*
    In this section all the functions that are used to access the
    parameters from the rest of the program are defined
-- 
2.17.1


From c68cd92038c7b70aa03a8223af577007b385a0d3 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Tue, 15 Oct 2019 12:29:08 +0200
Subject: [PATCH 04/18] s3:param: split out lp_parm_substituted_string()

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 source3/include/proto.h  |  6 ++++++
 source3/param/loadparm.c | 27 ++++++++++++++++++++++++---
 2 files changed, 30 insertions(+), 3 deletions(-)

diff --git a/source3/include/proto.h b/source3/include/proto.h
index acb7e95966c1..f19832a9089d 100644
--- a/source3/include/proto.h
+++ b/source3/include/proto.h
@@ -736,6 +736,12 @@ const struct loadparm_substitution *loadparm_s3_global_substitution(void);
 char *lp_substituted_string(TALLOC_CTX *mem_ctx,
 			    const struct loadparm_substitution *lp_sub,
 			    const char *s);
+char *lp_parm_substituted_string(TALLOC_CTX *mem_ctx,
+				 const struct loadparm_substitution *lp_sub,
+				 int snum,
+				 const char *type,
+				 const char *option,
+				 const char *def);
 
 #include "source3/param/param_proto.h"
 
diff --git a/source3/param/loadparm.c b/source3/param/loadparm.c
index 97adf9885aec..9db8e1e03eb0 100644
--- a/source3/param/loadparm.c
+++ b/source3/param/loadparm.c
@@ -1242,19 +1242,40 @@ static int lp_enum(const char *s,const struct enum_list *_enum)
 
 /* Return parametric option from a given service. Type is a part of option before ':' */
 /* Parametric option has following syntax: 'Type: option = value' */
-char *lp_parm_talloc_string(TALLOC_CTX *ctx, int snum, const char *type, const char *option, const char *def)
+char *lp_parm_substituted_string(TALLOC_CTX *mem_ctx,
+				 const struct loadparm_substitution *lp_sub,
+				 int snum,
+				 const char *type,
+				 const char *option,
+				 const char *def)
 {
 	struct parmlist_entry *data = get_parametrics(snum, type, option);
 
+	SMB_ASSERT(lp_sub != NULL);
+
 	if (data == NULL||data->value==NULL) {
 		if (def) {
-			return lp_string(ctx, def);
+			return lp_substituted_string(mem_ctx, lp_sub, def);
 		} else {
 			return NULL;
 		}
 	}
 
-	return lp_string(ctx, data->value);
+	return lp_substituted_string(mem_ctx, lp_sub, data->value);
+}
+
+char *lp_parm_talloc_string(TALLOC_CTX *mem_ctx,
+			    int snum,
+			    const char *type,
+			    const char *option,
+			    const char *def)
+{
+	return lp_parm_substituted_string(mem_ctx,
+					  &s3_global_substitution,
+					  snum,
+					  type,
+					  option,
+					  def);
 }
 
 /* Return parametric option from a given service. Type is a part of option before ':' */
-- 
2.17.1


From 9e20ef59bc48f7374c81a363e837f2d389e0ea77 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Tue, 15 Oct 2019 13:38:16 +0200
Subject: [PATCH 05/18] s3:mdssvc: make use of lp_parm_const_string()

We don't need any substitution for elasticsearch options.

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 source3/rpc_server/mdssvc/es_parser_test.c | 12 +++++------
 source3/rpc_server/mdssvc/mdssvc_es.c      | 24 ++++++++++++----------
 2 files changed, 18 insertions(+), 18 deletions(-)

diff --git a/source3/rpc_server/mdssvc/es_parser_test.c b/source3/rpc_server/mdssvc/es_parser_test.c
index 5751606fa1ea..7d88c67abffc 100644
--- a/source3/rpc_server/mdssvc/es_parser_test.c
+++ b/source3/rpc_server/mdssvc/es_parser_test.c
@@ -39,7 +39,7 @@ int main(int argc, char **argv)
 	json_t *mappings = NULL;
 	json_error_t json_error;
 	char *default_path = NULL;
-	char *path = NULL;
+	const char *path = NULL;
 	const char *query_string = NULL;
 	const char *path_scope = NULL;
 	char *es_query = NULL;
@@ -67,12 +67,10 @@ int main(int argc, char **argv)
 		return 1;
 	}
 
-	path = lp_parm_talloc_string(mem_ctx,
-				     GLOBAL_SECTION_SNUM,
-				     "elasticsearch",
-				     "mappings",
-				     default_path);
-	TALLOC_FREE(default_path);
+	path = lp_parm_const_string(GLOBAL_SECTION_SNUM,
+				    "elasticsearch",
+				    "mappings",
+				    default_path);
 	if (path == NULL) {
 		TALLOC_FREE(mem_ctx);
 		return 1;
diff --git a/source3/rpc_server/mdssvc/mdssvc_es.c b/source3/rpc_server/mdssvc/mdssvc_es.c
index 3c54abf01fde..aa169a80e1fe 100644
--- a/source3/rpc_server/mdssvc/mdssvc_es.c
+++ b/source3/rpc_server/mdssvc/mdssvc_es.c
@@ -55,7 +55,7 @@ static bool mdssvc_es_init(struct mdssvc_ctx *mdssvc_ctx)
 	struct mdssvc_es_ctx *mdssvc_es_ctx = NULL;
 	json_error_t json_error;
 	char *default_path = NULL;
-	char *path = NULL;
+	const char *path = NULL;
 
 	mdssvc_es_ctx = talloc_zero(mdssvc_ctx, struct mdssvc_es_ctx);
 	if (mdssvc_es_ctx == NULL) {
@@ -78,12 +78,10 @@ static bool mdssvc_es_init(struct mdssvc_ctx *mdssvc_ctx)
 		return false;
 	}
 
-	path = lp_parm_talloc_string(mdssvc_es_ctx,
-				     GLOBAL_SECTION_SNUM,
-				     "elasticsearch",
-				     "mappings",
-				     default_path);
-	TALLOC_FREE(default_path);
+	path = lp_parm_const_string(GLOBAL_SECTION_SNUM,
+				    "elasticsearch",
+				    "mappings",
+				    default_path);
 	if (path == NULL) {
 		TALLOC_FREE(mdssvc_es_ctx);
 		return false;
@@ -93,11 +91,10 @@ static bool mdssvc_es_init(struct mdssvc_ctx *mdssvc_ctx)
 	if (mdssvc_es_ctx->mappings == NULL) {
 		DBG_ERR("Opening mapping file [%s] failed: %s\n",
 			path, json_error.text);
-		TALLOC_FREE(path);
 		TALLOC_FREE(mdssvc_es_ctx);
 		return false;
 	}
-	TALLOC_FREE(path);
+	TALLOC_FREE(default_path);
 
 	mdssvc_ctx->backend_private = mdssvc_es_ctx;
 	return true;
@@ -187,6 +184,7 @@ static struct tevent_req *mds_es_connect_send(
 	struct tevent_req *req = NULL;
 	struct tevent_req *subreq = NULL;
 	struct mds_es_connect_state *state = NULL;
+	const char *server_addr = NULL;
 	bool use_tls;
 	NTSTATUS status;
 
@@ -199,12 +197,16 @@ static struct tevent_req *mds_es_connect_send(
 		.mds_es_ctx = mds_es_ctx,
 	};
 
-	state->server_addr = lp_parm_talloc_string(
-		state,
+	server_addr = lp_parm_const_string(
 		mds_es_ctx->mds_ctx->snum,
 		"elasticsearch",
 		"address",
 		"localhost");
+	state->server_addr = talloc_strdup(state, server_addr);
+	if (tevent_req_nomem(state->server_addr, req)) {
+		return tevent_req_post(req, ev);
+	}
+
 	state->server_port = lp_parm_int(
 		mds_es_ctx->mds_ctx->snum,
 		"elasticsearch",
-- 
2.17.1


From 4e7c1c63dd99d758d403012b140b4d6638987064 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Tue, 15 Oct 2019 13:56:44 +0200
Subject: [PATCH 06/18] s3:vfs_tsmsm: make use of lp_parm_substituted_string()

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 source3/modules/vfs_tsmsm.c | 14 ++++++++------
 1 file changed, 8 insertions(+), 6 deletions(-)

diff --git a/source3/modules/vfs_tsmsm.c b/source3/modules/vfs_tsmsm.c
index 85a9bfdfa9c0..27b213696736 100644
--- a/source3/modules/vfs_tsmsm.c
+++ b/source3/modules/vfs_tsmsm.c
@@ -89,6 +89,8 @@ static void tsmsm_free_data(void **pptr) {
 static int tsmsm_connect(struct vfs_handle_struct *handle,
 			 const char *service,
 			 const char *user) {
+	const struct loadparm_substitution *lp_sub =
+		loadparm_s3_global_substitution();
 	struct tsmsm_struct *tsmd;
 	const char *fres;
 	const char *tsmname;
@@ -115,18 +117,18 @@ static int tsmsm_connect(struct vfs_handle_struct *handle,
 	tsmname = (handle->param ? handle->param : "tsmsm");
 	
 	/* Get 'hsm script' and 'dmapi attribute' parameters to tsmd context */
-	tsmd->hsmscript = lp_parm_talloc_string(
-		tsmd, SNUM(handle->conn), tsmname,
+	tsmd->hsmscript = lp_parm_substituted_string(
+		tsmd, lp_sub, SNUM(handle->conn), tsmname,
 		"hsm script", NULL);
 	talloc_steal(tsmd, tsmd->hsmscript);
 	
-	tsmd->attrib_name = lp_parm_talloc_string(
-		tsmd, SNUM(handle->conn), tsmname,
+	tsmd->attrib_name = lp_parm_substituted_string(
+		tsmd, lp_sub, SNUM(handle->conn), tsmname,
 		"dmapi attribute", DM_ATTRIB_OBJECT);
 	talloc_steal(tsmd, tsmd->attrib_name);
 	
-	tsmd->attrib_value = lp_parm_talloc_string(
-		tsmd, SNUM(handle->conn), tsmname,
+	tsmd->attrib_value = lp_parm_substituted_string(
+		tsmd, lp_sub, SNUM(handle->conn), tsmname,
 		"dmapi value", NULL);
 	talloc_steal(tsmd, tsmd->attrib_value);
 	
-- 
2.17.1


From 07d4fe31ce4b9b34518a003a9e5c43dafd0f5ef3 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Tue, 15 Oct 2019 13:58:48 +0200
Subject: [PATCH 07/18] s3:vfs_streams_depot: make use of
 lp_parm_substituted_string()

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 source3/modules/vfs_streams_depot.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/source3/modules/vfs_streams_depot.c b/source3/modules/vfs_streams_depot.c
index 9f3b79992bc1..9b0e73b25b78 100644
--- a/source3/modules/vfs_streams_depot.c
+++ b/source3/modules/vfs_streams_depot.c
@@ -115,6 +115,8 @@ static char *stream_dir(vfs_handle_struct *handle,
 			const struct smb_filename *smb_fname,
 			const SMB_STRUCT_STAT *base_sbuf, bool create_it)
 {
+	const struct loadparm_substitution *lp_sub =
+		loadparm_s3_global_substitution();
 	uint32_t hash;
 	struct smb_filename *smb_fname_hash = NULL;
 	char *result = NULL;
@@ -141,7 +143,7 @@ static char *stream_dir(vfs_handle_struct *handle,
 		goto fail;
 	}
 
-	rootdir = lp_parm_talloc_string(talloc_tos(),
+	rootdir = lp_parm_substituted_string(talloc_tos(), lp_sub,
 		SNUM(handle->conn), "streams_depot", "directory",
 		tmp);
 	if (rootdir == NULL) {
-- 
2.17.1


From 77fa656fea086ef34e3146766489afdf6c358162 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Tue, 15 Oct 2019 14:00:29 +0200
Subject: [PATCH 08/18] s3:vfs_nfs4acl_xattr: make use of
 lp_parm_substituted_string()

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 source3/modules/vfs_nfs4acl_xattr.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/source3/modules/vfs_nfs4acl_xattr.c b/source3/modules/vfs_nfs4acl_xattr.c
index d03079be831e..f8cbe7964d14 100644
--- a/source3/modules/vfs_nfs4acl_xattr.c
+++ b/source3/modules/vfs_nfs4acl_xattr.c
@@ -476,6 +476,8 @@ static int nfs4acl_connect(struct vfs_handle_struct *handle,
 			   const char *service,
 			   const char *user)
 {
+	const struct loadparm_substitution *lp_sub =
+		loadparm_s3_global_substitution();
 	struct nfs4acl_config *config = NULL;
 	const struct enum_list *default_acl_style_list = NULL;
 	const char *default_xattr_name = NULL;
@@ -551,7 +553,7 @@ static int nfs4acl_connect(struct vfs_handle_struct *handle,
 						 default_acl_style_list,
 						 DEFAULT_ACL_EVERYONE);
 
-	config->xattr_name = lp_parm_talloc_string(config,
+	config->xattr_name = lp_parm_substituted_string(config, lp_sub,
 						   SNUM(handle->conn),
 						   "nfs4acl_xattr",
 						   "xattr_name",
-- 
2.17.1


From 46620542699002999e26a5b2322b56656355f88e Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Tue, 15 Oct 2019 14:04:27 +0200
Subject: [PATCH 09/18] s3:vfs_glusterfs: make use of
 lp_parm_substituted_string()

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 source3/modules/vfs_glusterfs.c | 19 ++++++++++++++-----
 1 file changed, 14 insertions(+), 5 deletions(-)

diff --git a/source3/modules/vfs_glusterfs.c b/source3/modules/vfs_glusterfs.c
index 3e28fcd143fe..646a5f59278f 100644
--- a/source3/modules/vfs_glusterfs.c
+++ b/source3/modules/vfs_glusterfs.c
@@ -268,6 +268,8 @@ static int vfs_gluster_connect(struct vfs_handle_struct *handle,
 			       const char *service,
 			       const char *user)
 {
+	const struct loadparm_substitution *lp_sub =
+		loadparm_s3_global_substitution();
 	const char *volfile_servers;
 	const char *volume;
 	char *logfile;
@@ -281,14 +283,21 @@ static int vfs_gluster_connect(struct vfs_handle_struct *handle,
 		ret = -1;
 		goto done;
 	}
-	logfile = lp_parm_talloc_string(tmp_ctx, SNUM(handle->conn), "glusterfs",
-				       "logfile", NULL);
+	logfile = lp_parm_substituted_string(tmp_ctx,
+					     lp_sub,
+					     SNUM(handle->conn),
+					     "glusterfs",
+					     "logfile",
+					     NULL);
 
 	loglevel = lp_parm_int(SNUM(handle->conn), "glusterfs", "loglevel", -1);
 
-	volfile_servers = lp_parm_talloc_string(tmp_ctx, SNUM(handle->conn),
-					       "glusterfs", "volfile_server",
-					       NULL);
+	volfile_servers = lp_parm_substituted_string(tmp_ctx,
+						     lp_sub,
+						     SNUM(handle->conn),
+						     "glusterfs",
+						     "volfile_server",
+						     NULL);
 	if (volfile_servers == NULL) {
 		volfile_servers = DEFAULT_VOLFILE_SERVER;
 	}
-- 
2.17.1


From f63f0c94f5b53e5904866ee9521bdfaa2a3d520f Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Tue, 15 Oct 2019 14:05:24 +0200
Subject: [PATCH 10/18] s3:parm: remove unused lp_parm_talloc_string()

Callers should use lp_parm_substituted_string()
directly or just use lp_parm_const_string().

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 source3/include/proto.h  |  1 -
 source3/param/loadparm.c | 14 --------------
 2 files changed, 15 deletions(-)

diff --git a/source3/include/proto.h b/source3/include/proto.h
index f19832a9089d..c341ca6cd91b 100644
--- a/source3/include/proto.h
+++ b/source3/include/proto.h
@@ -772,7 +772,6 @@ int lp_wi_scan_global_parametrics(
 		   void *private_data),
 	void *private_data);
 
-char *lp_parm_talloc_string(TALLOC_CTX *ctx, int snum, const char *type, const char *option, const char *def);
 const char *lp_parm_const_string(int snum, const char *type, const char *option, const char *def);
 struct loadparm_service;
 const char *lp_parm_const_string_service(struct loadparm_service *service, const char *type,
diff --git a/source3/param/loadparm.c b/source3/param/loadparm.c
index 9db8e1e03eb0..64062a23655b 100644
--- a/source3/param/loadparm.c
+++ b/source3/param/loadparm.c
@@ -1264,20 +1264,6 @@ char *lp_parm_substituted_string(TALLOC_CTX *mem_ctx,
 	return lp_substituted_string(mem_ctx, lp_sub, data->value);
 }
 
-char *lp_parm_talloc_string(TALLOC_CTX *mem_ctx,
-			    int snum,
-			    const char *type,
-			    const char *option,
-			    const char *def)
-{
-	return lp_parm_substituted_string(mem_ctx,
-					  &s3_global_substitution,
-					  snum,
-					  type,
-					  option,
-					  def);
-}
-
 /* Return parametric option from a given service. Type is a part of option before ':' */
 /* Parametric option has following syntax: 'Type: option = value' */
 const char *lp_parm_const_string(int snum, const char *type, const char *option, const char *def)
-- 
2.17.1


From 023eb38a2b70f69c93d57aabbc95079065df61ac Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Tue, 15 Oct 2019 16:50:34 +0200
Subject: [PATCH 11/18] s3_param: add lp_substituted_string hook

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 lib/param/s3_param.h         | 3 +++
 source3/param/loadparm_ctx.c | 1 +
 2 files changed, 4 insertions(+)

diff --git a/lib/param/s3_param.h b/lib/param/s3_param.h
index f31c5bcbaa95..1ef7fc5d63f1 100644
--- a/lib/param/s3_param.h
+++ b/lib/param/s3_param.h
@@ -12,6 +12,9 @@ struct loadparm_s3_helpers
 	bool (*store_cmdline)(const char *pszParmName, const char *pszParmValue);
 	void (*dump)(FILE *f, bool show_defaults, int maxtoprint);
 	char * (*lp_string)(TALLOC_CTX *ctx, const char *in);
+	char *(*lp_substituted_string)(TALLOC_CTX *ctx,
+				const struct loadparm_substitution *lp_sub,
+				const char *in);
 	bool (*lp_include)(struct loadparm_context*, struct loadparm_service *,
 		       	const char *, char **);
 	void (*init_ldap_debugging)(void);
diff --git a/source3/param/loadparm_ctx.c b/source3/param/loadparm_ctx.c
index 645b787acb9f..272da444189a 100644
--- a/source3/param/loadparm_ctx.c
+++ b/source3/param/loadparm_ctx.c
@@ -67,6 +67,7 @@ static struct loadparm_s3_helpers s3_fns =
 	.store_cmdline = store_lp_set_cmdline,
 	.dump = lp_dump,
 	.lp_string = lp_string,
+	.lp_substituted_string = lp_substituted_string,
 	.lp_include = lp_include,
 	.init_ldap_debugging = init_ldap_debugging,
 	.set_netbios_aliases = set_netbios_aliases,
-- 
2.17.1


From 59b70f0be1c3d44ee62ab77efa1c032ae776d57d Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Tue, 15 Oct 2019 16:52:30 +0200
Subject: [PATCH 12/18] param: add FN_{GLOBAL,LOCAL}_SUBSTITUTED_STRING support

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 lib/param/loadparm.c     | 13 +++++++++++++
 lib/param/param.h        |  1 +
 script/generate_param.py | 13 ++++++++++++-
 source3/lib/util_path.c  |  1 +
 source3/param/loadparm.c |  6 ++++++
 5 files changed, 33 insertions(+), 1 deletion(-)

diff --git a/lib/param/loadparm.c b/lib/param/loadparm.c
index 9a577aa188c5..f6c292995ac2 100644
--- a/lib/param/loadparm.c
+++ b/lib/param/loadparm.c
@@ -165,6 +165,16 @@ static struct loadparm_context *global_loadparm_context;
 	 }								\
 	 return lp_ctx->globals->var_name ? talloc_strdup(ctx, lpcfg_string(lp_ctx->globals->var_name)) : talloc_strdup(ctx, ""); \
 }
+#define FN_GLOBAL_SUBSTITUTED_STRING(fn_name,var_name) \
+ _PUBLIC_ char *lpcfg_ ## fn_name(struct loadparm_context *lp_ctx, \
+		 const struct loadparm_substitution *lp_sub, TALLOC_CTX *ctx) \
+{ \
+	 if (lp_ctx == NULL) return NULL;				\
+	 if (lp_ctx->s3_fns) {						\
+		 return lp_ctx->globals->var_name ? lp_ctx->s3_fns->lp_substituted_string(ctx, lp_sub, lp_ctx->globals->var_name) : talloc_strdup(ctx, ""); \
+	 }								\
+	 return lp_ctx->globals->var_name ? talloc_strdup(ctx, lpcfg_string(lp_ctx->globals->var_name)) : talloc_strdup(ctx, ""); \
+}
 
 #define FN_GLOBAL_CONST_STRING(fn_name,var_name)				\
  _PUBLIC_ const char *lpcfg_ ## fn_name(struct loadparm_context *lp_ctx) { \
@@ -198,6 +208,9 @@ static struct loadparm_context *global_loadparm_context;
 	 return(talloc_strdup(ctx, lpcfg_string((const char *)((service != NULL && service->val != NULL) ? service->val : sDefault->val)))); \
  }
 
+/* just a copy for now */
+#define FN_LOCAL_SUBSTITUTED_STRING(fn_name,val) FN_LOCAL_STRING(fn_name,val)
+
 #define FN_LOCAL_CONST_STRING(fn_name,val) \
  _PUBLIC_ const char *lpcfg_ ## fn_name(struct loadparm_service *service, \
 					struct loadparm_service *sDefault) { \
diff --git a/lib/param/param.h b/lib/param/param.h
index 0a3bde6c5cb5..44f01917a456 100644
--- a/lib/param/param.h
+++ b/lib/param/param.h
@@ -41,6 +41,7 @@ struct smbsrv_connection;
 
 struct loadparm_context;
 struct loadparm_service;
+struct loadparm_substitution;
 struct smbcli_options;
 struct smbcli_session_options;
 struct gensec_settings;
diff --git a/script/generate_param.py b/script/generate_param.py
index 5f8a50562d4c..388b6fd1211c 100644
--- a/script/generate_param.py
+++ b/script/generate_param.py
@@ -75,6 +75,7 @@ def iterate_all(path):
             continue
 
         constant = parameter.attrib.get("constant")
+        substitution = parameter.attrib.get("substitution")
         parm = parameter.attrib.get("parm")
         if name is None or param_type is None or context is None:
             raise Exception("Error parsing parameter: " + name)
@@ -89,6 +90,7 @@ def iterate_all(path):
                'context': context,
                'function': func,
                'constant': (constant == '1'),
+               'substitution': (substitution == '1'),
                'parm': (parm == '1'),
                'synonym' : synonym,
                'generated' : generated,
@@ -135,6 +137,8 @@ def generate_functions(path_in, path_out):
             output_string += temp
             if parameter['constant']:
                 output_string += "_CONST"
+            if parameter['substitution']:
+                output_string += "_SUBSTITUTED"
             if parameter['parm']:
                 output_string += "_PARM"
             temp = param_type_dict.get(parameter['type'])
@@ -192,7 +196,14 @@ def make_s3_param_proto(path_in, path_out):
             else:
                 param = "int"
 
-            if parameter['type'] == 'string' and not parameter['constant']:
+            if parameter['type'] == 'string' and parameter['substitution']:
+                if parameter['context'] == 'G':
+                    output_string += '(TALLOC_CTX *ctx, const struct loadparm_substitution *lp_sub);\n'
+                elif parameter['context'] == 'S':
+                    output_string += '(TALLOC_CTX *ctx, const struct loadparm_substitution *lp_sub, %s);\n' % param
+                else:
+                    raise Exception(parameter['name'] + " has an invalid param type " + parameter['type'])
+            elif parameter['type'] == 'string' and not parameter['constant']:
                 if parameter['context'] == 'G':
                     output_string += '(TALLOC_CTX *ctx);\n'
                 elif parameter['context'] == 'S':
diff --git a/source3/lib/util_path.c b/source3/lib/util_path.c
index d9fed29c2a51..63d01b810005 100644
--- a/source3/lib/util_path.c
+++ b/source3/lib/util_path.c
@@ -26,6 +26,7 @@
 #include "lib/util/samba_util.h"
 #include "lib/util_path.h"
 
+struct loadparm_substitution;
 struct share_params;
 #include "source3/param/param_proto.h"
 
diff --git a/source3/param/loadparm.c b/source3/param/loadparm.c
index 64062a23655b..f8e5dd97057d 100644
--- a/source3/param/loadparm.c
+++ b/source3/param/loadparm.c
@@ -1059,6 +1059,9 @@ char *lp_string(TALLOC_CTX *ctx, const char *s)
 
 #define FN_GLOBAL_STRING(fn_name,ptr) \
 char *lp_ ## fn_name(TALLOC_CTX *ctx) {return(lp_string((ctx), *(char **)(&Globals.ptr) ? *(char **)(&Globals.ptr) : ""));}
+#define FN_GLOBAL_SUBSTITUTED_STRING(fn_name,ptr) \
+char *lp_ ## fn_name(TALLOC_CTX *ctx, const struct loadparm_substitution *lp_sub) \
+ {return lp_substituted_string(ctx, lp_sub, *(char **)(&Globals.ptr) ? *(char **)(&Globals.ptr) : "");}
 #define FN_GLOBAL_CONST_STRING(fn_name,ptr) \
  const char *lp_ ## fn_name(void) {return(*(const char * const *)(&Globals.ptr) ? *(const char * const *)(&Globals.ptr) : "");}
 #define FN_GLOBAL_LIST(fn_name,ptr) \
@@ -1072,6 +1075,9 @@ char *lp_ ## fn_name(TALLOC_CTX *ctx) {return(lp_string((ctx), *(char **)(&Globa
 
 #define FN_LOCAL_STRING(fn_name,val) \
 char *lp_ ## fn_name(TALLOC_CTX *ctx,int i) {return(lp_string((ctx), (LP_SNUM_OK(i) && ServicePtrs[(i)]->val) ? ServicePtrs[(i)]->val : sDefault.val));}
+#define FN_LOCAL_SUBSTITUTED_STRING(fn_name,val) \
+char *lp_ ## fn_name(TALLOC_CTX *ctx, const struct loadparm_substitution *lp_sub, int i) \
+ {return lp_substituted_string((ctx), lp_sub, (LP_SNUM_OK(i) && ServicePtrs[(i)]->val) ? ServicePtrs[(i)]->val : sDefault.val);}
 #define FN_LOCAL_CONST_STRING(fn_name,val) \
  const char *lp_ ## fn_name(int i) {return (const char *)((LP_SNUM_OK(i) && ServicePtrs[(i)]->val) ? ServicePtrs[(i)]->val : sDefault.val);}
 #define FN_LOCAL_LIST(fn_name,val) \
-- 
2.17.1


From 7aeb944ad1cd4dc6ae0f37c524a174316d6596fa Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Tue, 15 Oct 2019 16:54:45 +0200
Subject: [PATCH 13/18] smbdotconf: mark "aio write behind" with
 substitution="1"

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 docs-xml/smbdotconf/tuning/aiowritebehind.xml | 1 +
 source3/smbd/service.c                        | 4 +++-
 2 files changed, 4 insertions(+), 1 deletion(-)

diff --git a/docs-xml/smbdotconf/tuning/aiowritebehind.xml b/docs-xml/smbdotconf/tuning/aiowritebehind.xml
index c88cd97fa970..d60af7154fd1 100644
--- a/docs-xml/smbdotconf/tuning/aiowritebehind.xml
+++ b/docs-xml/smbdotconf/tuning/aiowritebehind.xml
@@ -1,6 +1,7 @@
 <samba:parameter name="aio write behind"
                  context="S"
 		 type="string"
+                 substitution="1"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
 	<para>If Samba has been built with asynchronous I/O support,
diff --git a/source3/smbd/service.c b/source3/smbd/service.c
index 7e252a459b3a..12bf73378dac 100644
--- a/source3/smbd/service.c
+++ b/source3/smbd/service.c
@@ -530,6 +530,8 @@ static NTSTATUS make_connection_snum(struct smbXsrv_connection *xconn,
 					const char *pdev)
 {
 	struct smbd_server_connection *sconn = xconn->client->sconn;
+	const struct loadparm_substitution *lp_sub =
+		loadparm_s3_global_substitution();
 	struct smb_filename *smb_fname_cpath = NULL;
 	fstring dev;
 	int ret;
@@ -824,7 +826,7 @@ static NTSTATUS make_connection_snum(struct smbXsrv_connection *xconn,
 		set_namearray( &conn->veto_oplock_list,
 			       lp_veto_oplock_files(talloc_tos(), snum));
 		set_namearray( &conn->aio_write_behind_list,
-				lp_aio_write_behind(talloc_tos(), snum));
+				lp_aio_write_behind(talloc_tos(), lp_sub, snum));
 	}
 	smb_fname_cpath = synthetic_smb_fname(talloc_tos(),
 					conn->connectpath,
-- 
2.17.1


From b970905d1cd29dc821f1055d963bc85356fa0369 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Tue, 15 Oct 2019 16:54:45 +0200
Subject: [PATCH 14/18] smbdotconf: mark "comment" with substitution="1"

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 docs-xml/smbdotconf/base/comment.xml        |  1 +
 source3/rpc_server/spoolss/srv_spoolss_nt.c | 12 ++++++---
 source3/rpc_server/srvsvc/srv_srvsvc_nt.c   | 29 +++++++++++++++------
 source3/smbd/lanman.c                       |  6 +++--
 source3/smbd/msdfs.c                        |  4 ++-
 5 files changed, 38 insertions(+), 14 deletions(-)

diff --git a/docs-xml/smbdotconf/base/comment.xml b/docs-xml/smbdotconf/base/comment.xml
index b0dd91c8839c..c5aba83451a6 100644
--- a/docs-xml/smbdotconf/base/comment.xml
+++ b/docs-xml/smbdotconf/base/comment.xml
@@ -1,6 +1,7 @@
 <samba:parameter name="comment"
                  context="S"
                  type="string"
+                 substitution="1"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
     <para>This is a text field that is seen next to a share 
diff --git a/source3/rpc_server/spoolss/srv_spoolss_nt.c b/source3/rpc_server/spoolss/srv_spoolss_nt.c
index f32b465afb67..c80996532ad5 100644
--- a/source3/rpc_server/spoolss/srv_spoolss_nt.c
+++ b/source3/rpc_server/spoolss/srv_spoolss_nt.c
@@ -2805,10 +2805,12 @@ static void spoolss_notify_comment(struct messaging_context *msg_ctx,
 				   struct spoolss_PrinterInfo2 *pinfo2,
 				   TALLOC_CTX *mem_ctx)
 {
+	const struct loadparm_substitution *lp_sub =
+		loadparm_s3_global_substitution();
 	const char *p;
 
 	if (*pinfo2->comment == '\0') {
-		p = lp_comment(talloc_tos(), snum);
+		p = lp_comment(talloc_tos(), lp_sub, snum);
 	} else {
 		p = pinfo2->comment;
 	}
@@ -3970,12 +3972,14 @@ static WERROR construct_printer_info1(TALLOC_CTX *mem_ctx,
 				      struct spoolss_PrinterInfo1 *r,
 				      int snum)
 {
+	const struct loadparm_substitution *lp_sub =
+		loadparm_s3_global_substitution();
 	WERROR result;
 
 	r->flags		= flags;
 
 	if (info2->comment == NULL || info2->comment[0] == '\0') {
-		r->comment	= lp_comment(mem_ctx, snum);
+		r->comment	= lp_comment(mem_ctx, lp_sub, snum);
 	} else {
 		r->comment	= talloc_strdup(mem_ctx, info2->comment); /* saved comment */
 	}
@@ -4007,6 +4011,8 @@ static WERROR construct_printer_info2(TALLOC_CTX *mem_ctx,
 				      struct spoolss_PrinterInfo2 *r,
 				      int snum)
 {
+	const struct loadparm_substitution *lp_sub =
+		loadparm_s3_global_substitution();
 	int count;
 	print_status_struct status;
 	WERROR result;
@@ -4033,7 +4039,7 @@ static WERROR construct_printer_info2(TALLOC_CTX *mem_ctx,
 	W_ERROR_HAVE_NO_MEMORY(r->drivername);
 
 	if (info2->comment[0] == '\0') {
-		r->comment	= lp_comment(mem_ctx, snum);
+		r->comment	= lp_comment(mem_ctx, lp_sub, snum);
 	} else {
 		r->comment	= talloc_strdup(mem_ctx, info2->comment);
 	}
diff --git a/source3/rpc_server/srvsvc/srv_srvsvc_nt.c b/source3/rpc_server/srvsvc/srv_srvsvc_nt.c
index 6246a61672e5..281861ce9e1d 100644
--- a/source3/rpc_server/srvsvc/srv_srvsvc_nt.c
+++ b/source3/rpc_server/srvsvc/srv_srvsvc_nt.c
@@ -221,8 +221,10 @@ static void init_srv_share_info_1(struct pipes_struct *p,
 				  struct srvsvc_NetShareInfo1 *r,
 				  int snum)
 {
+	const struct loadparm_substitution *lp_sub =
+		loadparm_s3_global_substitution();
 	char *net_name = lp_servicename(talloc_tos(), snum);
-	char *remark = lp_comment(p->mem_ctx, snum);
+	char *remark = lp_comment(p->mem_ctx, lp_sub, snum);
 
 	if (remark) {
 		remark = talloc_sub_advanced(
@@ -245,13 +247,15 @@ static void init_srv_share_info_2(struct pipes_struct *p,
 				  struct srvsvc_NetShareInfo2 *r,
 				  int snum)
 {
+	const struct loadparm_substitution *lp_sub =
+		loadparm_s3_global_substitution();
 	char *remark = NULL;
 	char *path = NULL;
 	int max_connections = lp_max_connections(snum);
 	uint32_t max_uses = max_connections!=0 ? max_connections : (uint32_t)-1;
 	char *net_name = lp_servicename(talloc_tos(), snum);
 
-	remark = lp_comment(p->mem_ctx, snum);
+	remark = lp_comment(p->mem_ctx, lp_sub, snum);
 	if (remark) {
 		remark = talloc_sub_advanced(
 			p->mem_ctx, lp_servicename(talloc_tos(), snum),
@@ -314,8 +318,10 @@ static void map_generic_share_sd_bits(struct security_descriptor *psd)
 static void init_srv_share_info_501(struct pipes_struct *p,
 				    struct srvsvc_NetShareInfo501 *r, int snum)
 {
+	const struct loadparm_substitution *lp_sub =
+		loadparm_s3_global_substitution();
 	const char *net_name = lp_servicename(talloc_tos(), snum);
-	char *remark = lp_comment(p->mem_ctx, snum);
+	char *remark = lp_comment(p->mem_ctx, lp_sub, snum);
 
 	if (remark) {
 		remark = talloc_sub_advanced(
@@ -343,13 +349,15 @@ static void init_srv_share_info_501(struct pipes_struct *p,
 static void init_srv_share_info_502(struct pipes_struct *p,
 				    struct srvsvc_NetShareInfo502 *r, int snum)
 {
+	const struct loadparm_substitution *lp_sub =
+		loadparm_s3_global_substitution();
 	const char *net_name = lp_servicename(talloc_tos(), snum);
 	char *path = NULL;
 	struct security_descriptor *sd = NULL;
 	struct sec_desc_buf *sd_buf = NULL;
 	size_t sd_size = 0;
 	TALLOC_CTX *ctx = p->mem_ctx;
-	char *remark = lp_comment(ctx, snum);
+	char *remark = lp_comment(ctx, lp_sub, snum);
 
 	if (remark) {
 		remark = talloc_sub_advanced(
@@ -390,7 +398,9 @@ static void init_srv_share_info_1004(struct pipes_struct *p,
 				     struct srvsvc_NetShareInfo1004 *r,
 				     int snum)
 {
-	char *remark = lp_comment(p->mem_ctx, snum);
+	const struct loadparm_substitution *lp_sub =
+		loadparm_s3_global_substitution();
+	char *remark = lp_comment(p->mem_ctx, lp_sub, snum);
 
 	if (remark) {
 		remark = talloc_sub_advanced(
@@ -1710,6 +1720,8 @@ WERROR _srvsvc_NetShareGetInfo(struct pipes_struct *p,
 WERROR _srvsvc_NetShareSetInfo(struct pipes_struct *p,
 			       struct srvsvc_NetShareSetInfo *r)
 {
+	const struct loadparm_substitution *lp_sub =
+		loadparm_s3_global_substitution();
 	char *command = NULL;
 	char *share_name = NULL;
 	char *comment = NULL;
@@ -1830,7 +1842,7 @@ WERROR _srvsvc_NetShareSetInfo(struct pipes_struct *p,
 		}
 
 		pathname = lp_path(ctx, snum);
-		comment = lp_comment(ctx, snum);
+		comment = lp_comment(ctx, lp_sub, snum);
 		type = STYPE_DISKTREE;
 		break;
 	case 1006:
@@ -1838,7 +1850,7 @@ WERROR _srvsvc_NetShareSetInfo(struct pipes_struct *p,
 		return WERR_ACCESS_DENIED;
 	case 1501:
 		pathname = lp_path(ctx, snum);
-		comment = lp_comment(ctx, snum);
+		comment = lp_comment(ctx, lp_sub, snum);
 		psd = info->info1501->sd;
 		map_generic_share_sd_bits(psd);
 		type = STYPE_DISKTREE;
@@ -1878,7 +1890,8 @@ WERROR _srvsvc_NetShareSetInfo(struct pipes_struct *p,
 
 	/* Only call modify function if something changed. */
 
-	if (strcmp(path, lp_path(talloc_tos(), snum)) || strcmp(comment, lp_comment(talloc_tos(), snum))
+	if (strcmp(path, lp_path(talloc_tos(), snum))
+			|| strcmp(comment, lp_comment(talloc_tos(), lp_sub, snum))
 			|| (lp_max_connections(snum) != max_connections)
 			|| csc_policy_changed) {
 
diff --git a/source3/smbd/lanman.c b/source3/smbd/lanman.c
index 50451b2778dc..48988f1def3a 100644
--- a/source3/smbd/lanman.c
+++ b/source3/smbd/lanman.c
@@ -1888,6 +1888,8 @@ static int fill_share_info(connection_struct *conn, int snum, int uLevel,
  			   char** buf, int* buflen,
  			   char** stringbuf, int* stringspace, char* baseaddr)
 {
+	const struct loadparm_substitution *lp_sub =
+		loadparm_s3_global_substitution();
 	int struct_len;
 	char* p;
 	char* p2;
@@ -1915,7 +1917,7 @@ static int fill_share_info(connection_struct *conn, int snum, int uLevel,
 		len = 0;
 
 		if (uLevel > 0) {
-			len += StrlenExpanded(conn,snum,lp_comment(talloc_tos(), snum));
+			len += StrlenExpanded(conn,snum,lp_comment(talloc_tos(), lp_sub, snum));
 		}
 		if (uLevel > 1) {
 			len += strlen(lp_path(talloc_tos(), snum)) + 1;
@@ -1962,7 +1964,7 @@ static int fill_share_info(connection_struct *conn, int snum, int uLevel,
 		}
 		SSVAL(p,14,type);		/* device type */
 		SIVAL(p,16,PTR_DIFF(p2,baseaddr));
-		len += CopyExpanded(conn,snum,&p2,lp_comment(talloc_tos(),snum),&l2);
+		len += CopyExpanded(conn,snum,&p2,lp_comment(talloc_tos(), lp_sub, snum),&l2);
 	}
 
 	if (uLevel > 1) {
diff --git a/source3/smbd/msdfs.c b/source3/smbd/msdfs.c
index fe8553215a42..7ef368240d5c 100644
--- a/source3/smbd/msdfs.c
+++ b/source3/smbd/msdfs.c
@@ -1264,6 +1264,8 @@ bool create_junction(TALLOC_CTX *ctx,
 		bool allow_broken_path,
 		struct junction_map *jucn)
 {
+	const struct loadparm_substitution *lp_sub =
+		loadparm_s3_global_substitution();
 	int snum;
 	bool dummy;
 	struct dfs_path *pdp = talloc(ctx,struct dfs_path);
@@ -1299,7 +1301,7 @@ bool create_junction(TALLOC_CTX *ctx,
 
 	jucn->service_name = talloc_strdup(ctx, pdp->servicename);
 	jucn->volume_name = talloc_strdup(ctx, pdp->reqpath);
-	jucn->comment = lp_comment(ctx, snum);
+	jucn->comment = lp_comment(ctx, lp_sub, snum);
 
 	TALLOC_FREE(pdp);
 	if (!jucn->service_name || !jucn->volume_name || ! jucn->comment) {
-- 
2.17.1


From 8262f306416ea6cb188e354e6f602b89126b5598 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Tue, 15 Oct 2019 16:54:45 +0200
Subject: [PATCH 15/18] smbdotconf: mark "dfree command" with substitution="1"

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 docs-xml/smbdotconf/misc/dfreecommand.xml | 3 ++-
 source3/smbd/dfree.c                      | 4 +++-
 2 files changed, 5 insertions(+), 2 deletions(-)

diff --git a/docs-xml/smbdotconf/misc/dfreecommand.xml b/docs-xml/smbdotconf/misc/dfreecommand.xml
index a1eed4948a66..b12ee0f29234 100644
--- a/docs-xml/smbdotconf/misc/dfreecommand.xml
+++ b/docs-xml/smbdotconf/misc/dfreecommand.xml
@@ -1,6 +1,7 @@
 <samba:parameter name="dfree command"
 	         context="S"
-			 type="string"
+		 type="string"
+		 substitution="1"
 		 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
 
diff --git a/source3/smbd/dfree.c b/source3/smbd/dfree.c
index 31900c847f11..d083ce22797f 100644
--- a/source3/smbd/dfree.c
+++ b/source3/smbd/dfree.c
@@ -57,6 +57,8 @@ static uint64_t sys_disk_free(connection_struct *conn,
 			      uint64_t *dfree,
 			      uint64_t *dsize)
 {
+	const struct loadparm_substitution *lp_sub =
+		loadparm_s3_global_substitution();
 	uint64_t dfree_retval;
 	uint64_t dfree_q = 0;
 	uint64_t bsize_q = 0;
@@ -72,7 +74,7 @@ static uint64_t sys_disk_free(connection_struct *conn,
 	 * If external disk calculation specified, use it.
 	 */
 
-	dfree_command = lp_dfree_command(talloc_tos(), SNUM(conn));
+	dfree_command = lp_dfree_command(talloc_tos(), lp_sub, SNUM(conn));
 	if (dfree_command && *dfree_command) {
 		const char *p;
 		char **lines = NULL;
-- 
2.17.1


From 547e73810884a391636e2ec777240dc8e29af401 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Tue, 15 Oct 2019 16:54:45 +0200
Subject: [PATCH 16/18] smbdotconf: mark "cups options" with substitution="1"

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 docs-xml/smbdotconf/printing/cupsoptions.xml | 1 +
 source3/printing/print_cups.c                | 4 +++-
 2 files changed, 4 insertions(+), 1 deletion(-)

diff --git a/docs-xml/smbdotconf/printing/cupsoptions.xml b/docs-xml/smbdotconf/printing/cupsoptions.xml
index 7e6b07db9f5d..833ba30a0d31 100644
--- a/docs-xml/smbdotconf/printing/cupsoptions.xml
+++ b/docs-xml/smbdotconf/printing/cupsoptions.xml
@@ -1,6 +1,7 @@
 <samba:parameter name="cups options"
                  context="S"
                  type="string"
+                 substitution="1"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
     <para>
diff --git a/source3/printing/print_cups.c b/source3/printing/print_cups.c
index 738307f47b4c..2a1b2324f251 100644
--- a/source3/printing/print_cups.c
+++ b/source3/printing/print_cups.c
@@ -942,6 +942,8 @@ static int cups_job_submit(int snum, struct printjob *pjob,
 			   char *lpq_cmd)
 {
 	TALLOC_CTX *frame = talloc_stackframe();
+	const struct loadparm_substitution *lp_sub =
+		loadparm_s3_global_substitution();
 	int		ret = 1;		/* Return value */
 	http_t		*http = NULL;		/* HTTP connection to server */
 	ipp_t		*request = NULL,	/* IPP Request */
@@ -1049,7 +1051,7 @@ static int cups_job_submit(int snum, struct printjob *pjob,
 	 */
 
 	if (!push_utf8_talloc(frame, &cupsoptions,
-			      lp_cups_options(talloc_tos(), snum), &size)) {
+			      lp_cups_options(talloc_tos(), lp_sub, snum), &size)) {
 		goto out;
 	}
 	num_options = 0;
-- 
2.17.1


From cccd536e36ab77c6ac80bc634f593b7282c9aae4 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Tue, 15 Oct 2019 10:07:48 +0200
Subject: [PATCH 17/18] auth/samba_impersonation.*

---
 auth/samba_impersonation.c | 116 +++++++++++++++++++++++++++++++++++++
 auth/samba_impersonation.h |  41 +++++++++++++
 2 files changed, 157 insertions(+)
 create mode 100644 auth/samba_impersonation.c
 create mode 100644 auth/samba_impersonation.h

diff --git a/auth/samba_impersonation.c b/auth/samba_impersonation.c
new file mode 100644
index 000000000000..2f2f8f68888c
--- /dev/null
+++ b/auth/samba_impersonation.c
@@ -0,0 +1,116 @@
+/*
+   Unix SMB/Netbios implementation.
+
+   Generic impersonation infrastructure
+
+   Copyright (C) Stefan Metzmacher 2019
+
+   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 "system/filesys.h"
+#include "system/threads.h"
+#include "auth/samba_impersonation.h"
+
+static uint64_t samba_impersonation_cache_id_counter;
+static __thread uint64_t samba_impersonation_cache_id_current;
+
+struct samba_impersonation_info {
+	uint64_t cache_id;
+	const struct auth_session_info *session_info;
+	const struct loadparm_substitution *lp_sub;
+};
+
+struct samba_impersonation {
+	struct samba_impersonation_info *info;
+};
+
+NTSTATUS samba_impersonation_create(TALLOC_CTX *mem_ctx,
+				const struct auth_session_info *session_info,
+				const struct loadparm_substitution *lp_sub,
+				struct samba_impersonation **_imp)
+{
+	struct samba_impersonation *imp = NULL;
+
+	*_imp = NULL;
+
+	imp = talloc(mem_ctx, struct samba_impersonation);
+	if (imp == NULL) {
+		return NT_STATUS_NO_MEMORY;
+	}
+	imp->info = talloc(imp, struct samba_impersonation_info);
+	if (imp->info == NULL) {
+		TALLOC_FREE(imp);
+		return NT_STATUS_NO_MEMORY;
+	}
+	imp->info->session_info = copy_session_info(imp->info,
+						    session_info);
+	if (imp->info->session_info == NULL) {
+		TALLOC_FREE(imp);
+		return NT_STATUS_NO_MEMORY;
+	}
+	imp->info->lp_sub = lp_sub: // copy???
+
+	imp->info->cache_id = ++global_cache_id_counter;
+
+	*_imp = imp;
+	return NT_STATUS_OK;
+}
+
+struct samba_impersonation *samba_impersonation_ref(TALLOC_CTX *mem_ctx,
+				const struct samba_impersonation *imp)
+{
+	struct samba_impersonation *ref = NULL;
+
+	ref = talloc(mem_ctx, struct samba_impersonation);
+	if (imp == NULL) {
+		return NULL;
+	}
+	ref->info = talloc_reference(ref, imp);
+	if (ref->info == NULL) {
+		TALLOC_FREE(ref);
+		return NULL;
+	}
+
+	return ref;
+}
+
+void samba_impersonation_cache_reset(void)
+{
+	samba_impersonation_cache_id_current = 0;
+}
+
+uint64_t samba_impersonation_cache_id(const struct samba_impersonation *imp)
+{
+	SMB_ASSERT(imp->info->cache_id != 0);
+	return imp->info->cache_id;
+}
+
+const struct auth_session_info *samba_impersonation_session_info(
+		const struct samba_impersonation *imp)
+{
+	return imp->info->session_info;
+}
+
+const struct loadparm_substitution *samba_impersonation_substitution(
+		const struct samba_impersonation *imp)
+{
+	return imp->info->lp_sub;
+}
+
+void samba_impersonation_cache_reset(void)
+{
+	samba_impersonation_cache_id_current = 0;
+}
diff --git a/auth/samba_impersonation.h b/auth/samba_impersonation.h
new file mode 100644
index 000000000000..38a6d5b39309
--- /dev/null
+++ b/auth/samba_impersonation.h
@@ -0,0 +1,41 @@
+/*
+   Unix SMB/Netbios implementation.
+
+   Generic impersonation infrastructure
+
+   Copyright (C) Stefan Metzmacher 2019
+
+   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 __AUTH_SAMBA_IMPERSONATION_H__
+#define __AUTH_SAMBA_IMPERSONATION_H__ 1
+
+struct auth_session_info;
+struct loadparm_substitution;
+struct samba_impersonation;
+
+NTSTATUS samba_impersonation_create(TALLOC_CTX *mem_ctx,
+				const struct auth_session_info *session_info,
+				struct samba_impersonation **_imp);
+struct samba_impersonation *samba_impersonation_ref(TALLOC_CTX *mem_ctx,
+				const struct samba_impersonation *imp);
+void samba_impersonation_cache_reset(void);
+uint64_t samba_impersonation_cache_id(const struct samba_impersonation *imp);
+const struct auth_session_info *samba_impersonation_session_info(
+		const struct samba_impersonation *imp);
+const struct loadparm_substitution *samba_impersonation_substitution(
+		const struct samba_impersonation *imp)
+
+#endif /* __AUTH_SAMBA_IMPERSONATION_H__ */
-- 
2.17.1


From 592720567aabd6943077117045214cb25cc603d3 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Wed, 18 Sep 2019 11:07:08 +0200
Subject: [PATCH 18/18] TODO: smb_vfs_impersonation

---
 source3/include/vfs.h | 80 +++++++++++++++++++++++++++++++++++++++++++
 source3/smbd/vfs.c    | 24 +++++++++++++
 2 files changed, 104 insertions(+)

diff --git a/source3/include/vfs.h b/source3/include/vfs.h
index 5ea4f8058174..e657f1d3511d 100644
--- a/source3/include/vfs.h
+++ b/source3/include/vfs.h
@@ -306,6 +306,7 @@ struct ea_list;
 struct smb_file_time;
 struct smb_filename;
 struct dfs_GetDFSReferral;
+struct samba_impersonation;
 
 typedef union unid_t {
 	uid_t uid;
@@ -2012,4 +2013,83 @@ NTSTATUS vfs_not_implemented_durable_reconnect(struct vfs_handle_struct *handle,
 					       TALLOC_CTX *mem_ctx,
 					       struct files_struct **fsp,
 					       DATA_BLOB *new_cookie);
+
+NTSTATUS smb_vfs_impersonate_unix_token(const struct samba_impersonation *imp);
+
+/*
+ * For now we'll allow __imp = NULL, but once it's passed down
+ * everywhere we should assert a valid pointer.
+ */
+#define __SMB_VFS_IMPERSONATE_UNIX_TOKEN_CHECK_ERRNO(__imp, __ret_errno) \
+do { \
+	const struct samba_impersonation *___imp = (__imp); \
+	if (___imp != NULL) {\
+		NTSTATUS status; \
+		status = smb_vfs_impersonate_unix_token(___imp); \
+		if (!NT_STATUS_IS_OK(status)) { \
+			errno = __ret_errno; \
+			return -1; \
+		} \
+	} \
+} while(0)
+
+static inline int smb_vfs_sys_openat(const struct samba_impersonation *imp,
+				     int dirfd,
+				     const char *pathname,
+				     int flags,
+				     mode_t mode)
+{
+	__SMB_VFS_IMPERSONATE_UNIX_TOKEN_CHECK_ERRNO(imp, EPERM);
+	return openat(dirfd, pathname, flags, mode);
+}
+#define openat __error_please_use_smb_vfs_sys_openat
+
+static inline int smb_vfs_sys_mkdirat(const struct samba_impersonation *imp,
+				      int dirfd,
+				      const char *pathname,
+				      mode_t mode)
+{
+	__SMB_VFS_IMPERSONATE_UNIX_TOKEN_CHECK_ERRNO(imp, EPERM);
+	return mkdirat(dirfd, const char *pathname, mode);
+}
+#define mkdirat __error_please_use_smb_vfs_sys_mkdirat
+
+static inline int smb_vfs_sys_renameat(const struct samba_impersonation *imp,
+				       int olddirfd, const char *oldpath,
+				       int newdirfd, const char *newpath)
+{
+	__SMB_VFS_IMPERSONATE_UNIX_TOKEN_CHECK_ERRNO(imp, EPERM);
+	return renameat(olddirfd, oldpath, newdirfd, newpath);
+}
+#define renameat __error_please_use_smb_vfs_sys_renameat
+
+static inline int smb_vfs_sys_symlinkat(const struct samba_impersonation *imp,
+					const char *target,
+					int newdirfd,
+					const char *linkpath)
+{
+	__SMB_VFS_IMPERSONATE_UNIX_TOKEN_CHECK_ERRNO(imp, EPERM);
+	return symlinkat(target, newdirfd, linkpath);
+}
+#define symlinkat __error_please_use_smb_vfs_sys_symlinkat
+
+static inline ssize_t smb_vfs_sys_readlinkat(
+		const struct samba_impersonation *imp,
+		int dirfd, const char *pathname, char *buf, size_t bufsiz)
+{
+	__SMB_VFS_IMPERSONATE_UNIX_TOKEN_CHECK_ERRNO(imp, EPERM);
+	return readlinkat(dirfd, pathname, buf, bufsiz);
+}
+#define readlinkat __error_please_use_smb_vfs_sys_readlinkat
+
+static inline int smb_vfs_sys_linkat(const struct samba_impersonation *imp,
+				     int olddirfd, const char *oldpath,
+				     int newdirfd, const char *newpath,
+				     int flags)
+{
+	__SMB_VFS_IMPERSONATE_UNIX_TOKEN_CHECK_ERRNO(imp, EPERM);
+	return linkat(olddirfd, oldpath, newdirfd, newpath, flags);
+}
+#define linkat __error_please_use_smb_vfs_sys_linkat
+
 #endif /* _VFS_H */
diff --git a/source3/smbd/vfs.c b/source3/smbd/vfs.c
index 34923b62ab42..20d2fceb807d 100644
--- a/source3/smbd/vfs.c
+++ b/source3/smbd/vfs.c
@@ -384,6 +384,30 @@ bool smbd_vfs_init(connection_struct *conn)
 	return True;
 }
 
+NTSTATUS smb_vfs_impersonate_unix_token(const struct samba_impersonation *imp)
+{
+	SMB_ASSERT(imp->info->cache_id != 0);
+
+	if (smb_vfs_impersonation_cache_id_current != imp->info->cache_id) {
+		const struct auth_session_info *si = imp->info->session_info;
+		const struct unix_token *utok = si->unix_token;
+		int ret;
+
+		/* Become the correct credential on this thread. */
+		ret = set_thread_credentials(utok->uid,
+					     utok->gid,
+					     (size_t)utok->ngroups,
+					     utok->groups);
+		if (ret != 0) {
+			return NT_STATUS_CANNOT_IMPERSONATE;
+		}
+
+		smb_vfs_impersonation_cache_id_current = imp->info->cache_id;
+	}
+
+	return NT_STATUS_OK;
+}
+
 /*******************************************************************
  Check if a file exists in the vfs.
 ********************************************************************/
-- 
2.17.1

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


More information about the samba-technical mailing list