[PATCHES v1] GPO support for client USER policy (browser proxy)

David Mulder dmulder at suse.com
Fri Dec 22 19:32:35 UTC 2017


These patches add client user policy support to samba.
This adds a call to winbind to execute the samba_gpupdate
script when a user authenticates via PAM. The samba_gpupdate
script is passed the credentials of the authenticating user,
and group policy is applied for that user account.
This first set of patches adds browser proxy policies. Setting
an Internet Explorer browser proxy gpo will apply the proxy
settings to the respective http_proxy, https_proxy, and
ftp_proxy environment variables for a samba user.

There is a significant problem in the winbind pam patch
that still needs to be addressed, and I'd like some review and
feedback. We must have the user's credentials in
samba_gpoupdate in order to look up their gpo policies,
but what is the best way to pass those credentials from
winbind to a script? These patches simply pass the
credentials via the command line in plain text (bad).
Can we assume this user is kinit'd by pam winbind
(I have no idea here)? If so, we could probably just pass
the krb5 ccache location for creds. Thoughts?

 python/samba/gp_browser_ext.py        | 104 ++++++++++++++++++++++++++
 python/samba/gp_env_var_ext.py        |   1 +
 python/samba/gpclass.py               |  20 ++++-
 selftest/target/Samba4.pm             |   4 +-
 source3/winbindd/winbindd_gpupdate.c  |  35 +++++++++
 source3/winbindd/winbindd_pam_auth.c  |   3 +
 source3/winbindd/winbindd_proto.h     |   1 +
 source4/scripting/bin/samba_gpoupdate |  13 +++-
 source4/torture/gpo/apply.c           | 240
++++++++++++++++++++++++++++++++++++++++++++++++++++++-----
 9 files changed, 396 insertions(+), 25 deletions(-)

-- 
David Mulder
SUSE Labs Software Engineer - Samba
dmulder at suse.com
SUSE Linux GmbH, GF: Felix Imendörffer, Jane Smithard, Graham Norton, HRB 21284 (AG Nürnberg)

-------------- next part --------------
From 447e2d09dd585474925a475820541e85e5f68bc9 Mon Sep 17 00:00:00 2001
From: David Mulder <dmulder at suse.com>
Date: Tue, 10 Oct 2017 13:37:51 -0600
Subject: [PATCH 1/3] gpo: Add user policies

Add browser user policies

Signed-off-by: David Mulder <dmulder at suse.com>
---
 python/samba/gp_browser_ext.py        | 104 ++++++++++++++++++++++++++++++++++
 python/samba/gp_env_var_ext.py        |   1 +
 python/samba/gpclass.py               |  20 +++++--
 source4/scripting/bin/samba_gpoupdate |  13 ++++-
 4 files changed, 131 insertions(+), 7 deletions(-)
 create mode 100644 python/samba/gp_browser_ext.py

