[Patches] Simple libsmb preparations (part 1)

Stefan Metzmacher metze at samba.org
Fri Dec 16 21:49:45 UTC 2016


Hi,

here're some simple libsmb preparations from my master3-libsmb-ok branch:
https://git.samba.org/?p=metze/samba/wip.git;a=shortlog;h=refs/heads/master3-libsmb-ok

Please review and push (they passed several private autobuilds).

Thanks!
metze
-------------- next part --------------
From e7f03dcd08a342eacbe8a1cb3684a4d086864c52 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Fri, 9 Dec 2016 09:48:06 +0100
Subject: [PATCH 1/8] s3:lib/netapi: make use of lp_client_ipc_max_protocol()
 in libnetapi_open_ipc_connection()

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 source3/lib/netapi/cm.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/source3/lib/netapi/cm.c b/source3/lib/netapi/cm.c
index 2649422..57e44ac 100644
--- a/source3/lib/netapi/cm.c
+++ b/source3/lib/netapi/cm.c
@@ -111,7 +111,7 @@ static WERROR libnetapi_open_ipc_connection(struct libnetapi_ctx *ctx,
 			     server_name, "IPC$",
 			     auth_info,
 			     false, false,
-			     lp_client_max_protocol(),
+			     lp_client_ipc_max_protocol(),
 			     0, 0x20, &cli_ipc);
 	if (!NT_STATUS_IS_OK(status)) {
 		cli_ipc = NULL;
-- 
1.9.1


From 7ad8e3c9b17f1eb6616ac965d52cc79c57c790df Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Fri, 9 Dec 2016 09:06:21 +0100
Subject: [PATCH 2/8] s3:torture: make use of cli_tree_connect_creds() where we
 may use share level auth.

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 source3/torture/torture.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/source3/torture/torture.c b/source3/torture/torture.c
index 8f0f136..7072f3c 100644
--- a/source3/torture/torture.c
+++ b/source3/torture/torture.c
@@ -1341,7 +1341,7 @@ static bool run_tcon_test(int dummy)
 		return False;
 	}
 
