mirror of
https://github.com/samba-team/samba.git
synced 2024-12-25 23:21:54 +03:00
efff779c72
Guenther Signed-off-by: Günther Deschner <gd@samba.org> Reviewed-by: Andreas Schneider <asn@samba.org>
905 lines
25 KiB
C
905 lines
25 KiB
C
/*
|
|
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/popt_common.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;
|
|
level1.build = 1381;
|
|
level1.major = 3;
|
|
level1.minor = 0;
|
|
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;
|
|
}
|