diff --git a/python/samba/gp_browser_ext.py b/python/samba/gp_browser_ext.py
new file mode 100644
index 00000000000..a5685fd9524
--- /dev/null
+++ b/python/samba/gp_browser_ext.py
@@ -0,0 +1,104 @@
+from gpclass import gp_ext, file_to, gp_inf_ext
+from gp_file_append import ini_file_append
+import os, pwd
+from subprocess import Popen, PIPE
+
+proxy_enable = True
+use_same_proxy = False
+
+class inf_to_profile(file_to):
+    def __init__(self, *args):
+        super(inf_to_profile, self).__init__(*args)
+        self.filename = os.path.join(
+            pwd.getpwnam(self.creds.get_principal()).pw_dir,
+            '.profile'
+        )
+        self.profile = ini_file_append(self.filename)
+
+    def int_to_bool(self, val=None):
+        return int(val if val else self.val) > 0
+
+    def __proxy_enabled(self, val=None):
+        global proxy_enable
+        if val:
+            proxy_enable = self.int_to_bool(val)
+        return proxy_enable
+
+    def __use_same_proxy(self, val=None):
+        global use_same_proxy
+        if val:
+            use_same_proxy = self.int_to_bool(val)
+        return use_same_proxy
+
+    def set_proxy_url(self, val):
+        if self.__proxy_enabled():
+            if self.__use_same_proxy():
+                if self.attribute == 'http_proxy':
+                    self.__set_key_val_profile('http_proxy', val)
+                    self.__set_key_val_profile('https_proxy', val)
+                    self.__set_key_val_profile('ftp_proxy', val)
+            else:
+                self.__set_key_val_profile(self.attribute, val)
+
+    def __set_key_val_profile(self, key, val):
+        if key in self.profile.keys():
+            old_val = self.profile[key]
+        else:
+            old_val = None
+        self.logger.info('%s was changed from %s to %s in %s' % \
+            (key, old_val, val, self.filename))
+        if val == None:
+            del self.profile[key]
+        else:
+            self.profile[key] = val
+        self.gp_db.store(str(self), key, old_val)
+
+    def set_proxy_options(self, val):
+        global proxy_enable, use_same_proxy
+        if self.attribute == 'proxy_enable':
+            self.__proxy_enabled(self.val)
+            if not int(val): # Proxy is disabled
+                self.__set_key_val_profile('http_proxy', None)
+                self.__set_key_val_profile('https_proxy', None)
+                self.__set_key_val_profile('ftp_proxy', None)
+        elif self.attribute == 'use_same_proxy':
+            self.__use_same_proxy(self.val)
+            if val: # Use all the same proxy
+                if 'http_proxy' in self.profile.keys() and \
+                   self.__proxy_enabled():
+                    new_val = self.profile['http_proxy']
+                    self.__set_key_val_profile('https_proxy', new_val)
+                    self.__set_key_val_profile('ftp_proxy', new_val)
+
+    def mapper(self):
+        return { 'http_proxy' : (self.set_proxy_url, self.explicit),
+                 'https_proxy' : (self.set_proxy_url, self.explicit),
+                 'ftp_proxy' : (self.set_proxy_url, self.explicit),
+                 'proxy_enable' : (self.set_proxy_options, self.explicit),
+                 'use_same_proxy' : (self.set_proxy_options, self.explicit),
+               }
+
+    def __str__(self):
+        return 'Proxy'
+
+class gp_browser_ext(gp_inf_ext):
+
+    def list(self, rootpath):
+        return os.path.join(rootpath, 'USER/MICROSOFT/IEAK/install.ins')
+
+    def apply_map(self):
+        return { 'Proxy' : { 'Proxy_Enable' : ('proxy_enable', inf_to_profile),
+                             'HTTP_Proxy_Server' : ('http_proxy',
+                                                    inf_to_profile),
+                             'Secure_Proxy_Server' : ('https_proxy',
+                                                      inf_to_profile),
+                             'FTP_Proxy_Server' : ('ftp_proxy',
+                                                   inf_to_profile),
+                             'Use_Same_Proxy' : ('use_same_proxy',
+                                                 inf_to_profile),
+                           },
+               }
+
+    def __str__(self):
+        return 'Browser GPO extension'
+
diff --git a/python/samba/gp_env_var_ext.py b/python/samba/gp_env_var_ext.py
index 7655d90e684..e05a7b9ad10 100644
--- a/python/samba/gp_env_var_ext.py
+++ b/python/samba/gp_env_var_ext.py
@@ -101,6 +101,7 @@ class gp_environment_variable_ext(gp_ext):
                    self.ldb,
                    self.gp_db,
                    self.lp,
+                   self.creds,
                    att,
                    env_var.find('Properties').attrib).update_samba()
             self.gp_db.commit()
diff --git a/python/samba/gpclass.py b/python/samba/gpclass.py
index 02750105067..d72841c48bc 100644
--- a/python/samba/gpclass.py
+++ b/python/samba/gpclass.py
@@ -286,8 +286,9 @@ class GPOStorage:
 class gp_ext(object):
     __metaclass__ = ABCMeta
 
-    def __init__(self, logger):
+    def __init__(self, logger, creds=None):
         self.logger = logger
+        self.creds = creds
 
     @abstractmethod
     def list(self, rootpath):
