From e750e4a35f201f2e59e06933eb813e244279e73d Mon Sep 17 00:00:00 2001 From: David Mulder Date: Fri, 3 Mar 2017 12:54:30 -0700 Subject: [PATCH] gpo: Add gpo tests Lays down a sysvol gpttmpl.inf with password policies, then runs the samba_gpoupdate command. Verifies policies are applied to the samdb. Signed-off-by: David Mulder Reviewed-by: Garming Sam Reviewed-by: Andrew Bartlett --- python/samba/gpclass.py | 7 +- selftest/target/Samba4.pm | 1 + source4/selftest/tests.py | 4 + source4/torture/gpo/apply.c | 177 ++++++++++++++++++++++++++++++ source4/torture/gpo/gpo.c | 35 ++++++ source4/torture/gpo/wscript_build | 13 +++ source4/torture/wscript_build | 1 + 7 files changed, 236 insertions(+), 2 deletions(-) create mode 100644 source4/torture/gpo/apply.c create mode 100644 source4/torture/gpo/gpo.c create mode 100644 source4/torture/gpo/wscript_build diff --git a/python/samba/gpclass.py b/python/samba/gpclass.py index c3f7512a00d..a945969dde0 100644 --- a/python/samba/gpclass.py +++ b/python/samba/gpclass.py @@ -170,7 +170,7 @@ class gp_sec_ext(gp_ext): ret = False inftable = self.populate_inf() - policy = conn.loadfile(path.replace('/', '\\')).decode('utf-16') + policy = conn.loadfile(path.replace('/', '\\')) current_section = None # So here we would declare a boolean, @@ -181,7 +181,10 @@ class gp_sec_ext(gp_ext): inf_conf = ConfigParser() inf_conf.optionxform=str - inf_conf.readfp(StringIO(policy)) + try: + inf_conf.readfp(StringIO(policy)) + except: + inf_conf.readfp(StringIO(policy.decode('utf-16'))) for section in inf_conf.sections(): current_section = inftable.get(section) diff --git a/selftest/target/Samba4.pm b/selftest/target/Samba4.pm index 8b2af7ff063..68feb6b4673 100755 --- a/selftest/target/Samba4.pm +++ b/selftest/target/Samba4.pm @@ -616,6 +616,7 @@ 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 dreplsrv:periodic_startup_interval = 0 dsdb:schema update allowed = yes diff --git a/source4/selftest/tests.py b/source4/selftest/tests.py index 7362ec78e54..8d3d5261266 100755 --- a/source4/selftest/tests.py +++ b/source4/selftest/tests.py @@ -238,6 +238,10 @@ for env in ["ad_dc_ntvfs", "nt4_dc"]: plantestsuite("samba.blackbox.pdbtest.s4winbind(ad_dc_ntvfs)", "ad_dc_ntvfs:local", [os.path.join(bbdir, "test_pdbtest.sh"), '$SERVER', "$PREFIX", "pdbtest3", smbclient4, '$SMB_CONF_PATH', configuration + " --option='authmethods=winbind'"]) plantestsuite("samba.blackbox.pdbtest.s4winbind_wbclient(ad_dc_ntvfs)", "ad_dc_ntvfs:local", [os.path.join(bbdir, "test_pdbtest.sh"), '$SERVER', "$PREFIX", "pdbtest4", smbclient4, '$SMB_CONF_PATH', configuration + " --option='authmethods=winbind_wbclient'"]) +gpo = smbtorture4_testsuites("gpo.") +for t in gpo: + plansmbtorture4testsuite(t, 'ad_dc:local', ['//$SERVER/sysvol', '-U$USERNAME%$PASSWORD']) + transports = ["ncacn_np", "ncacn_ip_tcp"] #Kerberos varies between functional levels, so it is important to check this on all of them diff --git a/source4/torture/gpo/apply.c b/source4/torture/gpo/apply.c new file mode 100644 index 00000000000..b6b9b0ee76a --- /dev/null +++ b/source4/torture/gpo/apply.c @@ -0,0 +1,177 @@ +/* + Unix SMB/CIFS implementation. + + Copyright (C) David Mulder 2017 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#include "includes.h" +#include "param/param.h" +#include "param/loadparm.h" +#include "torture/smbtorture.h" +#include "lib/util/mkdir_p.h" +#include "dsdb/samdb/samdb.h" +#include "auth/session.h" +#include "lib/ldb/include/ldb.h" +#include "torture/gpo/proto.h" +#include + +struct torture_suite *gpo_apply_suite(TALLOC_CTX *ctx) +{ + struct torture_suite *suite = torture_suite_create(ctx, "apply"); + + torture_suite_add_simple_test(suite, "gpo_param_from_gpo", torture_gpo_system_access_policies); + + suite->description = talloc_strdup(suite, "Group Policy apply tests"); + + return suite; +} + +static int exec_wait(const char **cmd) +{ + int ret; + pid_t pid = fork(); + switch (pid) { + case 0: + execv(cmd[0], discard_const_p(char *, &(cmd[1]))); + ret = -1; + break; + case -1: + ret = errno; + break; + default: + if (waitpid(pid, &ret, 0) < 0) + ret = errno; + break; + } + return ret; +} + +static int unix2nttime(char *sval) +{ + return (strtoll(sval, NULL, 10) * -1 / 60 / 60 / 24 / 10000000); +} + +#define GPODIR "addom.samba.example.com/Policies/{31B2F340-016D-11D2-945F-00C04FB984F9}/MACHINE/Microsoft/Windows NT/SecEdit" +#define GPOFILE "GptTmpl.inf" +#define GPTTMPL "[System Access]\n\ +MinimumPasswordAge = %d\n\ +MaximumPasswordAge = %d\n\ +MinimumPasswordLength = %d\n\ +PasswordComplexity = %d\n\ +" +#define GPTINI "addom.samba.example.com/Policies/{31B2F340-016D-11D2-945F-00C04FB984F9}/GPT.INI" + +bool torture_gpo_system_access_policies(struct torture_context *tctx) +{ + int ret, vers = 0, i; + const char *sysvol_path = NULL, *gpo_dir = NULL, *gpo_file = NULL, *gpt_file = NULL; + struct ldb_context *samdb = NULL; + struct ldb_result *result; + const char *attrs[] = { + "minPwdAge", + "maxPwdAge", + "minPwdLength", + "pwdProperties", + NULL + }; + const struct ldb_val *val; + FILE *fp = NULL; + const char **gpo_update_cmd; + int minpwdcases[] = { 0, 1, 998 }; + int maxpwdcases[] = { 0, 1, 999 }; + int pwdlencases[] = { 0, 1, 14 }; + int pwdpropcases[] = { 0, 1, 1 }; + struct ldb_message *old_message = NULL; + + 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"); + + /* Ensure the sysvol path exists */ + gpo_dir = talloc_asprintf(tctx, "%s/%s", sysvol_path, GPODIR); + mkdir_p(gpo_dir, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); + gpo_file = talloc_asprintf(tctx, "%s/%s", gpo_dir, GPOFILE); + + /* 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"); + + /* Open and read the samba db and store the initial password settings */ + samdb = samdb_connect(tctx, tctx->ev, tctx->lp_ctx, system_session(tctx->lp_ctx), 0); + torture_assert(tctx, samdb, "Failed to connect to the samdb"); + + ret = ldb_search(samdb, tctx, &result, ldb_get_default_basedn(samdb), LDB_SCOPE_BASE, attrs, NULL); + torture_assert(tctx, ret == LDB_SUCCESS && result->count == 1, "Searching the samdb failed"); + + old_message = result->msgs[0]; + + for (i = 0; i < 3; i++) { + /* Write out the sysvol */ + if ( (fp = fopen(gpo_file, "w")) ) { + fputs(talloc_asprintf(tctx, GPTTMPL, minpwdcases[i], maxpwdcases[i], pwdlencases[i], pwdpropcases[i]), fp); + fclose(fp); + } + + /* Update the version in the GPT.INI */ + gpt_file = talloc_asprintf(tctx, "%s/%s", sysvol_path, GPTINI); + if ( (fp = fopen(gpt_file, "r")) ) { + char line[256]; + while (fgets(line, 256, fp)) { + if (strncasecmp(line, "Version=", 8) == 0) { + vers = atoi(line+8); + break; + } + } + fclose(fp); + } + if ( (fp = fopen(gpt_file, "w")) ) { + char *data = talloc_asprintf(tctx, "[General]\nVersion=%d\n", ++vers); + fputs(data, fp); + fclose(fp); + } + + /* Run the gpo update command */ + ret = exec_wait(gpo_update_cmd); + torture_assert(tctx, ret == 0, "Failed to execute the gpo update command"); + + ret = ldb_search(samdb, tctx, &result, ldb_get_default_basedn(samdb), LDB_SCOPE_BASE, attrs, NULL); + torture_assert(tctx, ret == LDB_SUCCESS && result->count == 1, "Searching the samdb failed"); + + /* minPwdAge */ + val = ldb_msg_find_ldb_val(result->msgs[0], attrs[0]); + torture_assert(tctx, unix2nttime((char*)val->data) == minpwdcases[i], "The minPwdAge was not applied"); + + /* maxPwdAge */ + val = ldb_msg_find_ldb_val(result->msgs[0], attrs[1]); + torture_assert(tctx, unix2nttime((char*)val->data) == maxpwdcases[i], "The maxPwdAge was not applied"); + + /* minPwdLength */ + val = ldb_msg_find_ldb_val(result->msgs[0], attrs[2]); + torture_assert(tctx, atoi((char*)val->data) == pwdlencases[i], "The minPwdLength was not applied"); + + /* pwdProperties */ + val = ldb_msg_find_ldb_val(result->msgs[0], attrs[3]); + torture_assert(tctx, atoi((char*)val->data) == pwdpropcases[i], "The pwdProperties were not applied"); + } + + for (i = 0; i < old_message->num_elements; i++) { + old_message->elements[i].flags = LDB_FLAG_MOD_REPLACE; + } + + ret = ldb_modify(samdb, old_message); + torture_assert(tctx, ret == 0, "Failed to reset password settings."); + + return true; +} diff --git a/source4/torture/gpo/gpo.c b/source4/torture/gpo/gpo.c new file mode 100644 index 00000000000..4a06809588e --- /dev/null +++ b/source4/torture/gpo/gpo.c @@ -0,0 +1,35 @@ +/* + Unix SMB/CIFS implementation. + + Copyright (C) David Mulder 2017 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#include "includes.h" +#include "torture/smbtorture.h" +#include "torture/gpo/proto.h" + +NTSTATUS torture_gpo_init(TALLOC_CTX *ctx) +{ + struct torture_suite *suite = torture_suite_create(ctx, "gpo"); + + torture_suite_add_suite(suite, gpo_apply_suite(suite)); + + suite->description = talloc_strdup(suite, "Group Policy tests"); + + torture_register_suite(ctx, suite); + + return NT_STATUS_OK; +} diff --git a/source4/torture/gpo/wscript_build b/source4/torture/gpo/wscript_build new file mode 100644 index 00000000000..d7b131f8095 --- /dev/null +++ b/source4/torture/gpo/wscript_build @@ -0,0 +1,13 @@ +#!/usr/bin/env python + +bld.SAMBA_MODULE('TORTURE_GPO', + source=''' + gpo.c + apply.c + ''', + subsystem='smbtorture', + deps='torture samba-util-core ldb', + internal_module=True, + autoproto='proto.h', + init_function='torture_gpo_init' + ) diff --git a/source4/torture/wscript_build b/source4/torture/wscript_build index fe066299ad3..aceededc9d8 100644 --- a/source4/torture/wscript_build +++ b/source4/torture/wscript_build @@ -33,6 +33,7 @@ bld.RECURSE('smb2') bld.RECURSE('winbind') bld.RECURSE('libnetapi') bld.RECURSE('libsmbclient') +bld.RECURSE('gpo') ntvfs_specific = dict(source='', deps='') -- 2.34.1