Copyright (C) Tim Potter 2003
Copyright (C) Stefan Metzmacher 2005
Copyright (C) Jelmer Vernooij 2007
- Copyright (C) Guenther Deschner 2009-2010
+ Copyright (C) Guenther Deschner 2009-2011,2013
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
#include "libcli/libcli.h"
#include "libcli/raw/raw_proto.h"
#include "libcli/resolve/resolve.h"
+#include "libcli/smb2/smb2.h"
+#include "libcli/smb2/smb2_calls.h"
#include "lib/cmdline/popt_common.h"
#include "system/filesys.h"
#include "torture/ndr/ndr.h"
+#include "torture/smb2/proto.h"
#define TORTURE_WELLKNOWN_PRINTER "torture_wkn_printer"
#define TORTURE_PRINTER "torture_printer"
#define TORTURE_DRIVER_EX_ADOBE "torture_driver_ex_adobe"
#define TORTURE_DRIVER_ADOBE_CUPSADDSMB "torture_driver_adobe_cupsaddsmb"
#define TORTURE_DRIVER_TIMESTAMPS "torture_driver_timestamps"
+#define TORTURE_DRIVER_DELETER "torture_driver_deleter"
+#define TORTURE_DRIVER_DELETERIN "torture_driver_deleterin"
+#define TORTURE_PRINTER_STATIC1 "print1"
#define TOP_LEVEL_PRINT_KEY "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Print"
#define TOP_LEVEL_PRINT_PRINTERS_KEY TOP_LEVEL_PRINT_KEY "\\Printers"
union spoolss_PortInfo *ports[3];
/* for EnumPrinterDrivers */
- uint32_t driver_count[8];
- union spoolss_DriverInfo *drivers[8];
+ uint32_t driver_count[9];
+ union spoolss_DriverInfo *drivers[9];
/* for EnumMonitors */
uint32_t monitor_count[3];
s->info2->drivername = i->info2.drivername;
s->info2->comment = i->info2.comment;
s->info2->location = i->info2.location;
- s->info2->devmode_ptr = 0;
+ s->info2->devmode_ptr = NULL;
s->info2->sepfile = i->info2.sepfile;
s->info2->printprocessor = i->info2.printprocessor;
s->info2->datatype = i->info2.datatype;
s->info2->parameters = i->info2.parameters;
- s->info2->secdesc_ptr = 0;
+ s->info2->secdesc_ptr = NULL;
s->info2->attributes = i->info2.attributes;
s->info2->priority = i->info2.priority;
s->info2->defaultpriority = i->info2.defaultpriority;
return true;
}
-static bool test_EnumPrinterDrivers_args(struct torture_context *tctx,
- struct dcerpc_binding_handle *b,
- const char *server_name,
- const char *environment,
- uint32_t level,
- uint32_t *count_p,
- union spoolss_DriverInfo **info_p)
+static bool test_EnumPrinterDrivers_buffers(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ const char *server_name,
+ const char *environment,
+ uint32_t level,
+ uint32_t offered,
+ uint32_t *count_p,
+ union spoolss_DriverInfo **info_p)
{
struct spoolss_EnumPrinterDrivers r;
uint32_t needed;
uint32_t count;
union spoolss_DriverInfo *info;
+ DATA_BLOB buffer;
+
+ if (offered > 0) {
+ buffer = data_blob_talloc_zero(tctx, offered);
+ }
r.in.server = server_name;
r.in.environment = environment;
r.in.level = level;
- r.in.buffer = NULL;
- r.in.offered = 0;
+ r.in.buffer = offered ? &buffer : NULL;
+ r.in.offered = offered;
r.out.needed = &needed;
r.out.count = &count;
r.out.info = &info;
- torture_comment(tctx, "Testing EnumPrinterDrivers(%s) level %u\n",
- r.in.environment, r.in.level);
+ torture_comment(tctx, "Testing EnumPrinterDrivers(%s) level %u, offered: %u\n",
+ r.in.environment, r.in.level, r.in.offered);
torture_assert_ntstatus_ok(tctx,
dcerpc_spoolss_EnumPrinterDrivers_r(b, tctx, &r),
}
+
+static bool test_EnumPrinterDrivers_args(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ const char *server_name,
+ const char *environment,
+ uint32_t level,
+ uint32_t *count_p,
+ union spoolss_DriverInfo **info_p)
+{
+ return test_EnumPrinterDrivers_buffers(tctx, b, server_name,
+ environment, level, 0,
+ count_p, info_p);
+}
+
static bool test_EnumPrinterDrivers_findone(struct torture_context *tctx,
struct dcerpc_binding_handle *b,
const char *server_name,
"failed to enumerate printer drivers");
for (i=0; i < count; i++) {
- const char *driver_name_ret;
+ const char *driver_name_ret = "";
switch (level) {
case 1:
driver_name_ret = info[i].info1.driver_name;
struct dcerpc_pipe *p = ctx->spoolss_pipe;
struct dcerpc_binding_handle *b = p->binding_handle;
uint16_t levels[] = { 1, 2, 3, 4, 5, 6, 8 };
+ uint16_t buffer_sizes[] = { 0, 1024, 6040, 0xffff };
int i, j, a;
/* FIXME: gd, come back and fix "" as server, and handle
for (a=0;a<ARRAY_SIZE(environments);a++) {
+ for (i=0;i<ARRAY_SIZE(buffer_sizes);i++) {
+ torture_assert(tctx,
+ test_EnumPrinterDrivers_buffers(tctx, b, server_name,
+ environments[a], 3,
+ buffer_sizes[i],
+ NULL, NULL),
+ "failed to enumerate drivers");
+ }
+
for (i=0;i<ARRAY_SIZE(levels);i++) {
int level = levels[i];
uint32_t count;
for (i=0;i<ARRAY_SIZE(levels);i++) {
int level = levels[i];
- for (j=0;j<ctx->driver_count[level];j++) {
- union spoolss_DriverInfo *cur = &ctx->drivers[level][j];
- union spoolss_DriverInfo *ref = &ctx->drivers[8][j];
+ for (j=0;j<ctx->driver_count[level - 1];j++) {
+ union spoolss_DriverInfo *cur = &ctx->drivers[level - 1][j];
+ union spoolss_DriverInfo *ref = &ctx->drivers[7][j];
switch (level) {
case 1:
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");
+ torture_assert(tctx, (W_ERROR_EQUAL(r.out.result, WERR_OK)
+ || W_ERROR_EQUAL(r.out.result, WERR_IO_PENDING)),
+ "SetPrinter failed");
return true;
}
static void clear_info2(struct spoolss_SetPrinterInfoCtr *r)
{
if ((r->level == 2) && (r->info.info2)) {
- r->info.info2->secdesc_ptr = 0;
- r->info.info2->devmode_ptr = 0;
+ r->info.info2->secdesc_ptr = NULL;
+ r->info.info2->devmode_ptr = NULL;
}
}
bool ret = true;
int i;
- torture_skip(tctx, "Printer Info test is currently broken, skipping");
-
uint32_t status_list[] = {
/* these do not stick
PRINTER_STATUS_PAUSED,
0x80000000 */
};
+ torture_skip(tctx, "Printer Info test is currently broken, skipping");
+
+
ZERO_STRUCT(devmode_ctr);
ZERO_STRUCT(secdesc_ctr);
}
#define TEST_PRINTERINFO_STRING_EXP_ERR(lvl1, field1, lvl2, field2, value, err) do { \
+ void *p; \
torture_comment(tctx, "field test %d/%s vs %d/%s\n", lvl1, #field1, lvl2, #field2); \
q.in.level = lvl1; \
TESTGETCALL(GetPrinter, q) \
info_ctr.level = lvl1; \
- info_ctr.info.info ## lvl1 = (struct spoolss_SetPrinterInfo ## lvl1 *)(void *)&q.out.info->info ## lvl1; \
+ p = (void *)&q.out.info->info ## lvl1; \
+ info_ctr.info.info ## lvl1 = (struct spoolss_SetPrinterInfo ## lvl1 *)p; \
info_ctr.info.info ## lvl1->field1 = value;\
TESTSETCALL_EXP(SetPrinter, s, err) \
info_ctr.info.info ## lvl1->field1 = ""; \
STRING_EQUAL(info_ctr.info.info ## lvl1->field1, value, field1); \
q.in.level = lvl2; \
TESTGETCALL(GetPrinter, q) \
- info_ctr.info.info ## lvl2 = (struct spoolss_SetPrinterInfo ## lvl2 *)(void *)&q.out.info->info ## lvl2; \
+ p = (void *)&q.out.info->info ## lvl2; \
+ info_ctr.info.info ## lvl2 = (struct spoolss_SetPrinterInfo ## lvl2 *)p; \
STRING_EQUAL(info_ctr.info.info ## lvl2->field2, value, field2); \
} while (0)
} while (0);
#define TEST_PRINTERINFO_INT_EXP(lvl1, field1, lvl2, field2, value, exp_value) do { \
+ void *p; \
torture_comment(tctx, "field test %d/%s vs %d/%s\n", lvl1, #field1, lvl2, #field2); \
q.in.level = lvl1; \
TESTGETCALL(GetPrinter, q) \
info_ctr.level = lvl1; \
- info_ctr.info.info ## lvl1 = (struct spoolss_SetPrinterInfo ## lvl1 *)(void *)&q.out.info->info ## lvl1; \
+ p = (void *)&q.out.info->info ## lvl1; \
+ info_ctr.info.info ## lvl1 = (struct spoolss_SetPrinterInfo ## lvl1 *)p; \
info_ctr.info.info ## lvl1->field1 = value; \
TESTSETCALL(SetPrinter, s) \
info_ctr.info.info ## lvl1->field1 = 0; \
TESTGETCALL(GetPrinter, q) \
- info_ctr.info.info ## lvl1 = (struct spoolss_SetPrinterInfo ## lvl1 *)(void *)&q.out.info->info ## lvl1; \
+ p = (void *)&q.out.info->info ## lvl1; \
+ info_ctr.info.info ## lvl1 = (struct spoolss_SetPrinterInfo ## lvl1 *)p; \
INT_EQUAL(info_ctr.info.info ## lvl1->field1, exp_value, field1); \
q.in.level = lvl2; \
TESTGETCALL(GetPrinter, q) \
- info_ctr.info.info ## lvl2 = (struct spoolss_SetPrinterInfo ## lvl2 *)(void *)&q.out.info->info ## lvl2; \
+ p = (void *)&q.out.info->info ## lvl2; \
+ info_ctr.info.info ## lvl2 = (struct spoolss_SetPrinterInfo ## lvl2 *)p; \
INT_EQUAL(info_ctr.info.info ## lvl2->field2, exp_value, field1); \
} while (0)
struct spoolss_DevmodeContainer devmode_ctr;
struct sec_desc_buf secdesc_ctr;
union spoolss_SetPrinterInfo sinfo;
+ union spoolss_PrinterInfo info;
+ struct spoolss_SetPrinterInfo3 info3;
ZERO_STRUCT(devmode_ctr);
ZERO_STRUCT(secdesc_ctr);
switch (level) {
case 2: {
- union spoolss_PrinterInfo info;
torture_assert(tctx, test_GetPrinter_level(tctx, b, handle, 2, &info), "");
torture_assert(tctx, PrinterInfo_to_SetPrinterInfo(tctx, &info, 2, &sinfo), "");
break;
}
case 3: {
- struct spoolss_SetPrinterInfo3 info3;
- info3.sec_desc_ptr = 0;
+ info3.sec_desc_ptr = NULL;
info_ctr.level = 3;
info_ctr.info.info3 = &info3;
case 8: {
struct spoolss_SetPrinterInfo8 info8;
- info8.devmode_ptr = 0;
+ info8.devmode_ptr = NULL;
info_ctr.level = 8;
info_ctr.info.info8 = &info8;
{
struct spoolss_SetPrinter s;
struct spoolss_GetPrinter q;
- struct spoolss_GetPrinter q0;
struct spoolss_SetPrinterInfoCtr info_ctr;
struct spoolss_SetPrinterInfo8 info8;
union spoolss_PrinterInfo info;
bool ret = true;
NTSTATUS status;
-#define TEST_DEVMODE_INT_EXP(lvl1, field1, lvl2, field2, value, exp_value) do { \
+#define TEST_DEVMODE_INT_EXP_RESULT(lvl1, field1, lvl2, field2, value, exp_value, expected_result) do { \
torture_comment(tctx, "field test %d/%s vs %d/%s\n", lvl1, #field1, lvl2, #field2); \
q.in.level = lvl1; \
TESTGETCALL(GetPrinter, q) \
info_ctr.level = lvl1; \
if (lvl1 == 2) {\
- info_ctr.info.info ## lvl1 = (struct spoolss_SetPrinterInfo ## lvl1 *)(void *)&q.out.info->info ## lvl1; \
+ void *p = (void *)&q.out.info->info ## lvl1; \
+ info_ctr.info.info ## lvl1 = (struct spoolss_SetPrinterInfo ## lvl1 *)p; \
} else if (lvl1 == 8) {\
info_ctr.info.info ## lvl1 = &info8; \
}\
devmode_ctr.devmode = q.out.info->info ## lvl1.devmode; \
devmode_ctr.devmode->field1 = value; \
- TESTSETCALL(SetPrinter, s) \
- TESTGETCALL(GetPrinter, q) \
- INT_EQUAL(q.out.info->info ## lvl1.devmode->field1, exp_value, field1); \
- q.in.level = lvl2; \
- TESTGETCALL(GetPrinter, q) \
- INT_EQUAL(q.out.info->info ## lvl2.devmode->field2, exp_value, field1); \
+ TESTSETCALL_EXP(SetPrinter, s, expected_result) \
+ if (W_ERROR_IS_OK(expected_result)) { \
+ TESTGETCALL(GetPrinter, q) \
+ INT_EQUAL(q.out.info->info ## lvl1.devmode->field1, exp_value, field1); \
+ q.in.level = lvl2; \
+ TESTGETCALL(GetPrinter, q) \
+ INT_EQUAL(q.out.info->info ## lvl2.devmode->field2, exp_value, field1); \
+ }\
} while (0)
+#define TEST_DEVMODE_INT_EXP(lvl1, field1, lvl2, field2, value, expected_result) do { \
+ TEST_DEVMODE_INT_EXP_RESULT(lvl1, field1, lvl2, field2, value, value, expected_result); \
+ } while (0)
+
#define TEST_DEVMODE_INT(lvl1, field1, lvl2, field2, value) do { \
- TEST_DEVMODE_INT_EXP(lvl1, field1, lvl2, field2, value, value); \
+ TEST_DEVMODE_INT_EXP_RESULT(lvl1, field1, lvl2, field2, value, value, WERR_OK); \
} while (0)
ZERO_STRUCT(devmode_ctr);
q.in.handle = handle;
q.out.info = &info;
- q0 = q;
#if 0
const char *devicename;/* [charset(UTF16)] */
enum spoolss_DeviceModeSpecVersion specversion;
uint16_t driverversion;
- uint16_t size;
uint16_t __driverextra_length;/* [value(r->driverextra_data.length)] */
uint32_t fields;
#endif
+ TEST_DEVMODE_INT_EXP(8, size, 8, size, __LINE__, WERR_INVALID_PARAM);
+ TEST_DEVMODE_INT_EXP(8, size, 8, size, 0, WERR_INVALID_PARAM);
+ TEST_DEVMODE_INT_EXP(8, size, 8, size, 0xffff, WERR_INVALID_PARAM);
+ TEST_DEVMODE_INT_EXP(8, size, 8, size, ndr_size_spoolss_DeviceMode(devmode_ctr.devmode, 0), (devmode_ctr.devmode->__driverextra_length > 0 ) ? WERR_INVALID_PARAM : WERR_OK);
+ TEST_DEVMODE_INT(8, size, 8, size, ndr_size_spoolss_DeviceMode(devmode_ctr.devmode, 0) - devmode_ctr.devmode->__driverextra_length);
+
+ devmode_ctr.devmode->driverextra_data = data_blob_string_const("foobar");
+ torture_assert(tctx,
+ test_devmode_set_level(tctx, b, handle, 8, devmode_ctr.devmode),
+ "failed to set devmode");
+
+ TEST_DEVMODE_INT_EXP(8, size, 8, size, ndr_size_spoolss_DeviceMode(devmode_ctr.devmode, 0), (devmode_ctr.devmode->__driverextra_length > 0 ) ? WERR_INVALID_PARAM : WERR_OK);
+ TEST_DEVMODE_INT(8, size, 8, size, ndr_size_spoolss_DeviceMode(devmode_ctr.devmode, 0) - devmode_ctr.devmode->__driverextra_length);
TEST_DEVMODE_INT(8, orientation, 8, orientation, __LINE__);
TEST_DEVMODE_INT(8, papersize, 8, papersize, __LINE__);
devmode = info.info8.devmode;
+ if (devmode && devmode->size == 0) {
+ torture_fail(tctx,
+ "devmode of zero size!");
+ }
+
torture_assert(tctx, test_GetPrinter_level(tctx, b, handle, 2, &info), "");
devmode2 = info.info2.devmode;
+ if (devmode2 && devmode2->size == 0) {
+ torture_fail(tctx,
+ "devmode of zero size!");
+ }
+
torture_assert(tctx, test_devicemode_equal(tctx, devmode, devmode2),
"DM level 8 != DM level 2");
devmode = info.info8.devmode;
+ if (devmode && devmode->size == 0) {
+ torture_fail(tctx,
+ "devmode of zero size!");
+ }
+
if (addprinter_devmode) {
if (!test_devicemode_equal(tctx, devmode, addprinter_devmode)) {
torture_warning(tctx, "current global DM is != DM provided in addprinter");
WERROR expected_result)
{
struct spoolss_AddForm r;
+ struct spoolss_AddFormInfoCtr info_ctr;
+
+ info_ctr.level = level;
+ info_ctr.info = *info;
if (level != 1) {
torture_skip(tctx, "only level 1 supported");
}
r.in.handle = handle;
- r.in.level = level;
- r.in.info = *info;
+ r.in.info_ctr = &info_ctr;
torture_comment(tctx, "Testing AddForm(%s) level %d, type %d\n",
- r.in.info.info1->form_name, r.in.level,
- r.in.info.info1->flags);
+ r.in.info_ctr->info.info1->form_name, level,
+ r.in.info_ctr->info.info1->flags);
torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_AddForm_r(b, tctx, &r),
"AddForm failed");
union spoolss_AddFormInfo *info)
{
struct spoolss_SetForm r;
+ struct spoolss_AddFormInfoCtr info_ctr;
+
+ info_ctr.level = level;
+ info_ctr.info = *info;
r.in.handle = handle;
r.in.form_name = form_name;
- r.in.level = level;
- r.in.info = *info;
+ r.in.info_ctr = &info_ctr;
torture_comment(tctx, "Testing SetForm(%s) level %d\n",
- form_name, r.in.level);
+ form_name, level);
torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_SetForm_r(b, tctx, &r),
"SetForm failed");
return true;
}
+#if 0
static bool test_GetJob(struct torture_context *tctx,
struct dcerpc_binding_handle *b,
struct policy_handle *handle,
return true;
}
+#endif
static bool test_SetJob(struct torture_context *tctx,
struct dcerpc_binding_handle *b,
torture_comment(tctx, "Testing AddJob\n");
status = dcerpc_spoolss_AddJob_r(b, tctx, &r);
+ torture_assert_ntstatus_ok(tctx, status, "AddJob failed");
torture_assert_werr_equal(tctx, r.out.result, WERR_UNKNOWN_LEVEL, "AddJob failed");
r.in.level = 1;
status = dcerpc_spoolss_AddJob_r(b, tctx, &r);
+ torture_assert_ntstatus_ok(tctx, status, "AddJob failed");
torture_assert_werr_equal(tctx, r.out.result, WERR_INVALID_PARAM, "AddJob failed");
return true;
struct dcerpc_binding_handle *b,
struct policy_handle *handle,
uint32_t level,
+ WERROR werr_expected,
uint32_t *count_p,
union spoolss_JobInfo **info_p)
{
status = dcerpc_spoolss_EnumJobs_r(b, tctx, &r);
torture_assert_ntstatus_ok(tctx, status, "EnumJobs failed");
- torture_assert_werr_ok(tctx, r.out.result, "EnumJobs failed");
+ torture_assert_werr_equal(tctx, r.out.result, werr_expected,
+ "EnumJobs failed");
torture_assert(tctx, info, "No jobs returned");
CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumJobs, *r.out.info, r.in.level, count, needed, 4);
} else {
- torture_assert_werr_ok(tctx, r.out.result, "EnumJobs failed");
+ torture_assert_werr_equal(tctx, r.out.result, werr_expected,
+ "EnumJobs failed");
}
if (count_p) {
return true;
}
-static bool test_DoPrintTest_add_one_job(struct torture_context *tctx,
+static bool test_JobPropertiesEnum(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ struct policy_handle *handle,
+ uint32_t job_id)
+{
+ struct spoolss_RpcEnumJobNamedProperties r;
+ uint32_t pcProperties = 0;
+ struct RPC_PrintNamedProperty *ppProperties = NULL;
+
+ r.in.hPrinter = handle;
+ r.in.JobId = job_id;
+ r.out.pcProperties = &pcProperties;
+ r.out.ppProperties = &ppProperties;
+
+ torture_comment(tctx, "Testing RpcEnumJobNamedProperties(%d)\n", job_id);
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_spoolss_RpcEnumJobNamedProperties_r(b, tctx, &r),
+ "spoolss_RpcEnumJobNamedProperties failed");
+ torture_assert_werr_ok(tctx, r.out.result,
+ "spoolss_RpcEnumJobNamedProperties failed");
+
+ return true;
+}
+
+static bool test_JobPropertySet(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ struct policy_handle *handle,
+ uint32_t job_id,
+ struct RPC_PrintNamedProperty *property)
+{
+ struct spoolss_RpcSetJobNamedProperty r;
+
+ r.in.hPrinter = handle;
+ r.in.JobId = job_id;
+ r.in.pProperty = property;
+
+ torture_comment(tctx, "Testing RpcSetJobNamedProperty(%d) %s - %d\n",
+ job_id, property->propertyName,
+ property->propertyValue.ePropertyType);
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_spoolss_RpcSetJobNamedProperty_r(b, tctx, &r),
+ "spoolss_RpcSetJobNamedProperty failed");
+ torture_assert_werr_ok(tctx, r.out.result,
+ "spoolss_RpcSetJobNamedProperty failed");
+
+ return true;
+}
+
+static bool test_JobPropertyGetValue(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ struct policy_handle *handle,
+ uint32_t job_id,
+ const char *property_name,
+ struct RPC_PrintPropertyValue *value)
+{
+ struct spoolss_RpcGetJobNamedPropertyValue r;
+
+ r.in.hPrinter = handle;
+ r.in.JobId = job_id;
+ r.in.pszName = property_name;
+ r.out.pValue = value;
+
+ torture_comment(tctx, "Testing RpcGetJobNamedPropertyValue(%d) %s\n",
+ job_id, property_name);
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_spoolss_RpcGetJobNamedPropertyValue_r(b, tctx, &r),
+ "spoolss_RpcGetJobNamedPropertyValue failed");
+ torture_assert_werr_ok(tctx, r.out.result,
+ "spoolss_RpcGetJobNamedPropertyValue failed");
+
+ return true;
+}
+
+static bool test_JobPropertyDelete(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ struct policy_handle *handle,
+ uint32_t job_id,
+ const char *property_name)
+{
+ struct spoolss_RpcDeleteJobNamedProperty r;
+
+ r.in.hPrinter = handle;
+ r.in.JobId = job_id;
+ r.in.pszName = property_name;
+
+ torture_comment(tctx, "Testing RpcDeleteJobNamedProperty(%d) %s\n",
+ job_id, property_name);
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_spoolss_RpcDeleteJobNamedProperty_r(b, tctx, &r),
+ "spoolss_RpcDeleteJobNamedProperty failed");
+ torture_assert_werr_ok(tctx, r.out.result,
+ "spoolss_RpcDeleteJobNamedProperty failed");
+
+ return true;
+}
+
+static bool test_DoPrintTest_add_one_job_common(struct torture_context *tctx,
struct dcerpc_binding_handle *b,
struct policy_handle *handle,
+ const char *document_name,
+ const char *datatype,
uint32_t *job_id)
{
NTSTATUS status;
struct spoolss_StartDocPrinter s;
+ struct spoolss_DocumentInfoCtr info_ctr;
struct spoolss_DocumentInfo1 info1;
struct spoolss_StartPagePrinter sp;
struct spoolss_WritePrinter w;
torture_comment(tctx, "Testing StartDocPrinter\n");
s.in.handle = handle;
- s.in.level = 1;
- s.in.info.info1 = &info1;
+ s.in.info_ctr = &info_ctr;
s.out.job_id = job_id;
- info1.document_name = "TorturePrintJob";
+
+ info1.document_name = document_name;
info1.output_file = NULL;
- info1.datatype = "RAW";
+ info1.datatype = datatype;
+
+ info_ctr.level = 1;
+ info_ctr.info.info1 = &info1;
status = dcerpc_spoolss_StartDocPrinter_r(b, tctx, &s);
torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_StartDocPrinter failed");
torture_assert_werr_ok(tctx, s.out.result, "StartDocPrinter failed");
for (i=1; i < 4; i++) {
+ union spoolss_JobInfo ginfo;
+ bool ok;
+
torture_comment(tctx, "Testing StartPagePrinter: Page[%d], JobId[%d]\n", i, *job_id);
sp.in.handle = handle;
"dcerpc_spoolss_StartPagePrinter failed");
torture_assert_werr_ok(tctx, sp.out.result, "StartPagePrinter failed");
+ ok = test_GetJob_args(tctx, b, handle, *job_id, 1, &ginfo);
+ if (!ok) {
+ torture_comment(tctx, "test_GetJob failed for JobId[%d]\n", *job_id);
+ }
+
torture_comment(tctx, "Testing WritePrinter: Page[%d], JobId[%d]\n", i, *job_id);
w.in.handle = handle;
return true;
}
+static bool test_DoPrintTest_add_one_job(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ struct policy_handle *handle,
+ const char *document_name,
+ uint32_t *job_id)
+{
+ test_DoPrintTest_add_one_job_common(tctx, b, handle, document_name, "RAW", job_id);
+
+ return true;
+}
+
+static bool test_DoPrintTest_add_one_job_v4(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ struct policy_handle *handle,
+ const char *document_name,
+ uint32_t *job_id)
+{
+ test_DoPrintTest_add_one_job_common(tctx, b, handle, document_name, "XPS_PASS", job_id);
+
+ return true;
+}
+
+
static bool test_DoPrintTest_check_jobs(struct torture_context *tctx,
struct dcerpc_binding_handle *b,
struct policy_handle *handle,
"AddJob failed");
torture_assert(tctx,
- test_EnumJobs_args(tctx, b, handle, 1, &count, &info),
+ test_EnumJobs_args(tctx, b, handle, 1, WERR_OK, &count, &info),
"EnumJobs level 1 failed");
torture_assert_int_equal(tctx, count, num_jobs, "unexpected number of jobs in queue");
job_ids = talloc_zero_array(tctx, uint32_t, num_jobs);
for (i=0; i < num_jobs; i++) {
- ret &= test_DoPrintTest_add_one_job(tctx, b, handle, &job_ids[i]);
+ ret &= test_DoPrintTest_add_one_job(tctx, b, handle, "TorturePrintJob", &job_ids[i]);
+ }
+
+ for (i=0; i < num_jobs; i++) {
+ ret &= test_SetJob(tctx, b, handle, job_ids[i], NULL, SPOOLSS_JOB_CONTROL_DELETE);
+ }
+
+ for (i=0; i < num_jobs; i++) {
+ ret &= test_DoPrintTest_add_one_job_v4(tctx, b, handle, "TorturePrintJob v4", &job_ids[i]);
}
for (i=0; i < num_jobs; i++) {
job_ids = talloc_zero_array(tctx, uint32_t, num_jobs);
for (i=0; i < num_jobs; i++) {
- ret &= test_DoPrintTest_add_one_job(tctx, b, handle, &job_ids[i]);
+ ret &= test_DoPrintTest_add_one_job(tctx, b, handle, "TorturePrintJob", &job_ids[i]);
}
ret &= test_DoPrintTest_check_jobs(tctx, b, handle, num_jobs, job_ids);
return ret;
}
+static bool test_JobPrintProperties_equal(struct torture_context *tctx,
+ struct RPC_PrintPropertyValue *got,
+ struct RPC_PrintNamedProperty *exp)
+{
+ torture_assert_int_equal(tctx,
+ got->ePropertyType,
+ exp->propertyValue.ePropertyType,
+ "ePropertyType");
+
+ switch (exp->propertyValue.ePropertyType) {
+ case kRpcPropertyTypeString:
+ torture_assert_str_equal(tctx,
+ got->value.propertyString,
+ exp->propertyValue.value.propertyString,
+ "propertyString");
+ break;
+ case kRpcPropertyTypeInt32:
+ torture_assert_int_equal(tctx,
+ got->value.propertyInt32,
+ exp->propertyValue.value.propertyInt32,
+ "propertyInt32");
+ break;
+ case kRpcPropertyTypeInt64:
+ torture_assert_u64_equal(tctx,
+ got->value.propertyInt64,
+ exp->propertyValue.value.propertyInt64,
+ "propertyInt64");
+ break;
+ case kRpcPropertyTypeByte:
+ torture_assert_int_equal(tctx,
+ got->value.propertyByte,
+ exp->propertyValue.value.propertyByte,
+ "propertyByte");
+ break;
+ case kRpcPropertyTypeBuffer:
+ torture_assert_int_equal(tctx,
+ got->value.propertyBlob.cbBuf,
+ exp->propertyValue.value.propertyBlob.cbBuf,
+ "propertyBlob.cbBuf");
+ torture_assert_mem_equal(tctx,
+ got->value.propertyBlob.pBuf,
+ exp->propertyValue.value.propertyBlob.pBuf,
+ exp->propertyValue.value.propertyBlob.cbBuf,
+ "propertyBlob.pBuf");
+
+ break;
+
+ }
+
+ return true;
+}
+
+static bool test_JobPrintProperties(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ struct policy_handle *handle,
+ uint32_t job_id)
+{
+ struct RPC_PrintNamedProperty in;
+ struct RPC_PrintPropertyValue out;
+ int i;
+ DATA_BLOB blob = data_blob_string_const("blob");
+ struct {
+ const char *property_name;
+ enum RPC_EPrintPropertyType type;
+ union RPC_PrintPropertyValueUnion value;
+ WERROR expected_result;
+ } tests[] = {
+ {
+ .property_name = "torture_property_string",
+ .type = kRpcPropertyTypeString,
+ .value.propertyString = "torture_property_value_string",
+ },{
+ .property_name = "torture_property_int32",
+ .type = kRpcPropertyTypeInt32,
+ .value.propertyInt32 = 42,
+ },{
+ .property_name = "torture_property_int64",
+ .type = kRpcPropertyTypeInt64,
+ .value.propertyInt64 = 0xaffe,
+ },{
+ .property_name = "torture_property_byte",
+ .type = kRpcPropertyTypeByte,
+ .value.propertyByte = 0xab,
+ },{
+ .property_name = "torture_property_buffer",
+ .type = kRpcPropertyTypeBuffer,
+ .value.propertyBlob.cbBuf = blob.length,
+ .value.propertyBlob.pBuf = blob.data,
+ }
+ };
+
+ torture_assert(tctx,
+ test_JobPropertiesEnum(tctx, b, handle, job_id),
+ "failed to enum properties");
+
+ for (i=0; i <ARRAY_SIZE(tests); i++) {
+
+ in.propertyName = tests[i].property_name;
+ in.propertyValue.ePropertyType = tests[i].type;
+ in.propertyValue.value = tests[i].value;
+
+ torture_assert(tctx,
+ test_JobPropertySet(tctx, b, handle, job_id, &in),
+ "failed to set property");
+
+ torture_assert(tctx,
+ test_JobPropertyGetValue(tctx, b, handle, job_id, in.propertyName, &out),
+ "failed to get property");
+
+ torture_assert(tctx,
+ test_JobPrintProperties_equal(tctx, &out, &in),
+ "property unequal");
+
+ torture_assert(tctx,
+ test_JobPropertiesEnum(tctx, b, handle, job_id),
+ "failed to enum properties");
+
+ torture_assert(tctx,
+ test_JobPropertyDelete(tctx, b, handle, job_id, in.propertyName),
+ "failed to delete job property");
+ }
+
+ torture_assert(tctx,
+ test_JobPropertiesEnum(tctx, b, handle, job_id),
+ "failed to enum properties");
+
+ return true;
+}
+
+static bool test_DoPrintTest_properties(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ struct policy_handle *handle)
+{
+ uint32_t num_jobs = 8;
+ uint32_t *job_ids;
+ int i;
+ torture_comment(tctx, "Testing real print operations (properties)\n");
+
+ job_ids = talloc_zero_array(tctx, uint32_t, num_jobs);
+
+ for (i=0; i < num_jobs; i++) {
+ torture_assert(tctx,
+ test_DoPrintTest_add_one_job(tctx, b, handle, "TorturePrintJob", &job_ids[i]),
+ "failed to create print job");
+ }
+
+ for (i=0; i < num_jobs; i++) {
+ torture_assert(tctx,
+ test_JobPrintProperties(tctx, b, handle, job_ids[i]),
+ "failed to test job properties");
+ }
+
+
+ for (i=0; i < num_jobs; i++) {
+ torture_assert(tctx,
+ test_SetJob(tctx, b, handle, job_ids[i], NULL, SPOOLSS_JOB_CONTROL_DELETE),
+ "failed to delete printjob");
+ }
+
+ torture_comment(tctx, "real print operations (properties) test succeeded\n\n");
+
+ return true;
+}
+
static bool test_PausePrinter(struct torture_context *tctx,
struct dcerpc_binding_handle *b,
struct policy_handle *handle)
return true;
}
+static bool test_printer_purge(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ struct policy_handle *handle)
+{
+ NTSTATUS status;
+ struct spoolss_SetPrinter r;
+ struct spoolss_SetPrinterInfoCtr info_ctr;
+ struct spoolss_DevmodeContainer devmode_ctr;
+ struct sec_desc_buf secdesc_ctr;
+
+ info_ctr.level = 0;
+ info_ctr.info.info0 = NULL;
+
+ ZERO_STRUCT(devmode_ctr);
+ ZERO_STRUCT(secdesc_ctr);
+
+ 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 = SPOOLSS_PRINTER_CONTROL_PURGE;
+
+ torture_comment(tctx, "Testing SetPrinter: SPOOLSS_PRINTER_CONTROL_PURGE\n");
+
+ status = dcerpc_spoolss_SetPrinter_r(b, tctx, &r);
+ torture_assert_ntstatus_ok(tctx, status, "SetPrinter failed");
+ torture_assert_werr_ok(tctx, r.out.result, "SetPrinter failed");
+
+ return true;
+}
+
static bool test_GetPrinterData_checktype(struct torture_context *tctx,
struct dcerpc_binding_handle *b,
struct policy_handle *handle,
struct policy_handle *hive_handle,
const char *server_name_slash)
{
- WERROR result;
+ WERROR result = WERR_OK;
union spoolss_DriverInfo info;
const char *driver_key;
struct policy_handle key_handle;
const char *driver_version;
const char *inbox_driver_version;
+ ZERO_STRUCT(key_handle);
+
torture_comment(tctx, "Testing Driver Info and winreg consistency\n");
driver_key = talloc_asprintf(tctx, "%s\\%s\\Drivers\\Version-%d\\%s",
test_winreg_OpenKey(tctx, winreg_handle, hive_handle, driver_key, &key_handle),
"failed to open driver key");
- if (torture_setting_bool(tctx, "samba3", false)) {
- goto try_level3;
- }
-
- if (torture_setting_bool(tctx, "w2k3", false)) {
+ if (torture_setting_bool(tctx, "samba3", false) ||
+ torture_setting_bool(tctx, "w2k3", false)) {
goto try_level6;
}
test_dword("Version", info.info6.version);
/* test_dword("TempDir", ?); */
- try_level3:
-
if (handle) {
torture_assert(tctx,
test_GetPrinterDriver2_level(tctx, b, handle, driver_name, environment, 3, version, 0, &info, &result),
TEST_SET_SZ("description", comment, "newval");
TEST_SET_SZ("location", location, "newval");
+ TEST_SET_SZ("driverName", drivername, "newval");
/* TEST_SET_DWORD("priority", priority, 25); */
torture_assert(tctx,
return test_PrintProcessors_winreg(tctx, b, ctx->environment);
}
-static bool test_GetChangeID_PrinterData(struct torture_context *tctx,
- struct dcerpc_binding_handle *b,
+static bool test_AddPrintProcessor(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ const char *environment,
+ const char *path_name,
+ const char *print_processor_name,
+ WERROR expected_error)
+{
+ struct spoolss_AddPrintProcessor r;
+
+ r.in.server = NULL;
+ r.in.architecture = environment;
+ r.in.path_name = path_name;
+ r.in.print_processor_name = print_processor_name;
+
+ torture_comment(tctx, "Testing AddPrintProcessor(%s)\n",
+ print_processor_name);
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_spoolss_AddPrintProcessor_r(b, tctx, &r),
+ "spoolss_AddPrintProcessor failed");
+ torture_assert_werr_equal(tctx, r.out.result, expected_error,
+ "spoolss_AddPrintProcessor failed");
+
+ return true;
+}
+
+static bool test_DeletePrintProcessor(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ const char *environment,
+ const char *print_processor_name,
+ WERROR expected_error)
+{
+ struct spoolss_DeletePrintProcessor r;
+
+ r.in.server = NULL;
+ r.in.architecture = environment;
+ r.in.print_processor_name = print_processor_name;
+
+ torture_comment(tctx, "Testing DeletePrintProcessor(%s)\n",
+ print_processor_name);
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_spoolss_DeletePrintProcessor_r(b, tctx, &r),
+ "spoolss_DeletePrintProcessor failed");
+ torture_assert_werr_equal(tctx, r.out.result, expected_error,
+ "spoolss_DeletePrintProcessor failed");
+
+ return true;
+}
+
+static bool test_add_print_processor(struct torture_context *tctx,
+ void *private_data)
+{
+ struct test_spoolss_context *ctx =
+ talloc_get_type_abort(private_data, struct test_spoolss_context);
+ struct dcerpc_pipe *p = ctx->spoolss_pipe;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ int i;
+
+ struct {
+ const char *environment;
+ const char *path_name;
+ const char *print_processor_name;
+ WERROR expected_add_result;
+ WERROR expected_del_result;
+ } tests[] = {
+ {
+ .environment = ctx->environment,
+ .path_name = "",
+ .print_processor_name = "winprint",
+ .expected_add_result = WERR_PRINT_PROCESSOR_ALREADY_INSTALLED,
+ .expected_del_result = WERR_CAN_NOT_COMPLETE
+ },{
+ .environment = ctx->environment,
+ .path_name = "",
+ .print_processor_name = "unknown",
+ .expected_add_result = WERR_MOD_NOT_FOUND,
+ .expected_del_result = WERR_UNKNOWN_PRINTPROCESSOR
+ }
+ };
+
+ for (i=0; i < ARRAY_SIZE(tests); i++) {
+ torture_assert(tctx,
+ test_AddPrintProcessor(tctx, b,
+ tests[i].environment,
+ tests[i].path_name,
+ tests[i].print_processor_name,
+ tests[i].expected_add_result),
+ "add print processor failed");
+ torture_assert(tctx,
+ test_DeletePrintProcessor(tctx, b,
+ tests[i].environment,
+ tests[i].print_processor_name,
+ tests[i].expected_del_result),
+ "delete print processor failed");
+ }
+
+ return true;
+}
+
+static bool test_GetChangeID_PrinterData(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
struct policy_handle *handle,
uint32_t *change_id)
{
struct policy_handle *handle)
{
NTSTATUS status;
- struct dcerpc_binding *b;
+ const struct dcerpc_binding *binding2;
struct dcerpc_pipe *p2;
struct spoolss_ClosePrinter cp;
torture_comment(tctx, "Testing close on secondary pipe\n");
- status = dcerpc_parse_binding(tctx, p->conn->binding_string, &b);
- torture_assert_ntstatus_ok(tctx, status, "Failed to parse dcerpc binding");
-
- status = dcerpc_secondary_connection(p, &p2, b);
+ binding2 = p->binding;
+ status = dcerpc_secondary_connection(p, &p2, binding2);
torture_assert_ntstatus_ok(tctx, status, "Failed to create secondary connection");
status = dcerpc_bind_auth_none(p2, &ndr_table_spoolss);
opEx.in.datatype = NULL;
opEx.in.devmode_ctr.devmode = NULL;
opEx.in.access_mask = 0;
- opEx.in.level = 1;
- opEx.in.userlevel.level1 = NULL;
+ opEx.in.userlevel_ctr.level = 1;
+ opEx.in.userlevel_ctr.user_info.level1 = NULL;
opEx.out.handle = &handle;
torture_comment(tctx, "Testing OpenPrinterEx(%s) with bad name\n", opEx.in.printername);
const char *datatype,
struct spoolss_DeviceMode *devmode,
uint32_t access_mask,
- uint32_t level,
- union spoolss_UserLevel *userlevel,
+ struct spoolss_UserLevelCtr *userlevel_ctr,
struct policy_handle *handle,
WERROR expected_result)
{
r.in.datatype = datatype;
r.in.devmode_ctr.devmode= devmode;
r.in.access_mask = access_mask;
- r.in.level = level;
- r.in.userlevel = *userlevel;
+ r.in.userlevel_ctr = *userlevel_ctr;
r.out.handle = handle;
torture_comment(tctx, "Testing OpenPrinterEx(%s)\n", r.in.printername);
struct spoolss_DeviceMode *devmode,
struct policy_handle *handle)
{
- union spoolss_UserLevel userlevel;
+ struct spoolss_UserLevelCtr userlevel_ctr;
struct spoolss_UserLevel1 userlevel1;
struct dcerpc_binding_handle *b = p->binding_handle;
userlevel1.minor = 3;
userlevel1.processor = 4;
- userlevel.level1 = &userlevel1;
+ userlevel_ctr.level = 1;
+ userlevel_ctr.user_info.level1 = &userlevel1;
return test_OpenPrinterEx(tctx, b, name, NULL, devmode,
SEC_FLAG_MAXIMUM_ALLOWED,
- 1,
- &userlevel,
+ &userlevel_ctr,
handle,
WERR_OK);
}
struct dcerpc_binding_handle *b,
const char *real_printername)
{
- union spoolss_UserLevel userlevel;
+ struct spoolss_UserLevelCtr userlevel_ctr;
struct policy_handle handle;
struct spoolss_UserLevel1 userlevel1;
const char *printername = NULL;
userlevel1.minor = 3;
userlevel1.processor = 4;
- userlevel.level1 = &userlevel1;
+ userlevel_ctr.level = 1;
+ userlevel_ctr.user_info.level1 = &userlevel1;
torture_comment(tctx, "Testing openprinterex printername pattern\n");
torture_assert(tctx,
- test_OpenPrinterEx(tctx, b, real_printername, NULL, NULL, 0, 1,
- &userlevel, &handle,
+ test_OpenPrinterEx(tctx, b, real_printername, NULL, NULL, 0,
+ &userlevel_ctr, &handle,
WERR_OK),
"OpenPrinterEx failed");
test_ClosePrinter(tctx, b, &handle);
tests[i].suffix);
torture_assert(tctx,
- test_OpenPrinterEx(tctx, b, printername, NULL, NULL, 0, 1,
- &userlevel, &handle,
+ test_OpenPrinterEx(tctx, b, printername, NULL, NULL, 0,
+ &userlevel_ctr, &handle,
tests[i].expected_result),
"OpenPrinterEx failed");
if (W_ERROR_IS_OK(tests[i].expected_result)) {
return true;
}
-
+#if 0
static bool test_GetPrinterDriver(struct torture_context *tctx,
struct dcerpc_binding_handle *b,
struct policy_handle *handle,
return true;
}
+#endif
static bool test_GetPrinterDriver2_level(struct torture_context *tctx,
struct dcerpc_binding_handle *b,
return true;
}
+#if 0
static struct spoolss_DeviceMode *torture_devicemode(TALLOC_CTX *mem_ctx,
const char *devicename)
{
return r;
}
+#endif
static bool test_architecture_buffer(struct torture_context *tctx,
void *private_data)
r.in.datatype = NULL;
r.in.devmode_ctr.devmode= NULL;
r.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
- r.in.level = 1;
- r.in.userlevel.level1 = &u1;
+ r.in.userlevel_ctr.level = 1;
+ r.in.userlevel_ctr.user_info.level1 = &u1;
r.out.handle = &handle;
torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_OpenPrinterEx_r(b, tctx, &r), "");
t->driver.local.driver_directory= "/usr/share/cups/drivers";
- t->info2.drivername = "Microsoft XPS Document Writer";
t->info2.portname = "LPT1:";
printer_name = t->info2.printername;
&t->driver.local.driver_directory),
"failed to compose local driver directory");
+ t->info2.drivername = "Microsoft XPS Document Writer";
+
if (test_EnumPrinterDrivers_findone(tctx, b, server_name_slash, t->driver.remote.environment, 3, t->info2.drivername, NULL)) {
torture_comment(tctx, "driver '%s' (architecture: %s, version: 3) is present on server\n",
t->info2.drivername, t->driver.remote.environment);
torture_comment(tctx, "driver '%s' (architecture: %s, version: 3) does not exist on the server\n",
t->info2.drivername, t->driver.remote.environment);
+
+ t->info2.drivername = "Microsoft XPS Document Writer v4";
+
+ if (test_EnumPrinterDrivers_findone(tctx, b, server_name_slash, t->driver.remote.environment, 3, t->info2.drivername, NULL)) {
+ torture_comment(tctx, "driver '%s' (architecture: %s, version: 4) is present on server\n",
+ t->info2.drivername, t->driver.remote.environment);
+ t->have_driver = true;
+ goto try_add;
+ }
+
torture_comment(tctx, "trying to upload own driver\n");
if (!directory_exist(t->driver.local.driver_directory)) {
return torture_rpc_spoolss_printer_setup_common(tctx, t);
}
+#if 0
static bool torture_rpc_spoolss_printerdm_setup(struct torture_context *tctx, void **data)
{
struct torture_printer_context *t;
return torture_rpc_spoolss_printer_setup_common(tctx, t);
}
+#endif
static bool torture_rpc_spoolss_printer_teardown_common(struct torture_context *tctx, struct torture_printer_context *t)
{
"failed to remove printer driver");
}
- if (p) {
+ if (p && !t->wellknown) {
b = p->binding_handle;
- }
- if (!t->wellknown) {
torture_assert(tctx,
test_DeletePrinter(tctx, b, &t->handle),
"failed to delete printer");
return ret;
}
+static bool test_print_test_properties(struct torture_context *tctx,
+ void *private_data)
+{
+ struct torture_printer_context *t =
+ (struct torture_printer_context *)talloc_get_type_abort(private_data, struct torture_printer_context);
+ struct dcerpc_pipe *p = t->spoolss_pipe;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ if (torture_setting_bool(tctx, "samba3", false)) {
+ torture_skip(tctx, "skip printer job property tests against samba");
+ }
+
+ torture_assert(tctx,
+ test_PausePrinter(tctx, b, &t->handle),
+ "failed to pause printer");
+
+ torture_assert(tctx,
+ test_DoPrintTest_properties(tctx, b, &t->handle),
+ "failed to test print job properties");
+
+ torture_assert(tctx,
+ test_ResumePrinter(tctx, b, &t->handle),
+ "failed to resume printer");
+
+ return true;
+}
+
+/* use smbd file IO to spool a print job */
+static bool test_print_test_smbd(struct torture_context *tctx,
+ void *private_data)
+{
+ struct torture_printer_context *t =
+ (struct torture_printer_context *)talloc_get_type_abort(private_data, struct torture_printer_context);
+ struct dcerpc_pipe *p = t->spoolss_pipe;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ NTSTATUS status;
+ uint32_t count;
+ union spoolss_JobInfo *info = NULL;
+ int i;
+
+ struct smb2_tree *tree;
+ struct smb2_handle job_h;
+ struct cli_credentials *credentials = cmdline_credentials;
+ struct smbcli_options options;
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ /*
+ * Do not test against the dynamically added printers, printing via
+ * smbd means that a different spoolss process may handle the
+ * OpenPrinter request to the one that handled the AddPrinter request.
+ * This currently leads to an ugly race condition where one process
+ * sees the new printer and one doesn't.
+ */
+ const char *share = TORTURE_PRINTER_STATIC1;
+
+ torture_comment(tctx, "Testing smbd job spooling\n");
+ lpcfg_smbcli_options(tctx->lp_ctx, &options);
+
+ status = smb2_connect(mem_ctx,
+ torture_setting_string(tctx, "host", NULL),
+ lpcfg_smb_ports(tctx->lp_ctx),
+ share,
+ lpcfg_resolve_context(tctx->lp_ctx),
+ credentials,
+ &tree,
+ tctx->ev,
+ &options,
+ lpcfg_socket_options(tctx->lp_ctx),
+ lpcfg_gensec_settings(tctx, tctx->lp_ctx));
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("Failed to connect to SMB2 printer %s - %s\n",
+ share, nt_errstr(status));
+ return false;
+ }
+
+ status = torture_smb2_testfile(tree, "smbd_spooler_job", &job_h);
+ torture_assert_ntstatus_ok(tctx, status, "smbd spool job create");
+
+ status = smb2_util_write(tree, job_h, "exciting print job data", 0,
+ sizeof("exciting print job data"));
+ torture_assert_ntstatus_ok(tctx, status, "smbd spool job write");
+
+ /* check back end spoolss job was created */
+ torture_assert(tctx,
+ test_EnumJobs_args(tctx, b, &t->handle, 1, WERR_OK,
+ &count, &info),
+ "EnumJobs level 1 failed");
+
+ for (i = 0; i < count; i++) {
+ if (!strcmp(info[i].info1.document_name, "smbd_spooler_job")) {
+ break;
+ }
+ }
+ torture_assert(tctx, (i != count), "smbd_spooler_job not found");
+
+ status = smb2_util_close(tree, job_h);
+ torture_assert_ntstatus_ok(tctx, status, "smbd spool job close");
+
+ /* disconnect from printer share */
+ talloc_free(mem_ctx);
+
+ return true;
+}
+
+static bool test_print_test_purge(struct torture_context *tctx,
+ void *private_data)
+{
+ struct torture_printer_context *t =
+ (struct torture_printer_context *)talloc_get_type_abort(private_data,
+ struct torture_printer_context);
+ struct dcerpc_pipe *p = t->spoolss_pipe;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ uint32_t num_jobs = 8;
+ uint32_t *job_ids;
+ int i;
+ bool ret = true;
+ uint32_t count;
+ union spoolss_JobInfo *info;
+
+ torture_assert(tctx,
+ test_PausePrinter(tctx, b, &t->handle),
+ "failed to pause printer");
+
+ job_ids = talloc_zero_array(tctx, uint32_t, num_jobs);
+ for (i=0; i < num_jobs; i++) {
+ ret = test_DoPrintTest_add_one_job(tctx, b, &t->handle,
+ "TorturePrintJob",
+ &job_ids[i]);
+ torture_assert(tctx, ret, "failed to add print job");
+ }
+
+ torture_assert(tctx,
+ test_EnumJobs_args(tctx, b, &t->handle, 1, WERR_OK,
+ &count, &info),
+ "EnumJobs level 1 failed");
+
+ torture_assert_int_equal(tctx, count, num_jobs,
+ "unexpected number of jobs in queue");
+
+ torture_assert(tctx,
+ test_printer_purge(tctx, b, &t->handle),
+ "failed to purge printer");
+
+ torture_assert(tctx,
+ test_EnumJobs_args(tctx, b, &t->handle, 1, WERR_OK,
+ &count, &info),
+ "EnumJobs level 1 failed");
+
+ torture_assert_int_equal(tctx, count, 0,
+ "unexpected number of jobs in queue");
+
+ torture_assert(tctx,
+ test_ResumePrinter(tctx, b, &t->handle),
+ "failed to resume printer");
+
+ return true;
+}
+
static bool test_printer_sd(struct torture_context *tctx,
void *private_data)
{
return true;
}
-static bool test_driver_info_winreg(struct torture_context *tctx,
- void *private_data)
+static bool test_printer_ic(struct torture_context *tctx,
+ void *private_data)
{
struct torture_printer_context *t =
- (struct torture_printer_context *)talloc_get_type_abort(private_data, struct torture_printer_context);
+ talloc_get_type_abort(private_data,
+ struct torture_printer_context);
struct dcerpc_pipe *p = t->spoolss_pipe;
- const char *driver_name = t->added_driver ? t->driver.info8.driver_name : t->info2.drivername;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ struct policy_handle gdi_handle;
- if (!t->have_driver) {
- torture_skip(tctx, "skipping driver info winreg test as we don't have a driver");
+ if (torture_setting_bool(tctx, "samba3", false)) {
+ torture_skip(tctx, "skip printer information context tests against samba");
}
- torture_assert(tctx,
- test_DriverInfo_winreg(tctx, p, &t->handle, t->info2.printername, driver_name, t->driver.remote.environment, 3),
- "failed to test driver info winreg");
+ {
+ struct spoolss_CreatePrinterIC r;
+ struct spoolss_DevmodeContainer devmode_ctr;
- return true;
-}
+ ZERO_STRUCT(devmode_ctr);
-void torture_tcase_printer(struct torture_tcase *tcase)
-{
- torture_tcase_add_simple_test(tcase, "openprinter", test_openprinter_wrap);
- torture_tcase_add_simple_test(tcase, "csetprinter", test_csetprinter);
- torture_tcase_add_simple_test(tcase, "print_test", test_print_test);
- torture_tcase_add_simple_test(tcase, "print_test_extended", test_print_test_extended);
- torture_tcase_add_simple_test(tcase, "printer_info", test_printer_info);
- torture_tcase_add_simple_test(tcase, "sd", test_printer_sd);
- torture_tcase_add_simple_test(tcase, "dm", test_printer_dm);
- torture_tcase_add_simple_test(tcase, "printer_info_winreg", test_printer_info_winreg);
- torture_tcase_add_simple_test(tcase, "change_id", test_printer_change_id);
- torture_tcase_add_simple_test(tcase, "keys", test_printer_keys);
- torture_tcase_add_simple_test(tcase, "printerdata_consistency", test_printer_data_consistency);
- torture_tcase_add_simple_test(tcase, "printerdata_keys", test_printer_data_keys);
- torture_tcase_add_simple_test(tcase, "printerdata_values", test_printer_data_values);
- torture_tcase_add_simple_test(tcase, "printerdata_set", test_printer_data_set);
- torture_tcase_add_simple_test(tcase, "printerdata_winreg", test_printer_data_winreg);
- torture_tcase_add_simple_test(tcase, "printerdata_dsspooler", test_printer_data_dsspooler);
- torture_tcase_add_simple_test(tcase, "driver_info_winreg", test_driver_info_winreg);
- torture_tcase_add_simple_test(tcase, "printer_rename", test_printer_rename);
-}
+ r.in.handle = &t->handle;
+ r.in.devmode_ctr = &devmode_ctr;
+ r.out.gdi_handle = &gdi_handle;
-struct torture_suite *torture_rpc_spoolss_printer(TALLOC_CTX *mem_ctx)
-{
- struct torture_suite *suite = torture_suite_create(mem_ctx, "printer");
- struct torture_tcase *tcase;
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_spoolss_CreatePrinterIC_r(b, tctx, &r),
+ "CreatePrinterIC failed");
+ torture_assert_werr_ok(tctx, r.out.result,
+ "CreatePrinterIC failed");
+ }
- tcase = torture_suite_add_tcase(suite, "addprinter");
+ {
+ struct spoolss_PlayGDIScriptOnPrinterIC r;
+ DATA_BLOB in,out;
+ int i;
+ uint32_t num_fonts = 0;
- torture_tcase_set_fixture(tcase,
- torture_rpc_spoolss_printer_setup,
- torture_rpc_spoolss_printer_teardown);
+ in = data_blob_string_const("");
- torture_tcase_printer(tcase);
+ r.in.gdi_handle = &gdi_handle;
+ r.in.pIn = in.data;
+ r.in.cIn = in.length;
+ r.in.ul = 0;
- tcase = torture_suite_add_tcase(suite, "addprinterex");
+ for (i = 0; i < 4; i++) {
- torture_tcase_set_fixture(tcase,
- torture_rpc_spoolss_printerex_setup,
- torture_rpc_spoolss_printer_teardown);
+ out = data_blob_talloc_zero(tctx, i);
- torture_tcase_printer(tcase);
+ r.in.cOut = out.length;
+ r.out.pOut = out.data;
- tcase = torture_suite_add_tcase(suite, "addprinterwkn");
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_spoolss_PlayGDIScriptOnPrinterIC_r(b, tctx, &r),
+ "PlayGDIScriptOnPrinterIC failed");
+ torture_assert_werr_equal(tctx, r.out.result, WERR_NOMEM,
+ "PlayGDIScriptOnPrinterIC failed");
+ }
- torture_tcase_set_fixture(tcase,
- torture_rpc_spoolss_printerwkn_setup,
- torture_rpc_spoolss_printer_teardown);
+ out = data_blob_talloc_zero(tctx, 4);
- tcase = torture_suite_add_tcase(suite, "addprinterexwkn");
+ r.in.cOut = out.length;
+ r.out.pOut = out.data;
- torture_tcase_set_fixture(tcase,
- torture_rpc_spoolss_printerexwkn_setup,
- torture_rpc_spoolss_printer_teardown);
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_spoolss_PlayGDIScriptOnPrinterIC_r(b, tctx, &r),
+ "PlayGDIScriptOnPrinterIC failed");
+ torture_assert_werr_equal(tctx, r.out.result, WERR_OK,
+ "PlayGDIScriptOnPrinterIC failed");
-#if 0
- /* test is not correct */
- tcase = torture_suite_add_tcase(suite, "addprinterdm");
+ /* now we should have the required length, so retry with a
+ * buffer which is large enough to carry all font ids */
- torture_tcase_set_fixture(tcase,
- torture_rpc_spoolss_printerdm_setup,
- torture_rpc_spoolss_printer_teardown);
+ num_fonts = IVAL(r.out.pOut, 0);
- torture_tcase_printer(tcase);
-#endif
- return suite;
-}
+ torture_comment(tctx, "PlayGDIScriptOnPrinterIC gave font count of %d\n", num_fonts);
-struct torture_suite *torture_rpc_spoolss(TALLOC_CTX *mem_ctx)
-{
- struct torture_suite *suite = torture_suite_create(mem_ctx, "spoolss");
- struct torture_tcase *tcase = torture_suite_add_tcase(suite, "printserver");
+ out = data_blob_talloc_zero(tctx,
+ num_fonts * sizeof(struct UNIVERSAL_FONT_ID) + 4);
- torture_tcase_set_fixture(tcase,
- torture_rpc_spoolss_setup,
- torture_rpc_spoolss_teardown);
+ r.in.cOut = out.length;
+ r.out.pOut = out.data;
- torture_tcase_add_simple_test(tcase, "openprinter_badnamelist", test_OpenPrinter_badname_list);
- torture_tcase_add_simple_test(tcase, "printer_data_list", test_GetPrinterData_list);
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_spoolss_PlayGDIScriptOnPrinterIC_r(b, tctx, &r),
+ "PlayGDIScriptOnPrinterIC failed");
+ torture_assert_werr_equal(tctx, r.out.result, WERR_OK,
+ "PlayGDIScriptOnPrinterIC failed");
+
+ }
+
+ {
+ struct spoolss_DeletePrinterIC r;
+
+ r.in.gdi_handle = &gdi_handle;
+ r.out.gdi_handle = &gdi_handle;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_spoolss_DeletePrinterIC_r(b, tctx, &r),
+ "DeletePrinterIC failed");
+ torture_assert_werr_ok(tctx, r.out.result,
+ "DeletePrinterIC failed");
+
+ }
+
+ return true;
+}
+
+static bool test_printer_bidi(struct torture_context *tctx,
+ void *private_data)
+{
+ struct torture_printer_context *t =
+ talloc_get_type_abort(private_data,
+ struct torture_printer_context);
+ struct dcerpc_pipe *p = t->spoolss_pipe;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ struct spoolss_RpcSendRecvBidiData r;
+ struct RPC_BIDI_REQUEST_CONTAINER bidi_req;
+ struct RPC_BIDI_RESPONSE_CONTAINER *bidi_rep = NULL;
+
+ if (torture_setting_bool(tctx, "samba3", false)) {
+ torture_skip(tctx, "skip printer bidirectional tests against samba");
+ }
+
+ ZERO_STRUCT(bidi_req);
+
+ r.in.hPrinter = t->handle;
+ r.in.pAction = "foobar";
+ r.in.pReqData = &bidi_req;
+ r.out.ppRespData = &bidi_rep;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_spoolss_RpcSendRecvBidiData_r(b, tctx, &r),
+ "RpcSendRecvBidiData failed");
+ torture_assert_werr_equal(tctx, r.out.result, WERR_NOT_SUPPORTED,
+ "RpcSendRecvBidiData failed");
+
+ if (!(t->info2.attributes & PRINTER_ATTRIBUTE_ENABLE_BIDI)) {
+ torture_skip(tctx, "skipping further tests as printer is not BIDI enabled");
+ }
+
+ r.in.pAction = BIDI_ACTION_ENUM_SCHEMA;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_spoolss_RpcSendRecvBidiData_r(b, tctx, &r),
+ "RpcSendRecvBidiData failed");
+ torture_assert_werr_ok(tctx, r.out.result,
+ "RpcSendRecvBidiData failed");
+
+ return true;
+}
+
+static bool test_printer_set_publish(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ struct policy_handle *handle)
+{
+ union spoolss_PrinterInfo info;
+ struct spoolss_SetPrinterInfo7 info7;
+ struct spoolss_SetPrinterInfoCtr info_ctr;
+ struct spoolss_DevmodeContainer devmode_ctr;
+ struct sec_desc_buf secdesc_ctr;
+
+ info7.guid = "";
+ info7.action = DSPRINT_PUBLISH;
+
+ ZERO_STRUCT(info_ctr);
+ ZERO_STRUCT(devmode_ctr);
+ ZERO_STRUCT(secdesc_ctr);
+ info_ctr.level = 7;
+ info_ctr.info.info7 = &info7;
+
+ torture_assert(tctx,
+ test_SetPrinter(tctx, b, handle, &info_ctr,
+ &devmode_ctr, &secdesc_ctr, 0), "");
+
+ torture_assert(tctx,
+ test_GetPrinter_level(tctx, b, handle, 2, &info),
+ "");
+ torture_assert(tctx,
+ (info.info2.attributes & PRINTER_ATTRIBUTE_PUBLISHED),
+ "info2 publish flag not set");
+ torture_assert(tctx,
+ test_GetPrinter_level(tctx, b, handle, 7, &info),
+ "");
+ if (info.info7.action & DSPRINT_PENDING) {
+ torture_comment(tctx, "publish is pending\n");
+ torture_assert_int_equal(tctx,
+ info.info7.action,
+ (DSPRINT_PENDING | DSPRINT_PUBLISH),
+ "info7 publish flag not set");
+ } else {
+ struct GUID guid;
+ torture_assert_int_equal(tctx,
+ info.info7.action,
+ DSPRINT_PUBLISH,
+ "info7 publish flag not set");
+ torture_assert_ntstatus_ok(tctx,
+ GUID_from_string(info.info7.guid,
+ &guid),
+ "invalid published printer GUID");
+ }
+
+ return true;
+}
+
+static bool test_printer_set_unpublish(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ struct policy_handle *handle)
+{
+ union spoolss_PrinterInfo info;
+ struct spoolss_SetPrinterInfo7 info7;
+ struct spoolss_SetPrinterInfoCtr info_ctr;
+ struct spoolss_DevmodeContainer devmode_ctr;
+ struct sec_desc_buf secdesc_ctr;
+
+ info7.action = DSPRINT_UNPUBLISH;
+ info7.guid = "";
+
+ ZERO_STRUCT(info_ctr);
+ ZERO_STRUCT(devmode_ctr);
+ ZERO_STRUCT(secdesc_ctr);
+ info_ctr.level = 7;
+ info_ctr.info.info7 = &info7;
+
+ torture_assert(tctx,
+ test_SetPrinter(tctx, b, handle, &info_ctr,
+ &devmode_ctr, &secdesc_ctr, 0), "");
+
+ torture_assert(tctx,
+ test_GetPrinter_level(tctx, b, handle, 2, &info),
+ "");
+ torture_assert(tctx,
+ !(info.info2.attributes & PRINTER_ATTRIBUTE_PUBLISHED),
+ "info2 publish flag still set");
+ torture_assert(tctx,
+ test_GetPrinter_level(tctx, b, handle, 7, &info),
+ "");
+
+ if (info.info7.action & DSPRINT_PENDING) {
+ struct GUID guid;
+ torture_comment(tctx, "unpublish is pending\n");
+ torture_assert_int_equal(tctx,
+ info.info7.action,
+ (DSPRINT_PENDING | DSPRINT_UNPUBLISH),
+ "info7 unpublish flag not set");
+ torture_assert_ntstatus_ok(tctx,
+ GUID_from_string(info.info7.guid,
+ &guid),
+ "invalid printer GUID");
+ } else {
+ torture_assert_int_equal(tctx,
+ info.info7.action, DSPRINT_UNPUBLISH,
+ "info7 unpublish flag not set");
+ }
+
+ return true;
+}
+
+static bool test_printer_publish_toggle(struct torture_context *tctx,
+ void *private_data)
+{
+ struct torture_printer_context *t =
+ talloc_get_type_abort(private_data,
+ struct torture_printer_context);
+ struct dcerpc_pipe *p = t->spoolss_pipe;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ struct policy_handle *handle = &t->handle;
+ union spoolss_PrinterInfo info7;
+ union spoolss_PrinterInfo info2;
+
+ /* check publish status via level 7 and level 2 */
+ torture_assert(tctx, test_GetPrinter_level(tctx, b, handle, 7, &info7),
+ "");
+ torture_assert(tctx, test_GetPrinter_level(tctx, b, handle, 2, &info2),
+ "");
+
+ if (info2.info2.attributes & PRINTER_ATTRIBUTE_PUBLISHED) {
+ torture_assert_int_equal(tctx,
+ info7.info7.action, DSPRINT_PUBLISH,
+ "info7 publish flag not set");
+ torture_assert(tctx, test_printer_set_unpublish(tctx, b, handle), "");
+ torture_assert(tctx, test_printer_set_publish(tctx, b, handle), "");
+ } else {
+ torture_assert_int_equal(tctx,
+ info7.info7.action, DSPRINT_UNPUBLISH,
+ "info7 unpublish flag not set");
+ torture_assert(tctx, test_printer_set_publish(tctx, b, handle), "");
+ torture_assert(tctx, test_printer_set_unpublish(tctx, b, handle), "");
+ }
+
+ return true;
+}
+
+static bool test_driver_info_winreg(struct torture_context *tctx,
+ void *private_data)
+{
+ struct torture_printer_context *t =
+ (struct torture_printer_context *)talloc_get_type_abort(private_data, struct torture_printer_context);
+ struct dcerpc_pipe *p = t->spoolss_pipe;
+ const char *driver_name = t->added_driver ? t->driver.info8.driver_name : t->info2.drivername;
+
+ if (!t->have_driver) {
+ torture_skip(tctx, "skipping driver info winreg test as we don't have a driver");
+ }
+
+ torture_assert(tctx,
+ test_DriverInfo_winreg(tctx, p, &t->handle, t->info2.printername, driver_name, t->driver.remote.environment, 3),
+ "failed to test driver info winreg");
+
+ return true;
+}
+
+static bool test_print_job_enum(struct torture_context *tctx,
+ void *private_data)
+{
+ struct torture_printer_context *t =
+ (struct torture_printer_context *)talloc_get_type_abort(private_data, struct torture_printer_context);
+ struct dcerpc_pipe *p = t->spoolss_pipe;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ bool ret = true;
+ uint32_t num_jobs = 8;
+ uint32_t *job_ids;
+ int i;
+ union spoolss_JobInfo *info = NULL;
+ uint32_t count;
+
+ torture_assert(tctx,
+ test_PausePrinter(tctx, b, &t->handle),
+ "failed to pause printer");
+
+ /* purge in case of any jobs from previous tests */
+ torture_assert(tctx,
+ test_printer_purge(tctx, b, &t->handle),
+ "failed to purge printer");
+
+ /* enum before jobs, valid level */
+ torture_assert(tctx,
+ test_EnumJobs_args(tctx, b, &t->handle, 1, WERR_OK,
+ &count, &info),
+ "EnumJobs with valid level");
+ torture_assert_int_equal(tctx, count, 0, "EnumJobs count");
+ torture_assert(tctx,
+ test_EnumJobs_args(tctx, b, &t->handle, 2, WERR_OK,
+ &count, &info),
+ "EnumJobs with valid level");
+ torture_assert_int_equal(tctx, count, 0, "EnumJobs count");
+ /* enum before jobs, invalid level - expect failure */
+ torture_assert(tctx,
+ test_EnumJobs_args(tctx, b, &t->handle, 100,
+ WERR_INVALID_LEVEL,
+ &count, &info),
+ "EnumJobs with invalid level");
+
+ job_ids = talloc_zero_array(tctx, uint32_t, num_jobs);
+
+ for (i = 0; i < num_jobs; i++) {
+ ret = test_DoPrintTest_add_one_job(tctx, b, &t->handle,
+ "TorturePrintJob",
+ &job_ids[i]);
+ torture_assert(tctx, ret, "failed to add print job");
+ }
+
+ /* enum after jobs, valid level */
+ torture_assert(tctx,
+ test_EnumJobs_args(tctx, b, &t->handle, 1, WERR_OK,
+ &count, &info),
+ "EnumJobs with valid level");
+ torture_assert_int_equal(tctx, count, num_jobs, "EnumJobs count");
+ torture_assert(tctx,
+ test_EnumJobs_args(tctx, b, &t->handle, 2, WERR_OK,
+ &count, &info),
+ "EnumJobs with valid level");
+ torture_assert_int_equal(tctx, count, num_jobs, "EnumJobs count");
+ /* enum after jobs, invalid level - expect failure */
+ torture_assert(tctx,
+ test_EnumJobs_args(tctx, b, &t->handle, 100,
+ WERR_INVALID_LEVEL,
+ &count, &info),
+ "EnumJobs with invalid level");
+
+ for (i = 0; i < num_jobs; i++) {
+ test_SetJob(tctx, b, &t->handle, job_ids[i], NULL,
+ SPOOLSS_JOB_CONTROL_DELETE);
+ }
+
+ torture_assert(tctx,
+ test_ResumePrinter(tctx, b, &t->handle),
+ "failed to resume printer");
+
+ return true;
+}
+
+void torture_tcase_printer(struct torture_tcase *tcase)
+{
+ torture_tcase_add_simple_test(tcase, "openprinter", test_openprinter_wrap);
+ torture_tcase_add_simple_test(tcase, "csetprinter", test_csetprinter);
+ torture_tcase_add_simple_test(tcase, "print_test", test_print_test);
+ torture_tcase_add_simple_test(tcase, "print_test_extended", test_print_test_extended);
+ torture_tcase_add_simple_test(tcase, "print_test_smbd", test_print_test_smbd);
+ torture_tcase_add_simple_test(tcase, "print_test_properties", test_print_test_properties);
+ torture_tcase_add_simple_test(tcase, "print_test_purge", test_print_test_purge);
+ torture_tcase_add_simple_test(tcase, "printer_info", test_printer_info);
+ torture_tcase_add_simple_test(tcase, "sd", test_printer_sd);
+ torture_tcase_add_simple_test(tcase, "dm", test_printer_dm);
+ torture_tcase_add_simple_test(tcase, "printer_info_winreg", test_printer_info_winreg);
+ torture_tcase_add_simple_test(tcase, "change_id", test_printer_change_id);
+ torture_tcase_add_simple_test(tcase, "keys", test_printer_keys);
+ torture_tcase_add_simple_test(tcase, "printerdata_consistency", test_printer_data_consistency);
+ torture_tcase_add_simple_test(tcase, "printerdata_keys", test_printer_data_keys);
+ torture_tcase_add_simple_test(tcase, "printerdata_values", test_printer_data_values);
+ torture_tcase_add_simple_test(tcase, "printerdata_set", test_printer_data_set);
+ torture_tcase_add_simple_test(tcase, "printerdata_winreg", test_printer_data_winreg);
+ torture_tcase_add_simple_test(tcase, "printerdata_dsspooler", test_printer_data_dsspooler);
+ torture_tcase_add_simple_test(tcase, "driver_info_winreg", test_driver_info_winreg);
+ torture_tcase_add_simple_test(tcase, "printer_rename", test_printer_rename);
+ torture_tcase_add_simple_test(tcase, "printer_ic", test_printer_ic);
+ torture_tcase_add_simple_test(tcase, "bidi", test_printer_bidi);
+ torture_tcase_add_simple_test(tcase, "publish_toggle",
+ test_printer_publish_toggle);
+ torture_tcase_add_simple_test(tcase, "print_job_enum", test_print_job_enum);
+}
+
+struct torture_suite *torture_rpc_spoolss_printer(TALLOC_CTX *mem_ctx)
+{
+ struct torture_suite *suite = torture_suite_create(mem_ctx, "printer");
+ struct torture_tcase *tcase;
+
+ tcase = torture_suite_add_tcase(suite, "addprinter");
+
+ torture_tcase_set_fixture(tcase,
+ torture_rpc_spoolss_printer_setup,
+ torture_rpc_spoolss_printer_teardown);
+
+ torture_tcase_printer(tcase);
+
+ tcase = torture_suite_add_tcase(suite, "addprinterex");
+
+ torture_tcase_set_fixture(tcase,
+ torture_rpc_spoolss_printerex_setup,
+ torture_rpc_spoolss_printer_teardown);
+
+ torture_tcase_printer(tcase);
+
+ tcase = torture_suite_add_tcase(suite, "addprinterwkn");
+
+ torture_tcase_set_fixture(tcase,
+ torture_rpc_spoolss_printerwkn_setup,
+ torture_rpc_spoolss_printer_teardown);
+
+ tcase = torture_suite_add_tcase(suite, "addprinterexwkn");
+
+ torture_tcase_set_fixture(tcase,
+ torture_rpc_spoolss_printerexwkn_setup,
+ torture_rpc_spoolss_printer_teardown);
+
+#if 0
+ /* test is not correct */
+ tcase = torture_suite_add_tcase(suite, "addprinterdm");
+
+ torture_tcase_set_fixture(tcase,
+ torture_rpc_spoolss_printerdm_setup,
+ torture_rpc_spoolss_printer_teardown);
+
+ torture_tcase_printer(tcase);
+#endif
+ return suite;
+}
+
+struct torture_suite *torture_rpc_spoolss(TALLOC_CTX *mem_ctx)
+{
+ struct torture_suite *suite = torture_suite_create(mem_ctx, "spoolss");
+ struct torture_tcase *tcase = torture_suite_add_tcase(suite, "printserver");
+
+ torture_tcase_set_fixture(tcase,
+ torture_rpc_spoolss_setup,
+ torture_rpc_spoolss_teardown);
+
+ torture_tcase_add_simple_test(tcase, "openprinter_badnamelist", test_OpenPrinter_badname_list);
+ torture_tcase_add_simple_test(tcase, "printer_data_list", test_GetPrinterData_list);
torture_tcase_add_simple_test(tcase, "enum_forms", test_PrintServer_EnumForms);
torture_tcase_add_simple_test(tcase, "forms", test_PrintServer_Forms);
torture_tcase_add_simple_test(tcase, "forms_winreg", test_PrintServer_Forms_Winreg);
torture_tcase_add_simple_test(tcase, "enum_monitors", test_EnumMonitors);
torture_tcase_add_simple_test(tcase, "enum_print_processors", test_EnumPrintProcessors);
torture_tcase_add_simple_test(tcase, "print_processors_winreg", test_print_processors_winreg);
+ torture_tcase_add_simple_test(tcase, "add_processor", test_add_print_processor);
torture_tcase_add_simple_test(tcase, "enum_printprocdata", test_EnumPrintProcDataTypes);
torture_tcase_add_simple_test(tcase, "enum_printers", test_EnumPrinters);
torture_tcase_add_simple_test(tcase, "enum_ports_old", test_EnumPorts_old);
}
torture_assert_nttime_equal(tctx, info.info6.driver_date, info6.driver_date, "driverdate mismatch");
+ torture_assert_u64_equal(tctx, info.info6.driver_version, info6.driver_version, "driverversion mismatch");
return true;
}
}
torture_assert_nttime_equal(tctx, info.info8.driver_date, r->driver_date, "driverdate mismatch");
+ torture_assert_u64_equal(tctx, info.info8.driver_version, r->driver_version, "driverversion mismatch");
return true;
}
buf = talloc_array(tctx, uint8_t, maxwrite);
if (!buf) {
+ x_fclose(f);
return false;
}
return true;
}
+static bool check_printer_driver_file(struct torture_context *tctx,
+ struct smbcli_state *cli,
+ struct torture_driver_context *d,
+ const char *file_name)
+{
+ const char *remote_arch_dir = driver_directory_dir(d->remote.driver_directory);
+ const char *remote_name = talloc_asprintf(tctx, "%s\\%d\\%s",
+ remote_arch_dir,
+ d->info8.version,
+ file_name);
+ int fnum;
+
+ torture_assert(tctx, (file_name && strlen(file_name) != 0), "invalid filename");
+
+ torture_comment(tctx, "checking for driver file at %s\n", remote_name);
+
+ fnum = smbcli_open(cli->tree, remote_name, O_RDONLY, DENY_NONE);
+ if (fnum == -1) {
+ return false;
+ }
+
+ torture_assert_ntstatus_ok(tctx,
+ smbcli_close(cli->tree, fnum),
+ "failed to close driver file");
+
+ return true;
+}
+
+static bool check_printer_driver_files(struct torture_context *tctx,
+ const char *server_name,
+ struct torture_driver_context *d,
+ bool expect_exist)
+{
+ struct smbcli_state *cli;
+ const char *share_name = driver_directory_share(tctx, d->remote.driver_directory);
+ int i;
+
+ torture_assert(tctx,
+ connect_printer_driver_share(tctx, server_name, share_name, &cli),
+ "failed to connect to driver share");
+
+ torture_comment(tctx, "checking %sexistent driver files at \\\\%s\\%s\n",
+ (expect_exist ? "": "non-"),
+ server_name, share_name);
+
+ if (d->info8.driver_path && d->info8.driver_path[0]) {
+ torture_assert(tctx,
+ check_printer_driver_file(tctx, cli, d, d->info8.driver_path) == expect_exist,
+ "failed driver_path check");
+ }
+ if (d->info8.data_file && d->info8.data_file[0]) {
+ torture_assert(tctx,
+ check_printer_driver_file(tctx, cli, d, d->info8.data_file) == expect_exist,
+ "failed data_file check");
+ }
+ if (d->info8.config_file && d->info8.config_file[0]) {
+ torture_assert(tctx,
+ check_printer_driver_file(tctx, cli, d, d->info8.config_file) == expect_exist,
+ "failed config_file check");
+ }
+ if (d->info8.help_file && d->info8.help_file[0]) {
+ torture_assert(tctx,
+ check_printer_driver_file(tctx, cli, d, d->info8.help_file) == expect_exist,
+ "failed help_file check");
+ }
+ if (d->info8.dependent_files) {
+ for (i=0; d->info8.dependent_files->string && d->info8.dependent_files->string[i] != NULL; i++) {
+ torture_assert(tctx,
+ check_printer_driver_file(tctx, cli, d, d->info8.dependent_files->string[i]) == expect_exist,
+ "failed dependent_files check");
+ }
+ }
+
+ talloc_free(cli);
+
+ return true;
+}
+
static bool remove_printer_driver_file(struct torture_context *tctx,
struct smbcli_state *cli,
struct torture_driver_context *d,
upload_printer_driver(tctx, dcerpc_server_name(p), d),
"failed to upload printer driver");
- info8.version = d->info8.version;
- info8.driver_name = d->info8.driver_name;
- info8.architecture = d->local.environment;
- info8.driver_path = d->info8.driver_path;
- info8.data_file = d->info8.data_file;
- info8.config_file = d->info8.config_file;
+ info8 = d->info8;
+ if (d->info8.dependent_files) {
+ info8.dependent_files = talloc_zero(tctx, struct spoolss_StringArray);
+ if (d->info8.dependent_files->string) {
+ for (i=0; d->info8.dependent_files->string[i] != NULL; i++) {
+ }
+ info8.dependent_files->string = talloc_zero_array(info8.dependent_files, const char *, i+1);
+ for (i=0; d->info8.dependent_files->string[i] != NULL; i++) {
+ info8.dependent_files->string[i] = talloc_strdup(info8.dependent_files->string, d->info8.dependent_files->string[i]);
+ }
+ }
+ }
+ info8.architecture = d->local.environment;
for (i=0; i < ARRAY_SIZE(levels); i++) {
{
struct torture_driver_context *d;
+ if (!torture_setting_bool(tctx, "samba3", false)) {
+ torture_skip(tctx, "skipping adobe test which only works against samba3");
+ }
+
d = talloc_zero(tctx, struct torture_driver_context);
d->info8.version = SPOOLSS_DRIVER_VERSION_9X;
struct torture_driver_context *d;
struct timeval t = timeval_current();
- if (torture_setting_bool(tctx, "samba3", false)) {
- torture_skip(tctx, "skipping timestamps test against samba");
- }
-
d = talloc_zero(tctx, struct torture_driver_context);
d->info8.version = SPOOLSS_DRIVER_VERSION_200X;
return true;
}
+static bool test_multiple_drivers(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ struct torture_driver_context *d;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ const char *server_name_slash = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
+ int i;
+ struct spoolss_AddDriverInfo8 info8;
+ uint32_t add_flags = APD_COPY_NEW_FILES;
+ uint32_t delete_flags = 0;
+
+ d = talloc_zero(tctx, struct torture_driver_context);
+
+ d->info8.version = SPOOLSS_DRIVER_VERSION_200X;
+ d->info8.driver_path = talloc_strdup(d, "pscript5.dll");
+ d->info8.data_file = talloc_strdup(d, "cups6.ppd");
+ d->info8.config_file = talloc_strdup(d, "cupsui6.dll");
+ d->local.environment = talloc_strdup(d, "Windows NT x86");
+ d->local.driver_directory = talloc_strdup(d, "/usr/share/cups/drivers/i386");
+ d->ex = true;
+
+ torture_assert(tctx,
+ fillup_printserver_info(tctx, p, d),
+ "failed to fillup printserver info");
+
+ if (!directory_exist(d->local.driver_directory)) {
+ torture_skip(tctx, "Skipping Printer Driver test as no local driver is available");
+ }
+
+ torture_assert(tctx,
+ upload_printer_driver(tctx, dcerpc_server_name(p), d),
+ "failed to upload printer driver");
+
+ info8 = d->info8;
+ info8.architecture = d->local.environment;
+
+ for (i=0; i < 3; i++) {
+ info8.driver_name = talloc_asprintf(d, "torture_test_driver_%d", i);
+
+ torture_assert(tctx,
+ test_AddPrinterDriver_args_level_3(tctx, b, server_name_slash, &info8, add_flags, true, NULL),
+ "failed to add driver");
+ }
+
+ torture_assert(tctx,
+ test_DeletePrinterDriverEx(tctx, b, server_name_slash, "torture_test_driver_0", info8.architecture, delete_flags, info8.version),
+ "failed to delete driver");
+
+ torture_assert(tctx,
+ test_EnumPrinterDrivers_findone(tctx, b, server_name_slash, info8.architecture, 3, "torture_test_driver_1", NULL),
+ "torture_test_driver_1 no longer on the server");
+
+ torture_assert(tctx,
+ test_EnumPrinterDrivers_findone(tctx, b, server_name_slash, info8.architecture, 3, "torture_test_driver_2", NULL),
+ "torture_test_driver_2 no longer on the server");
+
+ torture_assert(tctx,
+ test_DeletePrinterDriverEx(tctx, b, server_name_slash, "torture_test_driver_1", info8.architecture, delete_flags, info8.version),
+ "failed to delete driver");
+
+ torture_assert(tctx,
+ test_EnumPrinterDrivers_findone(tctx, b, server_name_slash, info8.architecture, 3, "torture_test_driver_2", NULL),
+ "torture_test_driver_2 no longer on the server");
+
+ torture_assert(tctx,
+ test_DeletePrinterDriverEx(tctx, b, server_name_slash, "torture_test_driver_2", info8.architecture, delete_flags, info8.version),
+ "failed to delete driver");
+
+ torture_assert(tctx,
+ remove_printer_driver(tctx, dcerpc_server_name(p), d),
+ "failed to remove printer driver");
+
+ return true;
+}
+
+static bool test_del_driver_all_files(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ struct torture_driver_context *d;
+ struct spoolss_StringArray *a;
+ uint32_t add_flags = APD_COPY_NEW_FILES;
+ uint32_t delete_flags = DPD_DELETE_ALL_FILES;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ const char *server_name_slash = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
+
+ d = talloc_zero(tctx, struct torture_driver_context);
+
+ d->ex = true;
+ d->info8.version = SPOOLSS_DRIVER_VERSION_200X;
+ d->info8.driver_name = TORTURE_DRIVER_DELETER;
+ d->info8.architecture = NULL;
+ d->info8.driver_path = talloc_strdup(d, "pscript5.dll");
+ d->info8.data_file = talloc_strdup(d, "cups6.ppd");
+ d->info8.config_file = talloc_strdup(d, "cupsui6.dll");
+ d->info8.help_file = talloc_strdup(d, "pscript.hlp");
+ d->local.environment = talloc_strdup(d, SPOOLSS_ARCHITECTURE_x64);
+ d->local.driver_directory = talloc_strdup(d, "/usr/share/cups/drivers/x64");
+
+ a = talloc_zero(d, struct spoolss_StringArray);
+ a->string = talloc_zero_array(a, const char *, 3);
+ a->string[0] = talloc_strdup(a->string, "cups6.inf");
+ a->string[1] = talloc_strdup(a->string, "cups6.ini");
+
+ d->info8.dependent_files = a;
+ d->info8.architecture = d->local.environment;
+
+ torture_assert(tctx,
+ fillup_printserver_info(tctx, p, d),
+ "failed to fillup printserver info");
+
+ if (!directory_exist(d->local.driver_directory)) {
+ torture_skip(tctx, "Skipping Printer Driver test as no local driver is available");
+ }
+
+ torture_assert(tctx,
+ upload_printer_driver(tctx, dcerpc_server_name(p), d),
+ "failed to upload printer driver");
+
+ torture_assert(tctx,
+ test_AddPrinterDriver_args_level_3(tctx, b, server_name_slash, &d->info8, add_flags, true, NULL),
+ "failed to add driver");
+
+ torture_assert(tctx,
+ test_DeletePrinterDriverEx(tctx, b, server_name_slash,
+ d->info8.driver_name,
+ d->local.environment,
+ delete_flags,
+ d->info8.version),
+ "failed to delete driver");
+
+ torture_assert(tctx,
+ check_printer_driver_files(tctx, dcerpc_server_name(p), d, false),
+ "printer driver file check failed");
+
+ talloc_free(d);
+ return true;
+}
+
+static bool test_del_driver_unused_files(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ struct torture_driver_context *d1;
+ struct torture_driver_context *d2;
+ uint32_t add_flags = APD_COPY_NEW_FILES;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ const char *server_name_slash = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
+
+ d1 = talloc_zero(tctx, struct torture_driver_context);
+ d1->ex = true;
+ d1->info8.version = SPOOLSS_DRIVER_VERSION_200X;
+ d1->info8.driver_name = TORTURE_DRIVER_DELETER;
+ d1->info8.architecture = NULL;
+ d1->info8.driver_path = talloc_strdup(d1, "pscript5.dll");
+ d1->info8.data_file = talloc_strdup(d1, "cups6.ppd");
+ d1->info8.config_file = talloc_strdup(d1, "cupsui6.dll");
+ d1->info8.help_file = talloc_strdup(d1, "pscript.hlp");
+ d1->local.environment = talloc_strdup(d1, SPOOLSS_ARCHITECTURE_x64);
+ d1->local.driver_directory = talloc_strdup(d1, "/usr/share/cups/drivers/x64");
+ d1->info8.architecture = d1->local.environment;
+
+ d2 = talloc_zero(tctx, struct torture_driver_context);
+ d2->ex = true;
+ d2->info8.version = SPOOLSS_DRIVER_VERSION_200X;
+ d2->info8.driver_name = TORTURE_DRIVER_DELETERIN;
+ d2->info8.architecture = NULL;
+ d2->info8.driver_path = talloc_strdup(d2, "pscript5.dll"); /* overlapping */
+ d2->info8.data_file = talloc_strdup(d2, "cupsps6.dll");
+ d2->info8.config_file = talloc_strdup(d2, "cups6.ini");
+ d2->info8.help_file = talloc_strdup(d2, "pscript.hlp"); /* overlapping */
+ d2->local.environment = talloc_strdup(d2, SPOOLSS_ARCHITECTURE_x64);
+ d2->local.driver_directory = talloc_strdup(d2, "/usr/share/cups/drivers/x64");
+ d2->info8.architecture = d2->local.environment;
+
+ torture_assert(tctx,
+ fillup_printserver_info(tctx, p, d1),
+ "failed to fillup printserver info");
+ torture_assert(tctx,
+ fillup_printserver_info(tctx, p, d2),
+ "failed to fillup printserver info");
+
+ if (!directory_exist(d1->local.driver_directory)) {
+ torture_skip(tctx, "Skipping Printer Driver test as no local driver is available");
+ }
+
+ torture_assert(tctx,
+ upload_printer_driver(tctx, dcerpc_server_name(p), d1),
+ "failed to upload printer driver");
+ torture_assert(tctx,
+ test_AddPrinterDriver_args_level_3(tctx, b, server_name_slash, &d1->info8, add_flags, true, NULL),
+ "failed to add driver");
+
+ torture_assert(tctx,
+ upload_printer_driver(tctx, dcerpc_server_name(p), d2),
+ "failed to upload printer driver");
+ torture_assert(tctx,
+ test_AddPrinterDriver_args_level_3(tctx, b, server_name_slash, &d2->info8, add_flags, true, NULL),
+ "failed to add driver");
+
+ /* some files are in use by a separate driver, should fail */
+ torture_assert(tctx,
+ test_DeletePrinterDriverEx_exp(tctx, b, server_name_slash,
+ d1->info8.driver_name,
+ d1->local.environment,
+ DPD_DELETE_ALL_FILES,
+ d1->info8.version,
+ WERR_PRINTER_DRIVER_IN_USE),
+ "invalid delete driver response");
+
+ /* should only delete files not in use by other driver */
+ torture_assert(tctx,
+ test_DeletePrinterDriverEx_exp(tctx, b, server_name_slash,
+ d1->info8.driver_name,
+ d1->local.environment,
+ DPD_DELETE_UNUSED_FILES,
+ d1->info8.version,
+ WERR_OK),
+ "failed to delete driver (unused files)");
+
+ /* check non-overlapping were deleted */
+ d1->info8.driver_path = NULL;
+ d1->info8.help_file = NULL;
+ torture_assert(tctx,
+ check_printer_driver_files(tctx, dcerpc_server_name(p), d1, false),
+ "printer driver file check failed");
+ /* d2 files should be uneffected */
+ torture_assert(tctx,
+ check_printer_driver_files(tctx, dcerpc_server_name(p), d2, true),
+ "printer driver file check failed");
+
+ torture_assert(tctx,
+ test_DeletePrinterDriverEx_exp(tctx, b, server_name_slash,
+ d2->info8.driver_name,
+ d2->local.environment,
+ DPD_DELETE_ALL_FILES,
+ d2->info8.version,
+ WERR_OK),
+ "failed to delete driver");
+
+ torture_assert(tctx,
+ check_printer_driver_files(tctx, dcerpc_server_name(p), d2, false),
+ "printer driver file check failed");
+
+ talloc_free(d1);
+ talloc_free(d2);
+ return true;
+}
+
struct torture_suite *torture_rpc_spoolss_driver(TALLOC_CTX *mem_ctx)
{
struct torture_suite *suite = torture_suite_create(mem_ctx, "spoolss.driver");
torture_rpc_tcase_add_test(tcase, "add_driver_timestamps", test_add_driver_timestamps);
+ torture_rpc_tcase_add_test(tcase, "multiple_drivers", test_multiple_drivers);
+
+ torture_rpc_tcase_add_test(tcase, "del_driver_all_files", test_del_driver_all_files);
+
+ torture_rpc_tcase_add_test(tcase, "del_driver_unused_files", test_del_driver_unused_files);
+
return suite;
}