@@ -309,7 +310,12 @@ class gp_ext(object):
         # Fixing the bug where only some Linux Boxes capitalize MACHINE
         try:
             blist = afile.split('/')
-            idx = afile.lower().split('/').index('machine')
+            index = None
+            if 'machine' in afile.lower():
+                index = 'machine'
+            elif 'user' in afile.lower():
+                index = 'user'
+            idx = afile.lower().split('/').index(index)
             for case in [
                             blist[idx].upper(),
                             blist[idx].capitalize(),
@@ -335,13 +341,14 @@ class gp_ext(object):
 class file_to():
     __metaclass__ = ABCMeta
 
-    def __init__(self, logger, ldb, gp_db, lp, attribute, val):
+    def __init__(self, logger, ldb, gp_db, lp, creds, attribute, val):
         self.logger = logger
         self.ldb = ldb
         self.attribute = attribute
         self.val = val
         self.lp = lp
         self.gp_db = gp_db
+        self.creds = creds
 
     def explicit(self):
         return self.val
@@ -482,7 +489,12 @@ class gp_inf_ext(gp_ext):
                     (att, setter) = current_section.get(key)
                     value = value.encode('ascii', 'ignore')
                     ret = True
-                    setter(self.logger, self.ldb, self.gp_db, self.lp, att,
+                    setter(self.logger,
+                           self.ldb,
+                           self.gp_db,
+                           self.lp,
+                           self.creds,
+                           att,
                            value).update_samba()
                     self.gp_db.commit()
         return ret
diff --git a/source4/scripting/bin/samba_gpoupdate b/source4/scripting/bin/samba_gpoupdate
index d84594a6701..23be60b2efc 100755
--- a/source4/scripting/bin/samba_gpoupdate
+++ b/source4/scripting/bin/samba_gpoupdate
@@ -36,6 +36,7 @@ except:
     SamDB = None
 from samba.gpclass import *
 from samba.gp_env_var_ext import gp_environment_variable_ext
+from samba.gp_browser_ext import gp_browser_ext
 from samba.net import Net
 from samba.dcerpc import nbt
 from samba import smb
@@ -117,7 +118,13 @@ def unapply_gp(lp, creds, test_ldb, logger, store, gp_extensions):
         gp_db.set_guid(gpo_guid)
         unapply_attributes = gp_db.list(gp_extensions)
         for attr in unapply_attributes:
-            attr_obj = attr[-1](logger, test_ldb, gp_db, lp, attr[0], attr[1])
+            attr_obj = attr[-1](logger,
+                                test_ldb,
+                                gp_db,
+                                lp,
+                                creds,
+                                attr[0],
+                                attr[1])
             attr_obj.mapper()[attr[0]][0](attr[1]) # Set the old value
             gp_db.delete(str(attr_obj), attr[0])
         gp_db.commit()
@@ -176,8 +183,8 @@ if __name__ == "__main__":
             gp_extensions.append(gp_sec_ext(logger))
         gp_extensions.append(gp_environment_variable_ext(logger,
                                                          opts.sysconfdir))
-    else:
-        pass # User extensions
+    else: # User extensions
+        gp_extensions.append(gp_browser_ext(logger, creds))
 
     # Get a live instance of Samba
     if SamDB:
-- 
2.13.6


From 04139b493501168aabc74e790193d901e7e5ea0a Mon Sep 17 00:00:00 2001
From: David Mulder <dmulder at suse.com>
Date: Mon, 18 Dec 2017 08:58:51 -0700
Subject: [PATCH 2/3] gpo: Add a winbind call to gpupdate for user policies
 apply

Signed-off-by: David Mulder <dmulder at suse.com>
---
 source3/winbindd/winbindd_gpupdate.c | 35 +++++++++++++++++++++++++++++++++++
 source3/winbindd/winbindd_pam_auth.c |  3 +++
 source3/winbindd/winbindd_proto.h    |  1 +
 3 files changed, 39 insertions(+)

diff --git a/source3/winbindd/winbindd_gpupdate.c b/source3/winbindd/winbindd_gpupdate.c
index 48ebb5501aa..bfe136365e0 100644
--- a/source3/winbindd/winbindd_gpupdate.c
+++ b/source3/winbindd/winbindd_gpupdate.c
@@ -114,3 +114,38 @@ void gpupdate_init(void)
 	}
 }
 
