diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 17:20:00 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 17:20:00 +0000 |
commit | 8daa83a594a2e98f39d764422bfbdbc62c9efd44 (patch) | |
tree | 4099e8021376c7d8c05bdf8503093d80e9c7bad0 /source4/torture/rpc/spoolss_access.c | |
parent | Initial commit. (diff) | |
download | samba-8daa83a594a2e98f39d764422bfbdbc62c9efd44.tar.xz samba-8daa83a594a2e98f39d764422bfbdbc62c9efd44.zip |
Adding upstream version 2:4.20.0+dfsg.upstream/2%4.20.0+dfsg
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'source4/torture/rpc/spoolss_access.c')
-rw-r--r-- | source4/torture/rpc/spoolss_access.c | 905 |
1 files changed, 905 insertions, 0 deletions
diff --git a/source4/torture/rpc/spoolss_access.c b/source4/torture/rpc/spoolss_access.c new file mode 100644 index 0000000..b0d5265 --- /dev/null +++ b/source4/torture/rpc/spoolss_access.c @@ -0,0 +1,905 @@ +/* + Unix SMB/CIFS implementation. + test suite for spoolss rpc operations + + Copyright (C) Guenther Deschner 2010 + + 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 "torture/torture.h" +#include "librpc/gen_ndr/ndr_misc.h" +#include "librpc/gen_ndr/ndr_spoolss.h" +#include "librpc/gen_ndr/ndr_spoolss_c.h" +#include "librpc/gen_ndr/ndr_samr_c.h" +#include "librpc/gen_ndr/ndr_lsa_c.h" +#include "librpc/gen_ndr/ndr_security.h" +#include "libcli/security/security.h" +#include "torture/rpc/torture_rpc.h" +#include "param/param.h" +#include "lib/cmdline/cmdline.h" + +#define TORTURE_USER "torture_user" +#define TORTURE_USER_ADMINGROUP "torture_user_544" +#define TORTURE_USER_PRINTOPGROUP "torture_user_550" +#define TORTURE_USER_PRINTOPPRIV "torture_user_priv" +#define TORTURE_USER_SD "torture_user_sd" +#define TORTURE_WORKSTATION "torture_workstation" + +struct torture_user { + const char *username; + void *testuser; + uint32_t *builtin_memberships; + uint32_t num_builtin_memberships; + const char **privs; + uint32_t num_privs; + bool privs_present; + bool sd; + bool admin_rights; + bool system_security; +}; + +struct torture_access_context { + struct dcerpc_pipe *spoolss_pipe; + const char *printername; + struct security_descriptor *sd_orig; + struct torture_user user; +}; + +static bool test_openprinter_handle(struct torture_context *tctx, + struct dcerpc_pipe *p, + const char *name, + const char *printername, + const char *username, + uint32_t access_mask, + WERROR expected_result, + struct policy_handle *handle) +{ + struct spoolss_OpenPrinterEx r; + struct spoolss_UserLevel1 level1; + struct dcerpc_binding_handle *b = p->binding_handle; + + level1.size = 28; + level1.client = talloc_asprintf(tctx, "\\\\%s", "smbtorture"); + level1.user = username; + /* Windows 7 and Windows Server 2008 R2 */ + level1.build = 7007; + level1.major = 6; + level1.minor = 1; + level1.processor= 0; + + r.in.printername = printername; + r.in.datatype = NULL; + r.in.devmode_ctr.devmode= NULL; + r.in.access_mask = access_mask; + r.in.userlevel_ctr.level = 1; + r.in.userlevel_ctr.user_info.level1 = &level1; + r.out.handle = handle; + + torture_comment(tctx, "Testing OpenPrinterEx(%s) with access_mask 0x%08x (%s)\n", + r.in.printername, r.in.access_mask, name); + + torture_assert_ntstatus_ok(tctx, + dcerpc_spoolss_OpenPrinterEx_r(b, tctx, &r), + "OpenPrinterEx failed"); + torture_assert_werr_equal(tctx, r.out.result, expected_result, + talloc_asprintf(tctx, "OpenPrinterEx(%s) as '%s' with access_mask: 0x%08x (%s) failed", + r.in.printername, username, r.in.access_mask, name)); + + return true; +} + +static bool test_openprinter_access(struct torture_context *tctx, + struct dcerpc_pipe *p, + const char *name, + const char *printername, + const char *username, + uint32_t access_mask, + WERROR expected_result) +{ + struct policy_handle handle; + struct dcerpc_binding_handle *b = p->binding_handle; + bool ret = true; + + ZERO_STRUCT(handle); + + if (printername == NULL) { + torture_comment(tctx, "skipping test %s as there is no printer\n", name); + return true; + } + + ret = test_openprinter_handle(tctx, p, name, printername, username, access_mask, expected_result, &handle); + if (is_valid_policy_hnd(&handle)) { + test_ClosePrinter(tctx, b, &handle); + } + + return ret; +} + +static bool spoolss_access_setup_membership(struct torture_context *tctx, + struct dcerpc_pipe *p, + uint32_t num_members, + uint32_t *members, + struct dom_sid *user_sid) +{ + struct dcerpc_binding_handle *b = p->binding_handle; + struct policy_handle connect_handle, domain_handle; + int i; + + torture_comment(tctx, + "Setting up BUILTIN membership for %s\n", + dom_sid_string(tctx, user_sid)); + for (i=0; i < num_members; i++) { + torture_comment(tctx, "adding user to S-1-5-32-%d\n", members[i]); + } + + { + struct samr_Connect2 r; + r.in.system_name = ""; + r.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED; + r.out.connect_handle = &connect_handle; + + torture_assert_ntstatus_ok(tctx, + dcerpc_samr_Connect2_r(b, tctx, &r), + "samr_Connect2 failed"); + torture_assert_ntstatus_ok(tctx, r.out.result, + "samr_Connect2 failed"); + } + + { + struct samr_OpenDomain r; + r.in.connect_handle = &connect_handle; + r.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED; + r.in.sid = dom_sid_parse_talloc(tctx, "S-1-5-32"); + r.out.domain_handle = &domain_handle; + + torture_assert_ntstatus_ok(tctx, + dcerpc_samr_OpenDomain_r(b, tctx, &r), + "samr_OpenDomain failed"); + torture_assert_ntstatus_ok(tctx, r.out.result, + "samr_OpenDomain failed"); + } + + for (i=0; i < num_members; i++) { + + struct policy_handle alias_handle; + + { + struct samr_OpenAlias r; + r.in.domain_handle = &domain_handle; + r.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED; + r.in.rid = members[i]; + r.out.alias_handle = &alias_handle; + + torture_assert_ntstatus_ok(tctx, + dcerpc_samr_OpenAlias_r(b, tctx, &r), + "samr_OpenAlias failed"); + torture_assert_ntstatus_ok(tctx, r.out.result, + "samr_OpenAlias failed"); + } + + { + struct samr_AddAliasMember r; + r.in.alias_handle = &alias_handle; + r.in.sid = user_sid; + + torture_assert_ntstatus_ok(tctx, + dcerpc_samr_AddAliasMember_r(b, tctx, &r), + "samr_AddAliasMember failed"); + torture_assert_ntstatus_ok(tctx, r.out.result, + "samr_AddAliasMember failed"); + } + + test_samr_handle_Close(b, tctx, &alias_handle); + } + + test_samr_handle_Close(b, tctx, &domain_handle); + test_samr_handle_Close(b, tctx, &connect_handle); + + return true; +} + +static void init_lsa_StringLarge(struct lsa_StringLarge *name, const char *s) +{ + name->string = s; +} +static void init_lsa_String(struct lsa_String *name, const char *s) +{ + name->string = s; +} + +static bool spoolss_access_setup_privs(struct torture_context *tctx, + struct dcerpc_pipe *p, + uint32_t num_privs, + const char **privs, + struct dom_sid *user_sid, + bool *privs_present) +{ + struct dcerpc_binding_handle *b = p->binding_handle; + struct policy_handle *handle; + int i; + + torture_assert(tctx, + test_lsa_OpenPolicy2(b, tctx, &handle), + "failed to open policy"); + + for (i=0; i < num_privs; i++) { + struct lsa_LookupPrivValue r; + struct lsa_LUID luid; + struct lsa_String name; + + init_lsa_String(&name, privs[i]); + + r.in.handle = handle; + r.in.name = &name; + r.out.luid = &luid; + + torture_assert_ntstatus_ok(tctx, + dcerpc_lsa_LookupPrivValue_r(b, tctx, &r), + "lsa_LookupPrivValue failed"); + if (!NT_STATUS_IS_OK(r.out.result)) { + torture_comment(tctx, "lsa_LookupPrivValue failed for '%s' with %s\n", + privs[i], nt_errstr(r.out.result)); + *privs_present = false; + return true; + } + } + + *privs_present = true; + + { + struct lsa_AddAccountRights r; + struct lsa_RightSet rights; + + rights.count = num_privs; + rights.names = talloc_zero_array(tctx, struct lsa_StringLarge, rights.count); + + for (i=0; i < rights.count; i++) { + init_lsa_StringLarge(&rights.names[i], privs[i]); + } + + r.in.handle = handle; + r.in.sid = user_sid; + r.in.rights = &rights; + + torture_assert_ntstatus_ok(tctx, + dcerpc_lsa_AddAccountRights_r(b, tctx, &r), + "lsa_AddAccountRights failed"); + torture_assert_ntstatus_ok(tctx, r.out.result, + "lsa_AddAccountRights failed"); + } + + test_lsa_Close(b, tctx, handle); + + return true; +} + +static bool test_SetPrinter(struct torture_context *tctx, + struct dcerpc_binding_handle *b, + struct policy_handle *handle, + struct spoolss_SetPrinterInfoCtr *info_ctr, + struct spoolss_DevmodeContainer *devmode_ctr, + struct sec_desc_buf *secdesc_ctr, + enum spoolss_PrinterControl command) +{ + struct spoolss_SetPrinter r; + + r.in.handle = handle; + r.in.info_ctr = info_ctr; + r.in.devmode_ctr = devmode_ctr; + r.in.secdesc_ctr = secdesc_ctr; + r.in.command = command; + + torture_comment(tctx, "Testing SetPrinter level %d\n", r.in.info_ctr->level); + + torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_SetPrinter_r(b, tctx, &r), + "failed to call SetPrinter"); + torture_assert_werr_ok(tctx, r.out.result, + "failed to call SetPrinter"); + + return true; +} + +static bool spoolss_access_setup_sd(struct torture_context *tctx, + struct dcerpc_pipe *p, + const char *printername, + const struct dom_sid *user_sid, + struct security_descriptor **sd_orig) +{ + struct dcerpc_binding_handle *b = p->binding_handle; + struct policy_handle handle; + union spoolss_PrinterInfo info; + struct spoolss_SetPrinterInfoCtr info_ctr; + struct spoolss_SetPrinterInfo3 info3; + struct spoolss_DevmodeContainer devmode_ctr; + struct sec_desc_buf secdesc_ctr; + struct security_ace *ace; + struct security_descriptor *sd; + + torture_assert(tctx, + test_openprinter_handle(tctx, p, "", printername, "", SEC_FLAG_MAXIMUM_ALLOWED, WERR_OK, &handle), + "failed to open printer"); + + torture_assert(tctx, + test_GetPrinter_level(tctx, b, &handle, 3, &info), + "failed to get sd"); + + sd = security_descriptor_copy(tctx, info.info3.secdesc); + *sd_orig = security_descriptor_copy(tctx, info.info3.secdesc); + + ace = talloc_zero(tctx, struct security_ace); + + ace->type = SEC_ACE_TYPE_ACCESS_ALLOWED; + ace->flags = 0; + ace->access_mask = PRINTER_ALL_ACCESS; + ace->trustee = *user_sid; + + torture_assert_ntstatus_ok(tctx, + security_descriptor_dacl_add(sd, ace), + "failed to add new ace"); + + ace = talloc_zero(tctx, struct security_ace); + + ace->type = SEC_ACE_TYPE_ACCESS_ALLOWED; + ace->flags = SEC_ACE_FLAG_OBJECT_INHERIT | + SEC_ACE_FLAG_CONTAINER_INHERIT | + SEC_ACE_FLAG_INHERIT_ONLY; + ace->access_mask = SEC_GENERIC_ALL; + ace->trustee = *user_sid; + + torture_assert_ntstatus_ok(tctx, + security_descriptor_dacl_add(sd, ace), + "failed to add new ace"); + + ZERO_STRUCT(info3); + ZERO_STRUCT(info_ctr); + ZERO_STRUCT(devmode_ctr); + ZERO_STRUCT(secdesc_ctr); + + info_ctr.level = 3; + info_ctr.info.info3 = &info3; + secdesc_ctr.sd = sd; + + torture_assert(tctx, + test_SetPrinter(tctx, b, &handle, &info_ctr, &devmode_ctr, &secdesc_ctr, 0), + "failed to set sd"); + + return true; +} + +static bool test_EnumPrinters_findone(struct torture_context *tctx, + struct dcerpc_pipe *p, + const char **printername) +{ + struct spoolss_EnumPrinters r; + uint32_t count; + union spoolss_PrinterInfo *info; + uint32_t needed; + int i; + struct dcerpc_binding_handle *b = p->binding_handle; + + *printername = NULL; + + r.in.flags = PRINTER_ENUM_LOCAL; + r.in.server = NULL; + r.in.level = 1; + r.in.buffer = NULL; + r.in.offered = 0; + r.out.count = &count; + r.out.info = &info; + r.out.needed = &needed; + + torture_assert_ntstatus_ok(tctx, + dcerpc_spoolss_EnumPrinters_r(b, tctx, &r), + "failed to enum printers"); + + if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) { + DATA_BLOB blob = data_blob_talloc_zero(tctx, needed); + r.in.buffer = &blob; + r.in.offered = needed; + + torture_assert_ntstatus_ok(tctx, + dcerpc_spoolss_EnumPrinters_r(b, tctx, &r), + "failed to enum printers"); + } + + torture_assert_werr_ok(tctx, r.out.result, + "failed to enum printers"); + + for (i=0; i < count; i++) { + + if (count > 1 && strequal(info[i].info1.name, "Microsoft XPS Document Writer")) { + continue; + } + + torture_comment(tctx, "testing printer: %s\n", + info[i].info1.name); + + *printername = talloc_strdup(tctx, info[i].info1.name); + + break; + } + + return true; +} + +static bool torture_rpc_spoolss_access_setup_common(struct torture_context *tctx, struct torture_access_context *t) +{ + void *testuser; + const char *testuser_passwd; + struct cli_credentials *test_credentials; + struct dom_sid *test_sid; + struct dcerpc_pipe *p; + const char *printername; + const char *binding = torture_setting_string(tctx, "binding", NULL); + struct dcerpc_pipe *spoolss_pipe; + + testuser = torture_create_testuser_max_pwlen(tctx, t->user.username, + torture_setting_string(tctx, "workgroup", NULL), + ACB_NORMAL, + &testuser_passwd, + 32); + if (!testuser) { + torture_fail(tctx, "Failed to create test user"); + } + + test_credentials = cli_credentials_init(tctx); + cli_credentials_set_workstation(test_credentials, "localhost", CRED_SPECIFIED); + cli_credentials_set_domain(test_credentials, lpcfg_workgroup(tctx->lp_ctx), + CRED_SPECIFIED); + cli_credentials_set_username(test_credentials, t->user.username, CRED_SPECIFIED); + cli_credentials_set_password(test_credentials, testuser_passwd, CRED_SPECIFIED); + test_sid = discard_const_p(struct dom_sid, + torture_join_user_sid(testuser)); + + if (t->user.num_builtin_memberships) { + struct dcerpc_pipe *samr_pipe = torture_join_samr_pipe(testuser); + + torture_assert(tctx, + spoolss_access_setup_membership(tctx, samr_pipe, + t->user.num_builtin_memberships, + t->user.builtin_memberships, + test_sid), + "failed to setup membership"); + } + + if (t->user.num_privs) { + struct dcerpc_pipe *lsa_pipe; + + torture_assert_ntstatus_ok(tctx, + torture_rpc_connection(tctx, &lsa_pipe, &ndr_table_lsarpc), + "Error connecting to server"); + + torture_assert(tctx, + spoolss_access_setup_privs(tctx, lsa_pipe, + t->user.num_privs, + t->user.privs, + test_sid, + &t->user.privs_present), + "failed to setup privs"); + talloc_free(lsa_pipe); + } + + torture_assert_ntstatus_ok(tctx, + torture_rpc_connection(tctx, &spoolss_pipe, &ndr_table_spoolss), + "Error connecting to server"); + + torture_assert(tctx, + test_EnumPrinters_findone(tctx, spoolss_pipe, &printername), + "failed to enumerate printers"); + + if (t->user.sd && printername) { + torture_assert(tctx, + spoolss_access_setup_sd(tctx, spoolss_pipe, + printername, + test_sid, + &t->sd_orig), + "failed to setup sd"); + } + + talloc_free(spoolss_pipe); + + torture_assert_ntstatus_ok(tctx, + dcerpc_pipe_connect(tctx, &p, binding, &ndr_table_spoolss, + test_credentials, tctx->ev, tctx->lp_ctx), + "Error connecting to server"); + + t->spoolss_pipe = p; + t->printername = printername; + t->user.testuser = testuser; + + return true; +} + +static bool torture_rpc_spoolss_access_setup(struct torture_context *tctx, void **data) +{ + struct torture_access_context *t; + + *data = t = talloc_zero(tctx, struct torture_access_context); + + t->user.username = talloc_strdup(t, TORTURE_USER); + + return torture_rpc_spoolss_access_setup_common(tctx, t); +} + +static bool torture_rpc_spoolss_access_admin_setup(struct torture_context *tctx, void **data) +{ + struct torture_access_context *t; + + *data = t = talloc_zero(tctx, struct torture_access_context); + + t->user.num_builtin_memberships = 1; + t->user.builtin_memberships = talloc_zero_array(t, uint32_t, t->user.num_builtin_memberships); + t->user.builtin_memberships[0] = BUILTIN_RID_ADMINISTRATORS; + t->user.username = talloc_strdup(t, TORTURE_USER_ADMINGROUP); + t->user.admin_rights = true; + t->user.system_security = true; + + return torture_rpc_spoolss_access_setup_common(tctx, t); +} + +static bool torture_rpc_spoolss_access_printop_setup(struct torture_context *tctx, void **data) +{ + struct torture_access_context *t; + + *data = t = talloc_zero(tctx, struct torture_access_context); + + t->user.num_builtin_memberships = 1; + t->user.builtin_memberships = talloc_zero_array(t, uint32_t, t->user.num_builtin_memberships); + t->user.builtin_memberships[0] = BUILTIN_RID_PRINT_OPERATORS; + t->user.username = talloc_strdup(t, TORTURE_USER_PRINTOPGROUP); + t->user.admin_rights = true; + + return torture_rpc_spoolss_access_setup_common(tctx, t); +} + +static bool torture_rpc_spoolss_access_priv_setup(struct torture_context *tctx, void **data) +{ + struct torture_access_context *t; + + *data = t = talloc_zero(tctx, struct torture_access_context); + + t->user.username = talloc_strdup(t, TORTURE_USER_PRINTOPPRIV); + t->user.num_privs = 1; + t->user.privs = talloc_zero_array(t, const char *, t->user.num_privs); + t->user.privs[0] = talloc_strdup(t, "SePrintOperatorPrivilege"); + t->user.admin_rights = true; + + return torture_rpc_spoolss_access_setup_common(tctx, t); +} + +static bool torture_rpc_spoolss_access_sd_setup(struct torture_context *tctx, void **data) +{ + struct torture_access_context *t; + + *data = t = talloc_zero(tctx, struct torture_access_context); + + t->user.username = talloc_strdup(t, TORTURE_USER_SD); + t->user.sd = true; + t->user.admin_rights = true; + + return torture_rpc_spoolss_access_setup_common(tctx, t); +} + +static bool torture_rpc_spoolss_access_teardown_common(struct torture_context *tctx, struct torture_access_context *t) +{ + if (t->user.testuser) { + torture_leave_domain(tctx, t->user.testuser); + } + + /* remove membership ? */ + if (t->user.num_builtin_memberships) { + } + + /* remove privs ? */ + if (t->user.num_privs) { + } + + /* restore sd */ + if (t->user.sd && t->printername) { + struct policy_handle handle; + struct spoolss_SetPrinterInfoCtr info_ctr; + struct spoolss_SetPrinterInfo3 info3; + struct spoolss_DevmodeContainer devmode_ctr; + struct sec_desc_buf secdesc_ctr; + struct dcerpc_pipe *spoolss_pipe; + struct dcerpc_binding_handle *b; + + torture_assert_ntstatus_ok(tctx, + torture_rpc_connection(tctx, &spoolss_pipe, &ndr_table_spoolss), + "Error connecting to server"); + + b = spoolss_pipe->binding_handle; + + ZERO_STRUCT(info_ctr); + ZERO_STRUCT(info3); + ZERO_STRUCT(devmode_ctr); + ZERO_STRUCT(secdesc_ctr); + + info_ctr.level = 3; + info_ctr.info.info3 = &info3; + secdesc_ctr.sd = t->sd_orig; + + torture_assert(tctx, + test_openprinter_handle(tctx, spoolss_pipe, "", t->printername, "", SEC_FLAG_MAXIMUM_ALLOWED, WERR_OK, &handle), + "failed to open printer"); + + torture_assert(tctx, + test_SetPrinter(tctx, b, &handle, &info_ctr, &devmode_ctr, &secdesc_ctr, 0), + "failed to set sd"); + + talloc_free(spoolss_pipe); + } + + return true; +} + +static bool torture_rpc_spoolss_access_teardown(struct torture_context *tctx, void *data) +{ + struct torture_access_context *t = talloc_get_type(data, struct torture_access_context); + bool ret; + + ret = torture_rpc_spoolss_access_teardown_common(tctx, t); + talloc_free(t); + + return ret; +} + +static bool test_openprinter(struct torture_context *tctx, + void *private_data) +{ + struct torture_access_context *t = + (struct torture_access_context *)talloc_get_type_abort(private_data, struct torture_access_context); + struct dcerpc_pipe *p = t->spoolss_pipe; + bool ret = true; + const char *username = t->user.username; + const char *servername_slash = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p)); + int i; + + struct { + const char *name; + uint32_t access_mask; + const char *printername; + WERROR expected_result; + } checks[] = { + + /* printserver handle tests */ + + { + .name = "0", + .access_mask = 0, + .printername = servername_slash, + .expected_result = WERR_OK + }, + { + .name = "SEC_FLAG_MAXIMUM_ALLOWED", + .access_mask = SEC_FLAG_MAXIMUM_ALLOWED, + .printername = servername_slash, + .expected_result = WERR_OK + }, + { + .name = "SERVER_ACCESS_ENUMERATE", + .access_mask = SERVER_ACCESS_ENUMERATE, + .printername = servername_slash, + .expected_result = WERR_OK + }, + { + .name = "SERVER_ACCESS_ADMINISTER", + .access_mask = SERVER_ACCESS_ADMINISTER, + .printername = servername_slash, + .expected_result = t->user.admin_rights ? WERR_OK : WERR_ACCESS_DENIED + }, + { + .name = "SERVER_READ", + .access_mask = SERVER_READ, + .printername = servername_slash, + .expected_result = WERR_OK + }, + { + .name = "SERVER_WRITE", + .access_mask = SERVER_WRITE, + .printername = servername_slash, + .expected_result = t->user.admin_rights ? WERR_OK : WERR_ACCESS_DENIED + }, + { + .name = "SERVER_EXECUTE", + .access_mask = SERVER_EXECUTE, + .printername = servername_slash, + .expected_result = WERR_OK + }, + { + .name = "SERVER_ALL_ACCESS", + .access_mask = SERVER_ALL_ACCESS, + .printername = servername_slash, + .expected_result = t->user.admin_rights ? WERR_OK : WERR_ACCESS_DENIED + }, + + /* printer handle tests */ + + { + .name = "0", + .access_mask = 0, + .printername = t->printername, + .expected_result = WERR_OK + }, + { + .name = "SEC_FLAG_MAXIMUM_ALLOWED", + .access_mask = SEC_FLAG_MAXIMUM_ALLOWED, + .printername = t->printername, + .expected_result = WERR_OK + }, + { + .name = "SEC_FLAG_SYSTEM_SECURITY", + .access_mask = SEC_FLAG_SYSTEM_SECURITY, + .printername = t->printername, + .expected_result = t->user.system_security ? WERR_OK : WERR_ACCESS_DENIED + }, + { + .name = "0x010e0000", + .access_mask = 0x010e0000, + .printername = t->printername, + .expected_result = t->user.system_security ? WERR_OK : WERR_ACCESS_DENIED + }, + { + .name = "PRINTER_ACCESS_USE", + .access_mask = PRINTER_ACCESS_USE, + .printername = t->printername, + .expected_result = WERR_OK + }, + { + .name = "SEC_STD_READ_CONTROL", + .access_mask = SEC_STD_READ_CONTROL, + .printername = t->printername, + .expected_result = WERR_OK + }, + { + .name = "PRINTER_ACCESS_ADMINISTER", + .access_mask = PRINTER_ACCESS_ADMINISTER, + .printername = t->printername, + .expected_result = t->user.admin_rights ? WERR_OK : WERR_ACCESS_DENIED + }, + { + .name = "SEC_STD_WRITE_DAC", + .access_mask = SEC_STD_WRITE_DAC, + .printername = t->printername, + .expected_result = t->user.admin_rights ? WERR_OK : WERR_ACCESS_DENIED + }, + { + .name = "SEC_STD_WRITE_OWNER", + .access_mask = SEC_STD_WRITE_OWNER, + .printername = t->printername, + .expected_result = t->user.admin_rights ? WERR_OK : WERR_ACCESS_DENIED + }, + { + .name = "PRINTER_READ", + .access_mask = PRINTER_READ, + .printername = t->printername, + .expected_result = WERR_OK + }, + { + .name = "PRINTER_WRITE", + .access_mask = PRINTER_WRITE, + .printername = t->printername, + .expected_result = t->user.admin_rights ? WERR_OK : WERR_ACCESS_DENIED + }, + { + .name = "PRINTER_EXECUTE", + .access_mask = PRINTER_EXECUTE, + .printername = t->printername, + .expected_result = WERR_OK + }, + { + .name = "PRINTER_ALL_ACCESS", + .access_mask = PRINTER_ALL_ACCESS, + .printername = t->printername, + .expected_result = t->user.admin_rights ? WERR_OK : WERR_ACCESS_DENIED + } + }; + + if (t->user.num_privs && !t->user.privs_present) { + torture_skip(tctx, "skipping test as not all required privileges are present on the server\n"); + } + + for (i=0; i < ARRAY_SIZE(checks); i++) { + ret &= test_openprinter_access(tctx, p, + checks[i].name, + checks[i].printername, + username, + checks[i].access_mask, + checks[i].expected_result); + } + + return ret; +} + +static bool test_openprinter_wrap(struct torture_context *tctx, + struct dcerpc_pipe *p) +{ + struct torture_access_context *t; + const char *printername; + bool ret = true; + + t = talloc_zero(tctx, struct torture_access_context); + + t->user.username = talloc_strdup(tctx, "dummy"); + t->spoolss_pipe = p; + + torture_assert(tctx, + test_EnumPrinters_findone(tctx, p, &printername), + "failed to enumerate printers"); + + t->printername = printername; + + ret = test_openprinter(tctx, (void *)t); + + talloc_free(t); + + return ret; +} + +struct torture_suite *torture_rpc_spoolss_access(TALLOC_CTX *mem_ctx) +{ + struct torture_suite *suite = torture_suite_create(mem_ctx, "spoolss.access"); + struct torture_tcase *tcase; + struct torture_rpc_tcase *rpc_tcase; + + tcase = torture_suite_add_tcase(suite, "normaluser"); + + torture_tcase_set_fixture(tcase, + torture_rpc_spoolss_access_setup, + torture_rpc_spoolss_access_teardown); + + torture_tcase_add_simple_test(tcase, "openprinter", test_openprinter); + + tcase = torture_suite_add_tcase(suite, "adminuser"); + + torture_tcase_set_fixture(tcase, + torture_rpc_spoolss_access_admin_setup, + torture_rpc_spoolss_access_teardown); + + torture_tcase_add_simple_test(tcase, "openprinter", test_openprinter); + + tcase = torture_suite_add_tcase(suite, "printopuser"); + + torture_tcase_set_fixture(tcase, + torture_rpc_spoolss_access_printop_setup, + torture_rpc_spoolss_access_teardown); + + torture_tcase_add_simple_test(tcase, "openprinter", test_openprinter); + + tcase = torture_suite_add_tcase(suite, "printopuserpriv"); + + torture_tcase_set_fixture(tcase, + torture_rpc_spoolss_access_priv_setup, + torture_rpc_spoolss_access_teardown); + + torture_tcase_add_simple_test(tcase, "openprinter", test_openprinter); + + tcase = torture_suite_add_tcase(suite, "normaluser_sd"); + + torture_tcase_set_fixture(tcase, + torture_rpc_spoolss_access_sd_setup, + torture_rpc_spoolss_access_teardown); + + torture_tcase_add_simple_test(tcase, "openprinter", test_openprinter); + + rpc_tcase = torture_suite_add_machine_workstation_rpc_iface_tcase(suite, "workstation", + &ndr_table_spoolss, + TORTURE_WORKSTATION); + + torture_rpc_tcase_add_test(rpc_tcase, "openprinter", test_openprinter_wrap); + + return suite; +} |