-	status = cli_tree_connect(cli, share, "?????", password);
+	status = cli_tree_connect_creds(cli, share, "?????", torture_creds);
 	if (!NT_STATUS_IS_OK(status)) {
 		printf("%s refused 2nd tree connect (%s)\n", host,
 		       nt_errstr(status));
@@ -1466,7 +1466,7 @@ static bool tcon_devtest(struct cli_state *cli,
 	NTSTATUS status;
 	bool ret;
 
-	status = cli_tree_connect(cli, myshare, devtype, password);
+	status = cli_tree_connect_creds(cli, myshare, devtype, torture_creds);
 
 	if (NT_STATUS_IS_OK(expected_error)) {
 		if (NT_STATUS_IS_OK(status)) {
-- 
1.9.1


From 4f419dd083503422668906f21ccfa6434edf63a0 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Fri, 9 Dec 2016 09:49:17 +0100
Subject: [PATCH 3/8] s3:torture/masktest: make use of cli_tree_connect_creds()

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 source3/torture/masktest.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/source3/torture/masktest.c b/source3/torture/masktest.c
index 537cfb0..143243d 100644
--- a/source3/torture/masktest.c
+++ b/source3/torture/masktest.c
@@ -218,8 +218,7 @@ static struct cli_state *connect_one(char *share)
 
 	DEBUG(4,(" session setup ok\n"));
 
-	status = cli_tree_connect(c, share, "?????", password,
-				  strlen(password)+1);
+	status = cli_tree_connect_creds(c, share, "?????", test_creds);
 	if (!NT_STATUS_IS_OK(status)) {
 		DEBUG(0,("tree connect failed: %s\n", nt_errstr(status)));
 		cli_shutdown(c);
-- 
1.9.1


From 4f443a60cc41e58e57ada7d95de1469bacb45d94 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Fri, 9 Dec 2016 09:49:17 +0100
Subject: [PATCH 4/8] s3:torture/masktest: masktest only works with SMB1
 currently

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 source3/torture/masktest.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/source3/torture/masktest.c b/source3/torture/masktest.c
index 143243d..95e0b04 100644
--- a/source3/torture/masktest.c
+++ b/source3/torture/masktest.c
@@ -536,6 +536,7 @@ static void usage(void)
 	argv += optind;
 
 	max_protocol = lp_client_max_protocol();
+	max_protocol = MIN(max_protocol, PROTOCOL_NT1);
 
 	if (!got_pass) {
 		char pwd[256] = {0};
-- 
1.9.1


From d876d636820d6612f971593676830180f9bb24fe Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Thu, 8 Dec 2016 12:11:45 +0100
Subject: [PATCH 5/8] s3:libsmb: split out a cli_session_creds_prepare_krb5()
 function

This can be temporary used to do the required kinit if
we use kerberos and have the password given.

In future this should be done in the gensec layer on demand,
but there's more work attached to doing it in the gensec_gse module.

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 source3/libsmb/cliconnect.c | 281 ++++++++++++++++++++++++--------------------
 source3/libsmb/proto.h      |   2 +
 2 files changed, 154 insertions(+), 129 deletions(-)

diff --git a/source3/libsmb/cliconnect.c b/source3/libsmb/cliconnect.c
index 559712e..d1ff251 100644
--- a/source3/libsmb/cliconnect.c
+++ b/source3/libsmb/cliconnect.c
@@ -219,6 +219,151 @@ fail:
 	return NULL;
 }
 
+NTSTATUS cli_session_creds_prepare_krb5(struct cli_state *cli,
+					struct cli_credentials *creds)
+{
+	TALLOC_CTX *frame = talloc_stackframe();
+	const char *user_principal = NULL;
+	const char *user_account = NULL;
+	const char *user_domain = NULL;
+	const char *pass = NULL;
+	const char *target_hostname = NULL;
+	const DATA_BLOB *server_blob = NULL;
+	enum credentials_use_kerberos krb5_state;
+	bool try_kerberos = false;
+	bool need_kinit = false;
+	bool auth_requested = true;
+	int ret;
+
+	target_hostname = smbXcli_conn_remote_name(cli->conn);
+	if (!cli->got_kerberos_mechanism) {
+		server_blob = smbXcli_conn_server_gss_blob(cli->conn);
+	}
+
+	/* the server might not even do spnego */
+	if (server_blob != NULL && server_blob->length != 0) {
+		char *OIDs[ASN1_MAX_OIDS] = { NULL, };
+		size_t i;
+		bool ok;
+
+		/*
+		 * The server sent us the first part of the SPNEGO exchange in the
+		 * negprot reply. It is WRONG to depend on the principal sent in the
+		 * negprot reply, but right now we do it. If we don't receive one,
+		 * we try to best guess, then fall back to NTLM.
+		 */
+		ok = spnego_parse_negTokenInit(frame, *server_blob, OIDs,
+					       NULL, NULL);
+		if (!ok) {
+			TALLOC_FREE(frame);
+			return NT_STATUS_INVALID_PARAMETER;
+		}
+		if (OIDs[0] == NULL) {
+			TALLOC_FREE(frame);
+			return NT_STATUS_INVALID_PARAMETER;
+		}
+
+		/* make sure the server understands kerberos */
+		for (i = 0; OIDs[i] != NULL; i++) {
+			if (i == 0) {
+				DEBUG(3,("got OID=%s\n", OIDs[i]));
+			} else {
+				DEBUGADD(3,("got OID=%s\n", OIDs[i]));
+			}
+
+			if (strcmp(OIDs[i], OID_KERBEROS5_OLD) == 0 ||
+			    strcmp(OIDs[i], OID_KERBEROS5) == 0) {
+				cli->got_kerberos_mechanism = true;
+				break;
+			}
+		}
+	}
+
+	auth_requested = cli_credentials_authentication_requested(creds);
+	if (auth_requested) {
+		user_principal = cli_credentials_get_principal(creds, frame);
+		if (user_principal == NULL) {
+			TALLOC_FREE(frame);
+			return NT_STATUS_NO_MEMORY;
+		}
+	}
+	user_account = cli_credentials_get_username(creds);
+	user_domain = cli_credentials_get_domain(creds);
+	pass = cli_credentials_get_password(creds);
+
+	krb5_state = cli_credentials_get_kerberos_state(creds);
+
+	if (krb5_state != CRED_DONT_USE_KERBEROS) {
+		try_kerberos = true;
+	}
+
+	if (target_hostname == NULL) {
+		try_kerberos = false;
+	} else if (is_ipaddress(target_hostname)) {
+		try_kerberos = false;
+	} else if (strequal(target_hostname, "localhost")) {
+		try_kerberos = false;
+	} else if (strequal(target_hostname, STAR_SMBSERVER)) {
+		try_kerberos = false;
+	} else if (!auth_requested) {
+		try_kerberos = false;
+	}
+
+	if (krb5_state == CRED_MUST_USE_KERBEROS && !try_kerberos) {
+		DEBUG(0, ("Kerberos auth with '%s' (%s\\%s) to access "
+			  "'%s' not possible\n",
+			  user_principal, user_domain, user_account,
+			  target_hostname));
+		TALLOC_FREE(frame);
+		return NT_STATUS_ACCESS_DENIED;
+	}
+
+	if (pass == NULL || strlen(pass) == 0) {
+		need_kinit = false;
+	} else if (krb5_state == CRED_MUST_USE_KERBEROS) {
+		need_kinit = try_kerberos;
+	} else if (!cli->got_kerberos_mechanism) {
+		/*
+		 * Most likely the server doesn't support
+		 * Kerberos, don't waste time doing a kinit
+		 */
+		need_kinit = false;
+	} else {
+		need_kinit = try_kerberos;
+	}
+
+	if (!need_kinit) {
+		TALLOC_FREE(frame);
+		return NT_STATUS_OK;
+	}
+
+
+	/*
+	 * TODO: This should be done within the gensec layer
+	 * only if required!
+	 */
+	setenv(KRB5_ENV_CCNAME, "MEMORY:cliconnect", 1);
+	ret = kerberos_kinit_password(user_principal, pass,
+				0 /* no time correction for now */,
+				NULL);
+	if (ret != 0) {
+		DEBUG(0, ("Kinit for %s to access %s failed: %s\n",
+			  user_principal, target_hostname,
+			  error_message(ret)));
+		if (krb5_state == CRED_MUST_USE_KERBEROS) {
+			TALLOC_FREE(frame);
+			return krb5_to_nt_status(ret);
+		}
+
+		/*
+		 * Ignore the error and hope that NTLM will work
+		 */
+	}
+
+	TALLOC_FREE(frame);
+	return NT_STATUS_OK;
+}
+
 /********************************************************
  Utility function to ensure we always return at least
  a valid char * pointer to an empty string for the
@@ -689,14 +834,6 @@ static NTSTATUS cli_sesssetup_blob_recv(struct tevent_req *req,
 }
 
 /****************************************************************************
- Use in-memory credentials cache
-****************************************************************************/
-
-static void use_in_memory_ccache(void) {
-	setenv(KRB5_ENV_CCNAME, "MEMORY:cliconnect", 1);
-}
-
-/****************************************************************************
  Do a spnego/NTLMSSP encrypted session setup.
 ****************************************************************************/
 
@@ -1089,16 +1226,9 @@ static struct tevent_req *cli_session_setup_spnego_send(
 {
 	struct tevent_req *req, *subreq;
 	struct cli_session_setup_spnego_state *state;
-	const char *user_principal = NULL;
-	const char *user_account = NULL;
-	const char *user_domain = NULL;
-	const char *pass = NULL;
+	const char *target_service = NULL;
 	const char *target_hostname = NULL;
-	const DATA_BLOB *server_blob = NULL;
-	enum credentials_use_kerberos krb5_state;
-	bool try_kerberos = false;
-	bool need_kinit = false;
-	bool auth_requested = true;
+	NTSTATUS status;
 
 	req = tevent_req_create(mem_ctx, &state,
 				struct cli_session_setup_spnego_state);
@@ -1106,123 +1236,16 @@ static struct tevent_req *cli_session_setup_spnego_send(
 		return NULL;
 	}
 
+	target_service = "cifs";
 	target_hostname = smbXcli_conn_remote_name(cli->conn);
-	server_blob = smbXcli_conn_server_gss_blob(cli->conn);
-
-	/* the server might not even do spnego */
-	if (server_blob != NULL && server_blob->length != 0) {
-		char *principal = NULL;
-		char *OIDs[ASN1_MAX_OIDS];
-		int i;
-
-		/* The server sent us the first part of the SPNEGO exchange in the
-		 * negprot reply. It is WRONG to depend on the principal sent in the
-		 * negprot reply, but right now we do it. If we don't receive one,
-		 * we try to best guess, then fall back to NTLM.  */
-		if (!spnego_parse_negTokenInit(state, *server_blob, OIDs,
-					       &principal, NULL) ||
-				OIDs[0] == NULL) {
-			state->result = ADS_ERROR_NT(NT_STATUS_INVALID_PARAMETER);
-			tevent_req_done(req);
-			return tevent_req_post(req, ev);
-		}
-		TALLOC_FREE(principal);
-
-		/* make sure the server understands kerberos */
-		for (i = 0; OIDs[i] != NULL; i++) {
-			if (i == 0) {
-				DEBUG(3,("got OID=%s\n", OIDs[i]));
-			} else {
-				DEBUGADD(3,("got OID=%s\n", OIDs[i]));
-			}
-
-			if (strcmp(OIDs[i], OID_KERBEROS5_OLD) == 0 ||
-			    strcmp(OIDs[i], OID_KERBEROS5) == 0) {
-				cli->got_kerberos_mechanism = True;
-			}
-			talloc_free(OIDs[i]);
-		}
-	}
 
-	auth_requested = cli_credentials_authentication_requested(creds);
-	if (auth_requested) {
-		user_principal = cli_credentials_get_principal(creds, state);
-		if (tevent_req_nomem(user_principal, req)) {
-			return tevent_req_post(req, ev);
-		}
-	}
-	user_account = cli_credentials_get_username(creds);
-	user_domain = cli_credentials_get_domain(creds);
-	pass = cli_credentials_get_password(creds);
-
-	krb5_state = cli_credentials_get_kerberos_state(creds);
-
-	if (krb5_state != CRED_DONT_USE_KERBEROS) {
-		try_kerberos = true;
-	}
-
-	if (target_hostname == NULL) {
-		try_kerberos = false;
-	} else if (is_ipaddress(target_hostname)) {
-		try_kerberos = false;
-	} else if (strequal(target_hostname, "localhost")) {
-		try_kerberos = false;
-	} else if (strequal(target_hostname, STAR_SMBSERVER)) {
-		try_kerberos = false;
-	} else if (!auth_requested) {
-		try_kerberos = false;
-	}
-
-	if (krb5_state == CRED_MUST_USE_KERBEROS && !try_kerberos) {
-		DEBUG(0, ("Kerberos auth with '%s' (%s\\%s) to access "
-			  "'%s' not possible\n",
-			  user_principal, user_domain, user_account,
-			  target_hostname));
-		tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
-		return tevent_req_post(req, ev);
-	}
-
-	if (pass == NULL || strlen(pass) == 0) {
-		need_kinit = false;
-	} else if (krb5_state == CRED_MUST_USE_KERBEROS) {
-		need_kinit = try_kerberos;
-	} else if (!cli->got_kerberos_mechanism) {
-		/*
-		 * Most likely the server doesn't support
-		 * Kerberos, don't waste time doing a kinit
-		 */
-		need_kinit = false;
-	} else {
-		need_kinit = try_kerberos;
-	}
-
-	if (need_kinit) {
-		int ret;
-
-		use_in_memory_ccache();
-		ret = kerberos_kinit_password(user_principal, pass,
-					0 /* no time correction for now */,
-					NULL);
-
-		if (ret != 0) {
-			DEBUG(0, ("Kinit for %s to access %s failed: %s\n",
-				  user_principal, target_hostname,
-				  error_message(ret)));
-			if (krb5_state == CRED_MUST_USE_KERBEROS) {
-				state->result = ADS_ERROR_KRB5(ret);
-				tevent_req_done(req);
-				return tevent_req_post(req, ev);
-			}
-
-			/*
-			 * Ignore the error and hope that NTLM will work
-			 */
-			ret = 0;
-		}
+	status = cli_session_creds_prepare_krb5(cli, creds);
+	if (tevent_req_nterror(req, status)) {
+		return tevent_req_post(req, ev);;
 	}
 
 	subreq = cli_session_setup_gensec_send(state, ev, cli, creds,
-					       "cifs", target_hostname);
+					       target_service, target_hostname);
 	if (tevent_req_nomem(subreq, req)) {
 		return tevent_req_post(req, ev);
 	}
diff --git a/source3/libsmb/proto.h b/source3/libsmb/proto.h
index e1cd185..290183c 100644
--- a/source3/libsmb/proto.h
+++ b/source3/libsmb/proto.h
@@ -43,6 +43,8 @@ struct cli_credentials *cli_session_creds_init(TALLOC_CTX *mem_ctx,
 					       bool fallback_after_kerberos,
 					       bool use_ccache,
 					       bool password_is_nt_hash);
+NTSTATUS cli_session_creds_prepare_krb5(struct cli_state *cli,
+					struct cli_credentials *creds);
 struct tevent_req *cli_session_setup_creds_send(TALLOC_CTX *mem_ctx,
 					struct tevent_context *ev,
 					struct cli_state *cli,
-- 
1.9.1


From 9fa300ad8ce73ffc8e20aa01ae2401837cba12f1 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Fri, 16 Dec 2016 01:26:29 +0100
Subject: [PATCH 6/8] s3:libsmb: don't let cli_session_creds_init() overwrite
 the default domain with ""

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 source3/libsmb/cliconnect.c | 16 +++++++---------
 1 file changed, 7 insertions(+), 9 deletions(-)

diff --git a/source3/libsmb/cliconnect.c b/source3/libsmb/cliconnect.c
index d1ff251..631264f 100644
--- a/source3/libsmb/cliconnect.c
+++ b/source3/libsmb/cliconnect.c
@@ -72,10 +72,6 @@ struct cli_credentials *cli_session_creds_init(TALLOC_CTX *mem_ctx,
 	}
 	cli_credentials_set_conf(creds, lp_ctx);
 
-	if (domain == NULL) {
-		domain = "";
-	}
-
 	if (username == NULL) {
 		username = "";
 	}
@@ -159,11 +155,13 @@ struct cli_credentials *cli_session_creds_init(TALLOC_CTX *mem_ctx,
 		goto fail;
 	}
 
-	ok = cli_credentials_set_domain(creds,
-					domain,
-					CRED_SPECIFIED);
-	if (!ok) {
-		goto fail;
+	if (domain != NULL) {
+		ok = cli_credentials_set_domain(creds,
+						domain,
+						CRED_SPECIFIED);
+		if (!ok) {
+			goto fail;
+		}
 	}
 
 	if (principal != NULL) {
-- 
1.9.1


From be5d3418431ff018e37e8c2e9880073e54063cea Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Thu, 3 Nov 2016 15:11:29 +0100
Subject: [PATCH 7/8] s3:libsmb: use cli_cm_force_encryption() instead of
 cli_force_encryption()

This allows SMB3 encryption instead of returning NT_STATUS_NOT_SUPPORTED.

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 source3/libsmb/libsmb_server.c | 23 +++++++++++++----------
 1 file changed, 13 insertions(+), 10 deletions(-)

diff --git a/source3/libsmb/libsmb_server.c b/source3/libsmb/libsmb_server.c
index 438b7e6..bb7153c 100644
--- a/source3/libsmb/libsmb_server.c
+++ b/source3/libsmb/libsmb_server.c
@@ -587,11 +587,12 @@ SMBC_server_internal(TALLOC_CTX *ctx,
         }
 
 	if (context->internal->smb_encryption_level) {
-		/* Attempt UNIX smb encryption. */
-		if (!NT_STATUS_IS_OK(cli_force_encryption(c,
-                                                          username_used,
-                                                          password_used,
-                                                          *pp_workgroup))) {
+		/* Attempt encryption. */
+		status = cli_cm_force_encryption(c, username_used,
+						 password_used,
+						 *pp_workgroup,
+						 share);
+		if (!NT_STATUS_IS_OK(status)) {
 
 			/*
 			 * context->smb_encryption_level == 1
@@ -787,11 +788,13 @@ SMBC_attr_server(TALLOC_CTX *ctx,
                 }
 
 		if (context->internal->smb_encryption_level) {
-			/* Attempt UNIX smb encryption. */
-			if (!NT_STATUS_IS_OK(cli_force_encryption(ipc_cli,
-                                                                  *pp_username,
-                                                                  *pp_password,
-                                                                  *pp_workgroup))) {
+			/* Attempt encryption. */
+			nt_status = cli_cm_force_encryption(ipc_cli,
+							    *pp_username,
+							    *pp_password,
+							    *pp_workgroup,
+							    "IPC$");
+			if (!NT_STATUS_IS_OK(nt_status)) {
 
 				/*
 				 * context->smb_encryption_level ==
-- 
1.9.1


From 97eb8e698d72458b944012042bbf0d34d6bb8909 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Thu, 3 Nov 2016 15:11:29 +0100
Subject: [PATCH 8/8] s3:utils: use cli_cm_force_encryption() instead of
 cli_force_encryption()

This allows SMB3 encryption instead of returning NT_STATUS_NOT_SUPPORTED.

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 source3/utils/net_util.c | 24 +++---------------------
 1 file changed, 3 insertions(+), 21 deletions(-)

diff --git a/source3/utils/net_util.c b/source3/utils/net_util.c
index cc65457..08ee94e 100644
--- a/source3/utils/net_util.c
+++ b/source3/utils/net_util.c
@@ -155,29 +155,11 @@ NTSTATUS connect_to_service(struct net_context *c,
 	}
 
 	if (c->smb_encrypt) {
-		nt_status = cli_force_encryption(*cli_ctx,
+		nt_status = cli_cm_force_encryption(*cli_ctx,
 					c->opt_user_name,
 					c->opt_password,
-					c->opt_workgroup);
-
-		if (NT_STATUS_EQUAL(nt_status,NT_STATUS_NOT_SUPPORTED)) {
-			d_printf(_("Encryption required and "
-				"server that doesn't support "
-				"UNIX extensions - failing connect\n"));
-		} else if (NT_STATUS_EQUAL(nt_status,NT_STATUS_UNKNOWN_REVISION)) {
-			d_printf(_("Encryption required and "
-				"can't get UNIX CIFS extensions "
-				"version from server.\n"));
-		} else if (NT_STATUS_EQUAL(nt_status,NT_STATUS_UNSUPPORTED_COMPRESSION)) {
-			d_printf(_("Encryption required and "
-				"share %s doesn't support "
-				"encryption.\n"), service_name);
-		} else if (!NT_STATUS_IS_OK(nt_status)) {
-			d_printf(_("Encryption required and "
-				"setup failed with error %s.\n"),
-				nt_errstr(nt_status));
-		}
-
+					c->opt_workgroup,
+					service_name);
 		if (!NT_STATUS_IS_OK(nt_status)) {
 			cli_shutdown(*cli_ctx);
 			*cli_ctx = NULL;
-- 
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/20161216/35d89667/signature.sig>


More information about the samba-technical mailing list