+void gpupdate_user(const char *user, const char *pass)
+{
+	TALLOC_CTX * ctx = talloc_new(NULL);
+	struct tevent_context *ev = tevent_context_init(ctx);
+	struct tevent_req *req = NULL;
+	struct loadparm_context *lp_ctx =
+		loadparm_init_s3(ctx, loadparm_s3_helpers());
+	const char *const *gpupdate_cmd =
+		lpcfg_gpo_update_command(lp_ctx);
+	const char *smbconf = lp_default_path();
+
+	/*
+	 * Check if gpupdate is enabled for winbind, if not
+	 * return without executing gpupdate.
+	 */
+	if (!lpcfg_apply_group_policies(lp_ctx)) {
+		talloc_free(ctx);
+		return;
+	}
+
+	req = samba_runcmd_send(ctx, ev, timeval_zero(), 2, 0,
+				gpupdate_cmd,
+				"-s",
+				smbconf,
+				talloc_asprintf(ctx, "--username=%s", user),
+				talloc_asprintf(ctx, "--password=%s", pass),
+				NULL);
+	if (req == NULL) {
+		DEBUG(0, ("Failed to execute the gpupdate command\n"));
+		talloc_free(ctx);
+		return;
+	}
+
+	talloc_free(ctx);
+}
diff --git a/source3/winbindd/winbindd_pam_auth.c b/source3/winbindd/winbindd_pam_auth.c
index 7ff44888975..f7ed82846fc 100644
--- a/source3/winbindd/winbindd_pam_auth.c
+++ b/source3/winbindd/winbindd_pam_auth.c
@@ -139,5 +139,8 @@ NTSTATUS winbindd_pam_auth_recv(struct tevent_req *req,
 			   nt_errstr(status)));
 	}
 
+	gpupdate_user(state->request->data.auth.user,
+		      state->request->data.auth.pass);
+
 	return status;
 }
diff --git a/source3/winbindd/winbindd_proto.h b/source3/winbindd/winbindd_proto.h
index 0e59a51ba54..5780e7a7198 100644
--- a/source3/winbindd/winbindd_proto.h
+++ b/source3/winbindd/winbindd_proto.h
@@ -934,5 +934,6 @@ bool reconnect_need_retry(NTSTATUS status, struct winbindd_domain *domain);
 
 /* The following definitions come from winbindd/winbindd_gpupdate.c  */
 void gpupdate_init(void);
+void gpupdate_user(const char *user, const char *pass);
 
 #endif /*  _WINBINDD_PROTO_H_  */
-- 
2.13.6


From c6b24aa6f595d10f106b2405962e488430aad64a Mon Sep 17 00:00:00 2001
From: David Mulder <dmulder at suse.com>
Date: Mon, 18 Dec 2017 11:25:28 -0700
Subject: [PATCH 3/3] gpo: Test that user proxy settings work

Signed-off-by: David Mulder <dmulder at suse.com>
---
 selftest/target/Samba4.pm   |   4 +-
 source4/torture/gpo/apply.c | 240 ++++++++++++++++++++++++++++++++++++++++----
 2 files changed, 226 insertions(+), 18 deletions(-)

diff --git a/selftest/target/Samba4.pm b/selftest/target/Samba4.pm
index 74659f2776c..18db4c59082 100755
--- a/selftest/target/Samba4.pm
+++ b/selftest/target/Samba4.pm
@@ -493,6 +493,7 @@ sub provision_raw_prepare($$$$$$$$$$$)
 	$ctx->{ipv4} = "127.0.0.$swiface";
 	$ctx->{ipv6} = sprintf("fd00:0000:0000:0000:0000:0000:5357:5f%02x", $swiface);
 	$ctx->{interfaces} = "$ctx->{ipv4}/8 $ctx->{ipv6}/64";
+	$ctx->{prefix_abs} = "$prefix_abs";
 
 	push(@{$ctx->{directories}}, $ctx->{privatedir});
 	push(@{$ctx->{directories}}, $ctx->{binddnsdir});
@@ -616,7 +617,8 @@ sub provision_raw_step1($$)
 	rndc command = true
 	dns update command = $ctx->{samba_dnsupdate}
 	spn update command = $ENV{SRCDIR_ABS}/source4/scripting/bin/samba_spnupdate -s $ctx->{smb_conf}
-	gpo update command = $ENV{SRCDIR_ABS}/source4/scripting/bin/samba_gpoupdate -s $ctx->{smb_conf} -H $ctx->{privatedir}/sam.ldb --sysconfdir=$ctx->{etcdir} --machine
+	gpo update command = $ENV{SRCDIR_ABS}/source4/scripting/bin/samba_gpoupdate -s $ctx->{smb_conf} -H $ctx->{privatedir}/sam.ldb --sysconfdir=$ctx->{etcdir}
+	template homedir = $ctx->{prefix_abs}/%D/%U
 	dreplsrv:periodic_startup_interval = 0
 	dsdb:schema update allowed = yes
 
diff --git a/source4/torture/gpo/apply.c b/source4/torture/gpo/apply.c
index cbf79edf9c1..22454091ab7 100644
--- a/source4/torture/gpo/apply.c
+++ b/source4/torture/gpo/apply.c
@@ -28,6 +28,7 @@
 #include "torture/gpo/proto.h"
 #include <unistd.h>
 #include <fcntl.h>
+#include <pwd.h>
 
 struct torture_suite *gpo_apply_suite(TALLOC_CTX *ctx)
 {
@@ -40,6 +41,8 @@ struct torture_suite *gpo_apply_suite(TALLOC_CTX *ctx)
 				   torture_gpo_environment_variables_policies);
 	torture_suite_add_simple_test(suite, "gpo_bad_env_var",
 				      torture_gpo_bad_env_var);
+	torture_suite_add_simple_test(suite, "torture_gpo_user_proxy_policy",
+				      torture_gpo_user_proxy_policy);
 
 	suite->description = talloc_strdup(suite, "Group Policy apply tests");
 
@@ -133,28 +136,54 @@ static void increment_gpt_ini(TALLOC_CTX *ctx, const char *gpt_file)
 	}
 }
 
-static bool exec_gpo_update_command(struct torture_context *tctx)
+static bool exec_gpo_update_command(struct torture_context *tctx, bool machine,
+				    const char *user, const char *pass)
 {
-	int ret = 0;
+	TALLOC_CTX *ctx = talloc_new(tctx);
+	char **gpo_cmd;
 	const char **gpo_update_cmd;
+	int gpo_update_len = 0;
+	const char **itr;
+	int ret = 0, i;
 
 	/* Get the gpo update command */
 	gpo_update_cmd = lpcfg_gpo_update_command(tctx->lp_ctx);
 	torture_assert(tctx, gpo_update_cmd && gpo_update_cmd[0],
 		       "Failed to fetch the gpo update command");
 
+	for (itr = gpo_update_cmd; *itr != NULL; itr++) {
+		gpo_update_len++;
+	}
+	gpo_cmd = talloc_array(ctx, char*, gpo_update_len+3);
+	for (i = 0; i < gpo_update_len; i++) {
+		gpo_cmd[i] = talloc_strdup(gpo_cmd,
+					   gpo_update_cmd[i]);
+	}
+	if (machine) {
+		gpo_cmd[i] = talloc_asprintf(gpo_cmd, "--machine");
+		gpo_cmd[i+1] = NULL;
+	} else {
+		gpo_cmd[i] = talloc_asprintf(gpo_cmd, "--username=%s", user);
+		gpo_cmd[i+1] = talloc_asprintf(gpo_cmd,
+					       "--password=%s", pass);
+		gpo_cmd[i+2] = NULL;
+	}
+
 	/* Run the gpo update command */
-	ret = exec_wait(discard_const_p(char *, gpo_update_cmd));
+	ret = exec_wait(gpo_cmd);
 	torture_assert(tctx, ret == 0,
 		       "Failed to execute the gpo update command");
 
+	talloc_free(ctx);
 	return true;
 }
 
-static bool exec_gpo_unapply_command(struct torture_context *tctx)
+static bool exec_gpo_unapply_command(struct torture_context *tctx,
+				     bool machine,
+				     const char *user, const char *pass)
 {
 	TALLOC_CTX *ctx = talloc_new(tctx);
-	char **gpo_unapply_cmd;
+	char **gpo_cmd;
 	const char **gpo_update_cmd;
 	int gpo_update_len = 0;
 	const char **itr;
@@ -168,14 +197,23 @@ static bool exec_gpo_unapply_command(struct torture_context *tctx)
 	for (itr = gpo_update_cmd; *itr != NULL; itr++) {
 		gpo_update_len++;
 	}
-	gpo_unapply_cmd = talloc_array(ctx, char*, gpo_update_len+2);
+	gpo_cmd = talloc_array(ctx, char*, gpo_update_len+4);
 	for (i = 0; i < gpo_update_len; i++) {
-		gpo_unapply_cmd[i] = talloc_strdup(gpo_unapply_cmd,
-						   gpo_update_cmd[i]);
+		gpo_cmd[i] = talloc_strdup(gpo_cmd, gpo_update_cmd[i]);
 	}
-	gpo_unapply_cmd[i] = talloc_asprintf(gpo_unapply_cmd, "--unapply");
-	gpo_unapply_cmd[i+1] = NULL;
-	ret = exec_wait(gpo_unapply_cmd);
+	if (machine) {
+		gpo_cmd[i] = talloc_asprintf(gpo_cmd, "--machine");
+		gpo_cmd[i+1] = talloc_asprintf(gpo_cmd, "--unapply");
+		gpo_cmd[i+2] = NULL;
+	} else {
+		gpo_cmd[i] = talloc_asprintf(gpo_cmd, "--unapply");
+		gpo_cmd[i+1] = talloc_asprintf(gpo_cmd,
+					       "--username=%s", user);
+		gpo_cmd[i+2] = talloc_asprintf(gpo_cmd,
+					       "--password=%s", pass);
+		gpo_cmd[i+3] = NULL;
+	}
+	ret = exec_wait(gpo_cmd);
 	torture_assert(tctx, ret == 0,
 		       "Failed to execute the gpo unapply command");
 
@@ -238,7 +276,7 @@ bool torture_gpo_system_access_policies(struct torture_context *tctx)
 		gpt_file = talloc_asprintf(ctx, "%s/%s", sysvol_path, GPTINI);
 		increment_gpt_ini(ctx, gpt_file);
 
-		exec_gpo_update_command(tctx);
+		exec_gpo_update_command(tctx, true, NULL, NULL);
 
 		ret = ldb_search(samdb, ctx, &result,
 				 ldb_get_default_basedn(samdb),
@@ -280,7 +318,7 @@ bool torture_gpo_system_access_policies(struct torture_context *tctx)
 	}
 
 	/* Unapply the settings and verify they are removed */
-	exec_gpo_unapply_command(tctx);
+	exec_gpo_unapply_command(tctx, true, NULL, NULL);
 
 	ret = ldb_search(samdb, ctx, &result, ldb_get_default_basedn(samdb),
 			 LDB_SCOPE_BASE, attrs, NULL);
@@ -375,7 +413,7 @@ bool torture_gpo_environment_variables_policies(struct torture_context *tctx)
 		gpt_file = talloc_asprintf(ctx, "%s/%s", sysvol_path, GPTINI);
 		increment_gpt_ini(ctx, gpt_file);
 
-		exec_gpo_update_command(tctx);
+		exec_gpo_update_command(tctx, true, NULL, NULL);
 
 		/* Machine env var policy */
 		envexpected = talloc_asprintf(ctx, RESENV, envres[i]);
@@ -393,7 +431,7 @@ bool torture_gpo_environment_variables_policies(struct torture_context *tctx)
 	}
 
 	/* Unapply the settings and verify they are removed */
-	exec_gpo_unapply_command(tctx);
+	exec_gpo_unapply_command(tctx, true, NULL, NULL);
 
 	/* Machine env var policy */
 	fd = open(profile, O_RDONLY);
@@ -446,7 +484,7 @@ bool torture_gpo_bad_env_var(struct torture_context *tctx)
 		gpt_file = talloc_asprintf(ctx, "%s/%s", sysvol_path, GPTINI);
 		increment_gpt_ini(ctx, gpt_file);
 
-		exec_gpo_update_command(tctx);
+		exec_gpo_update_command(tctx, true, NULL, NULL);
 
 		/* Make sure the profile is either not there, or empty */
 		if (access(profile, F_OK) == 0) {
@@ -459,7 +497,175 @@ bool torture_gpo_bad_env_var(struct torture_context *tctx)
 	}
 
 	/* Unapply the settings */
-	exec_gpo_unapply_command(tctx);
+	exec_gpo_unapply_command(tctx, true, NULL, NULL);
+
+	talloc_free(ctx);
+	return true;
+}
+
+#define PROXYPATH "addom.samba.example.com/Policies/"\
+		  "{31B2F340-016D-11D2-945F-00C04FB984F9}/USER/"\
+		  "MICROSOFT/IEAK"
+#define PROXYFILE "install.ins"
+
+#define PROXYTMPL "[Proxy]\n\
+Proxy_Enable=%s\n\
+HTTP_Proxy_Server=%s\n\
+Use_Same_Proxy=%s\n\
+%s\
+"
+#define PROXYTMPLEXT "\
+FTP_Proxy_Server=%s\n\
+Secure_Proxy_Server=%s\n\
+"
+#define TESTUSER "alice"
+#define TESTPASS "Secret007"
+
+bool torture_gpo_user_proxy_policy(struct torture_context *tctx)
+{
+	TALLOC_CTX *ctx = talloc_new(tctx);
+	int ret, i;
+	const char *sysvol_path = NULL, *proxy_dir = NULL;
+	const char *proxy_file = NULL, *gpt_file = NULL;
+	FILE *fp = NULL;
+	const char *use_same[] = {
+		"proxy2.example.com:8080",
+		"proxy3.example.com:8080"
+	};
+	const char *proxycases[][4] = {
+		{ "1", "proxy.example.com:8080", "1", "" },
+		{ "1", "proxy.example.com:8080", "0",
+		  talloc_asprintf(ctx, PROXYTMPLEXT,
+				  use_same[0],
+				  use_same[1]) },
+		{ "1", "proxy.example.com:8080", "1",
+		  talloc_asprintf(ctx, PROXYTMPLEXT,
+				  use_same[0],
+				  use_same[1]) },
+		{ "0", "proxy.example.com:8080", "0",
+		  talloc_asprintf(ctx, PROXYTMPLEXT,
+				  use_same[0],
+				  use_same[1]) },
+		{ "0", "proxy.example.com:8080", "1", "" },
+	};
+	char *profile = NULL;
+	struct stat *finfo = talloc_zero(ctx, struct stat);
+	struct passwd *pwd = NULL;
+	char *profile_data = NULL;
+
+	/* Ensure the sysvol path exists */
+	sysvol_path = lpcfg_path(lpcfg_service(tctx->lp_ctx, "sysvol"),
+				 lpcfg_default_service(tctx->lp_ctx), tctx);
+	torture_assert(tctx, sysvol_path, "Failed to fetch the sysvol path");
+	proxy_dir = talloc_asprintf(ctx, "%s/%s", sysvol_path, PROXYPATH);
+	mkdir_p(proxy_dir, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
+	proxy_file = talloc_asprintf(ctx, "%s/%s", proxy_dir, PROXYFILE);
+
+	pwd = getpwnam(TESTUSER);
+	mkdir_p(pwd->pw_dir, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
+	profile = talloc_asprintf(ctx, "%s/.profile", pwd->pw_dir);
+
+	for (i = 0; i < sizeof(proxycases)/sizeof(proxycases[0]); i++) {
+		if ( (fp = fopen(proxy_file, "w")) ) {
+			fputs(talloc_asprintf(ctx, PROXYTMPL,
+					      proxycases[i][0],
+					      proxycases[i][1],
+					      proxycases[i][2],
+					      proxycases[i][3]), fp);
+			fclose(fp);
+		}
+		gpt_file = talloc_asprintf(ctx, "%s/%s", sysvol_path, GPTINI);
+		increment_gpt_ini(ctx, gpt_file);
+
+		exec_gpo_update_command(tctx, false, TESTUSER, TESTPASS);
+
+		/* test that things are applied here */
+		torture_assert(tctx, access(profile, F_OK) == 0,
+			       "The profile does not exist");
+		torture_assert(tctx, stat(profile, finfo) == 0,
+			       "Failed to stat the profile");
+		profile_data = talloc_zero_size(ctx, finfo->st_size);
+		fp = fopen(profile, "rb");
+		fread(profile_data, 1, finfo->st_size, fp);
+
+		if (atoi(proxycases[i][0]) == 1) {
+			torture_assert(tctx, strstr(profile_data,
+				       talloc_asprintf(ctx, "http_proxy=%s",
+						       proxycases[i][1]))
+				       != NULL,
+				       "Failed to find http_proxy in profile");
+			if (atoi(proxycases[i][2]) == 0) {
+				torture_assert(tctx, strstr(profile_data,
+					talloc_asprintf(ctx, "ftp_proxy=%s",
+							use_same[0]))
+					!= NULL,
+					"Failed to find ftp_proxy in profile");
+				torture_assert(tctx, strstr(profile_data,
+					talloc_asprintf(ctx, "https_proxy=%s",
+							use_same[1]))
+					!= NULL,
+				"Failed to find https_proxy in profile");
+			} else {
+				torture_assert(tctx, strstr(profile_data,
+					talloc_asprintf(ctx, "ftp_proxy=%s",
+							use_same[0]))
+					== NULL,
+					"ftp_proxy should NOT have been set");
+				torture_assert(tctx, strstr(profile_data,
+					talloc_asprintf(ctx, "https_proxy=%s",
+							use_same[1]))
+					== NULL,
+				"https_proxy should NOT have been set");
+			}
+		} else {
+			torture_assert(tctx, strstr(profile_data,
+				       talloc_asprintf(ctx, "http_proxy=%s",
+						       proxycases[i][1]))
+				       == NULL,
+				       "http_proxy should NOT have been set");
+			torture_assert(tctx, strstr(profile_data,
+				       talloc_asprintf(ctx, "ftp_proxy=%s",
+						       use_same[0]))
+				       == NULL,
+				       "ftp_proxy should NOT have been set");
+			torture_assert(tctx, strstr(profile_data,
+				       talloc_asprintf(ctx, "https_proxy=%s",
+						       use_same[1]))
+				       == NULL,
+				       "https_proxy should NOT have been set");
+		}
+	}
+
+	exec_gpo_unapply_command(tctx, false, TESTUSER, TESTPASS);
+
+	/* Make sure the profile is either not there, or empty */
+	if (access(profile, F_OK) == 0) {
+		if (stat(profile, finfo) == 0) {
+			if (finfo->st_size != 0) {
+				torture_assert(tctx, strstr(profile_data,
+					talloc_asprintf(ctx, "http_proxy=%s",
+							proxycases[i][1]))
+					== NULL,
+					"http_proxy should NOT have been set");
+				torture_assert(tctx, strstr(profile_data,
+					talloc_asprintf(ctx, "ftp_proxy=%s",
+							use_same[0]))
+					== NULL,
+					"ftp_proxy should NOT have been set");
+				torture_assert(tctx, strstr(profile_data,
+					talloc_asprintf(ctx, "https_proxy=%s",
+							use_same[1]))
+					== NULL,
+				"https_proxy should NOT have been set");
+				torture_assert(tctx, strstr(profile_data,
+					       "use_same_proxy=") == NULL,
+				"use_same_proxy should NOT have been set");
+				torture_assert(tctx, strstr(profile_data,
+					       "proxy_enable=") == NULL,
+				"proxy_enable should NOT have been set");
+			}
+		}
+	}
 
 	talloc_free(ctx);
 	return true;
-- 
2.13.6



More information about the samba-technical mailing list