#include "librpc/gen_ndr/ndr_winreg_c.h"
#include "librpc/gen_ndr/ndr_security.h"
#include "libcli/security/security.h"
-#include "torture/rpc/rpc.h"
+#include "torture/rpc/torture_rpc.h"
#include "param/param.h"
#include "lib/registry/registry.h"
+#include "libcli/libcli.h"
+#include "libcli/raw/raw_proto.h"
+#include "libcli/resolve/resolve.h"
+#include "lib/cmdline/popt_common.h"
+#include "system/filesys.h"
#define TORTURE_WELLKNOWN_PRINTER "torture_wkn_printer"
#define TORTURE_PRINTER "torture_printer"
#define TORTURE_WELLKNOWN_PRINTER_EX "torture_wkn_printer_ex"
#define TORTURE_PRINTER_EX "torture_printer_ex"
+#define TORTURE_DRIVER "torture_driver"
+#define TORTURE_DRIVER_EX "torture_driver_ex"
-#define TOP_LEVEL_PRINTER_KEY "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Print\\Printers"
+#define TOP_LEVEL_PRINT_KEY "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Print"
+#define TOP_LEVEL_PRINT_PRINTERS_KEY TOP_LEVEL_PRINT_KEY "\\Printers"
+#define TOP_LEVEL_CONTROL_KEY "SYSTEM\\CurrentControlSet\\Control\\Print"
+#define TOP_LEVEL_CONTROL_FORMS_KEY TOP_LEVEL_CONTROL_KEY "\\Forms"
+#define TOP_LEVEL_CONTROL_PRINTERS_KEY TOP_LEVEL_CONTROL_KEY "\\Printers"
+#define TOP_LEVEL_CONTROL_ENVIRONMENTS_KEY TOP_LEVEL_CONTROL_KEY "\\Environments"
struct test_spoolss_context {
/* print server handle */
union spoolss_PrinterInfo *printers[6];
};
+struct torture_driver_context {
+ struct {
+ const char *driver_directory;
+ const char *environment;
+ } local;
+ struct {
+ const char *driver_directory;
+ const char *environment;
+ } remote;
+ struct spoolss_AddDriverInfo8 info8;
+ bool ex;
+};
+
+struct torture_printer_context {
+ struct spoolss_SetPrinterInfo2 info2;
+ struct torture_driver_context driver;
+ bool ex;
+ bool wellknown;
+ bool added_driver;
+ bool have_driver;
+};
+
+static bool upload_printer_driver(struct torture_context *tctx,
+ const char *server_name,
+ struct torture_driver_context *d);
+static bool remove_printer_driver(struct torture_context *tctx,
+ const char *server_name,
+ struct torture_driver_context *d);
+static bool fillup_printserver_info(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ struct torture_driver_context *d);
+static bool test_AddPrinterDriver_args_level_3(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ const char *server_name,
+ struct spoolss_AddDriverInfo8 *r,
+ uint32_t flags,
+ bool ex);
+
#define COMPARE_STRING(tctx, c,r,e) \
torture_assert_str_equal(tctx, c.e, r.e, "invalid value")
torture_assert_werr_equal(tctx, r.out.result, WERR_INSUFFICIENT_BUFFER,
"EnumPorts unexpected return code");
- blob = data_blob_talloc(ctx, NULL, needed);
- data_blob_clear(&blob);
+ blob = data_blob_talloc_zero(ctx, needed);
r.in.buffer = &blob;
r.in.offered = needed;
static bool test_GetPrintProcessorDirectory(struct torture_context *tctx,
struct dcerpc_pipe *p,
- struct test_spoolss_context *ctx,
const char *environment)
{
NTSTATUS status;
.server = ""
},{
.level = 1,
- .server = talloc_asprintf(ctx, "\\\\%s", dcerpc_server_name(p))
+ .server = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p))
},{
.level = 1024,
- .server = talloc_asprintf(ctx, "\\\\%s", dcerpc_server_name(p))
+ .server = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p))
}
};
int i;
torture_comment(tctx, "Testing GetPrintProcessorDirectory level %u\n", r.in.level);
- status = dcerpc_spoolss_GetPrintProcessorDirectory_r(b, ctx, &r);
+ status = dcerpc_spoolss_GetPrintProcessorDirectory_r(b, tctx, &r);
torture_assert_ntstatus_ok(tctx, status,
"dcerpc_spoolss_GetPrintProcessorDirectory failed");
torture_assert_werr_equal(tctx, r.out.result, WERR_INSUFFICIENT_BUFFER,
"GetPrintProcessorDirectory unexpected return code");
- blob = data_blob_talloc(ctx, NULL, needed);
- data_blob_clear(&blob);
+ blob = data_blob_talloc_zero(tctx, needed);
r.in.buffer = &blob;
r.in.offered = needed;
- status = dcerpc_spoolss_GetPrintProcessorDirectory_r(b, ctx, &r);
+ status = dcerpc_spoolss_GetPrintProcessorDirectory_r(b, tctx, &r);
torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_GetPrintProcessorDirectory failed");
torture_assert_werr_ok(tctx, r.out.result, "GetPrintProcessorDirectory failed");
static bool test_GetPrinterDriverDirectory(struct torture_context *tctx,
struct dcerpc_pipe *p,
- struct test_spoolss_context *ctx,
const char *environment)
{
NTSTATUS status;
.server = ""
},{
.level = 1,
- .server = talloc_asprintf(ctx, "\\\\%s", dcerpc_server_name(p))
+ .server = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p))
},{
.level = 1024,
- .server = talloc_asprintf(ctx, "\\\\%s", dcerpc_server_name(p))
+ .server = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p))
}
};
int i;
torture_comment(tctx, "Testing GetPrinterDriverDirectory level %u\n", r.in.level);
- status = dcerpc_spoolss_GetPrinterDriverDirectory_r(b, ctx, &r);
+ status = dcerpc_spoolss_GetPrinterDriverDirectory_r(b, tctx, &r);
torture_assert_ntstatus_ok(tctx, status,
"dcerpc_spoolss_GetPrinterDriverDirectory failed");
torture_assert_werr_equal(tctx, r.out.result, WERR_INSUFFICIENT_BUFFER,
"GetPrinterDriverDirectory unexpected return code");
- blob = data_blob_talloc(ctx, NULL, needed);
- data_blob_clear(&blob);
+ blob = data_blob_talloc_zero(tctx, needed);
r.in.buffer = &blob;
r.in.offered = needed;
- status = dcerpc_spoolss_GetPrinterDriverDirectory_r(b, ctx, &r);
+ status = dcerpc_spoolss_GetPrinterDriverDirectory_r(b, tctx, &r);
torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_GetPrinterDriverDirectory failed");
torture_assert_werr_ok(tctx, r.out.result, "GetPrinterDriverDirectory failed");
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)
+{
+ struct spoolss_EnumPrinterDrivers r;
+ uint32_t needed;
+ uint32_t count;
+ union spoolss_DriverInfo *info;
+
+ r.in.server = server_name;
+ r.in.environment = environment;
+ r.in.level = level;
+ r.in.buffer = NULL;
+ r.in.offered = 0;
+ 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_assert_ntstatus_ok(tctx,
+ dcerpc_spoolss_EnumPrinterDrivers_r(b, tctx, &r),
+ "EnumPrinterDrivers failed");
+ 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_EnumPrinterDrivers_r(b, tctx, &r),
+ "EnumPrinterDrivers failed");
+ }
+
+ torture_assert_werr_ok(tctx, r.out.result,
+ "EnumPrinterDrivers failed");
+
+ if (count_p) {
+ *count_p = count;
+ }
+ if (info_p) {
+ *info_p = info;
+ }
+
+ CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumPrinterDrivers, info, r.in.level, count, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
+
+ return true;
+
+}
+
+static bool test_EnumPrinterDrivers_findone(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ const char *server_name,
+ const char *environment,
+ uint32_t level,
+ const char *driver_name)
+{
+ uint32_t count;
+ union spoolss_DriverInfo *info;
+ int i;
+
+ torture_assert(tctx,
+ test_EnumPrinterDrivers_args(tctx, b, server_name, environment, level, &count, &info),
+ "failed to enumerate printer drivers");
+
+ for (i=0; i < count; i++) {
+ const char *driver_name_ret;
+ switch (level) {
+ case 1:
+ driver_name_ret = info[i].info1.driver_name;
+ break;
+ case 2:
+ driver_name_ret = info[i].info2.driver_name;
+ break;
+ case 3:
+ driver_name_ret = info[i].info3.driver_name;
+ break;
+ case 4:
+ driver_name_ret = info[i].info4.driver_name;
+ break;
+ case 5:
+ driver_name_ret = info[i].info5.driver_name;
+ break;
+ case 6:
+ driver_name_ret = info[i].info6.driver_name;
+ break;
+ case 7:
+ driver_name_ret = info[i].info7.driver_name;
+ break;
+ case 8:
+ driver_name_ret = info[i].info8.driver_name;
+ break;
+ default:
+ break;
+ }
+ if (strequal(driver_name, driver_name_ret)) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
static bool test_EnumPrinterDrivers(struct torture_context *tctx,
struct dcerpc_pipe *p,
struct test_spoolss_context *ctx,
const char *architecture)
{
- NTSTATUS status;
struct dcerpc_binding_handle *b = p->binding_handle;
- struct spoolss_EnumPrinterDrivers r;
uint16_t levels[] = { 1, 2, 3, 4, 5, 6, 8 };
int i, j;
+ /* FIXME: gd, come back and fix "" as server, and handle
+ * priority of returned error codes in torture test and samba 3
+ * server */
+ const char *server_name = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
+
for (i=0;i<ARRAY_SIZE(levels);i++) {
int level = levels[i];
- DATA_BLOB blob;
- uint32_t needed;
uint32_t count;
union spoolss_DriverInfo *info;
- /* FIXME: gd, come back and fix "" as server, and handle
- * priority of returned error codes in torture test and samba 3
- * server */
-
- r.in.server = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
- r.in.environment = architecture;
- r.in.level = level;
- r.in.buffer = NULL;
- r.in.offered = 0;
- r.out.needed = &needed;
- r.out.count = &count;
- r.out.info = &info;
-
- torture_comment(tctx, "Testing EnumPrinterDrivers level %u (%s)\n", r.in.level, r.in.environment);
-
- status = dcerpc_spoolss_EnumPrinterDrivers_r(b, ctx, &r);
- torture_assert_ntstatus_ok(tctx, status,
- "dcerpc_spoolss_EnumPrinterDrivers failed");
- if (W_ERROR_IS_OK(r.out.result)) {
- /* TODO: do some more checks here */
- continue;
- }
- if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
- blob = data_blob_talloc(ctx, NULL, needed);
- data_blob_clear(&blob);
- r.in.buffer = &blob;
- r.in.offered = needed;
-
- status = dcerpc_spoolss_EnumPrinterDrivers_r(b, ctx, &r);
- torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EnumPrinterDrivers failed");
- }
-
- torture_assert_werr_ok(tctx, r.out.result, "EnumPrinterDrivers failed");
-
- CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumPrinterDrivers, info, r.in.level, count, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
+ torture_assert(tctx,
+ test_EnumPrinterDrivers_args(tctx, b, server_name, architecture, level, &count, &info),
+ "failed to enumerate drivers");
ctx->driver_count[level] = count;
ctx->drivers[level] = info;
torture_assert_werr_equal(tctx, r.out.result, WERR_INSUFFICIENT_BUFFER,
"EnumMonitors failed");
- blob = data_blob_talloc(ctx, NULL, needed);
- data_blob_clear(&blob);
+ blob = data_blob_talloc_zero(ctx, needed);
r.in.buffer = &blob;
r.in.offered = needed;
torture_assert_werr_equal(tctx, r.out.result, WERR_INSUFFICIENT_BUFFER,
"EnumPrintProcessors unexpected return code");
- blob = data_blob_talloc(ctx, NULL, needed);
- data_blob_clear(&blob);
+ blob = data_blob_talloc_zero(ctx, needed);
r.in.buffer = &blob;
r.in.offered = needed;
}
static bool test_EnumPrintProcDataTypes(struct torture_context *tctx,
- struct dcerpc_binding_handle *b,
- struct test_spoolss_context *ctx)
+ struct dcerpc_binding_handle *b)
{
NTSTATUS status;
struct spoolss_EnumPrintProcDataTypes r;
torture_comment(tctx, "Testing EnumPrintProcDataTypes level %u\n", r.in.level);
- status = dcerpc_spoolss_EnumPrintProcDataTypes_r(b, ctx, &r);
+ status = dcerpc_spoolss_EnumPrintProcDataTypes_r(b, tctx, &r);
torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EnumPrintProcDataType failed");
if (W_ERROR_IS_OK(r.out.result)) {
/* TODO: do some more checks here */
torture_assert_werr_equal(tctx, r.out.result, WERR_INSUFFICIENT_BUFFER,
"EnumPrintProcDataTypes unexpected return code");
- blob = data_blob_talloc(ctx, NULL, needed);
- data_blob_clear(&blob);
+ blob = data_blob_talloc_zero(tctx, needed);
r.in.buffer = &blob;
r.in.offered = needed;
- status = dcerpc_spoolss_EnumPrintProcDataTypes_r(b, ctx, &r);
+ status = dcerpc_spoolss_EnumPrintProcDataTypes_r(b, tctx, &r);
torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EnumPrintProcDataTypes failed");
torture_assert_werr_ok(tctx, r.out.result, "EnumPrintProcDataTypes failed");
torture_assert_werr_equal(tctx, r.out.result, WERR_INSUFFICIENT_BUFFER,
"EnumPrinters unexpected return code");
- blob = data_blob_talloc(ctx, NULL, needed);
- data_blob_clear(&blob);
+ blob = data_blob_talloc_zero(ctx, needed);
r.in.buffer = &blob;
r.in.offered = needed;
"GetPrinter failed");
if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
- DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed);
- data_blob_clear(&blob);
+ DATA_BLOB blob = data_blob_talloc_zero(tctx, needed);
r.in.buffer = &blob;
r.in.offered = needed;
break; \
}\
if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {\
- DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed); \
- data_blob_clear(&blob); \
+ DATA_BLOB blob = data_blob_talloc_zero(tctx, needed); \
r.in.buffer = &blob; \
r.in.offered = needed; \
}\
return true;
}
-static bool test_GetForm(struct torture_context *tctx,
- struct dcerpc_binding_handle *b,
- struct policy_handle *handle,
- const char *form_name,
- uint32_t level)
+static bool test_GetForm_args(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ struct policy_handle *handle,
+ const char *form_name,
+ uint32_t level,
+ union spoolss_FormInfo *info_p)
{
NTSTATUS status;
struct spoolss_GetForm r;
r.in.offered = 0;
r.out.needed = &needed;
- torture_comment(tctx, "Testing GetForm level %d\n", r.in.level);
+ torture_comment(tctx, "Testing GetForm(%s) level %d\n", form_name, r.in.level);
status = dcerpc_spoolss_GetForm_r(b, tctx, &r);
torture_assert_ntstatus_ok(tctx, status, "GetForm failed");
if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
- DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed);
- data_blob_clear(&blob);
+ DATA_BLOB blob = data_blob_talloc_zero(tctx, needed);
r.in.buffer = &blob;
r.in.offered = needed;
status = dcerpc_spoolss_GetForm_r(b, tctx, &r);
CHECK_NEEDED_SIZE_LEVEL(spoolss_FormInfo, r.out.info, r.in.level, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
+ if (info_p) {
+ *info_p = *r.out.info;
+ }
+
return true;
}
+static bool test_GetForm(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ struct policy_handle *handle,
+ const char *form_name,
+ uint32_t level)
+{
+ return test_GetForm_args(tctx, b, handle, form_name, level, NULL);
+}
+
static bool test_EnumForms(struct torture_context *tctx,
struct dcerpc_binding_handle *b,
- struct policy_handle *handle, bool print_server)
+ struct policy_handle *handle,
+ bool print_server,
+ uint32_t level,
+ uint32_t *count_p,
+ union spoolss_FormInfo **info_p)
{
- NTSTATUS status;
struct spoolss_EnumForms r;
- bool ret = true;
uint32_t needed;
uint32_t count;
- uint32_t levels[] = { 1, 2 };
- int i;
+ union spoolss_FormInfo *info;
- for (i=0; i<ARRAY_SIZE(levels); i++) {
+ r.in.handle = handle;
+ r.in.level = level;
+ r.in.buffer = NULL;
+ r.in.offered = 0;
+ r.out.needed = &needed;
+ r.out.count = &count;
+ r.out.info = &info;
- union spoolss_FormInfo *info;
+ torture_comment(tctx, "Testing EnumForms level %d\n", r.in.level);
- r.in.handle = handle;
- r.in.level = levels[i];
- r.in.buffer = NULL;
- r.in.offered = 0;
- r.out.needed = &needed;
- r.out.count = &count;
- r.out.info = &info;
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_spoolss_EnumForms_r(b, tctx, &r),
+ "EnumForms failed");
- torture_comment(tctx, "Testing EnumForms level %d\n", levels[i]);
+ if ((r.in.level == 2) && (W_ERROR_EQUAL(r.out.result, WERR_UNKNOWN_LEVEL))) {
+ torture_skip(tctx, "EnumForms level 2 not supported");
+ }
- status = dcerpc_spoolss_EnumForms_r(b, tctx, &r);
- torture_assert_ntstatus_ok(tctx, status, "EnumForms failed");
+ if (print_server && W_ERROR_EQUAL(r.out.result, WERR_BADFID)) {
+ torture_fail(tctx, "EnumForms on the PrintServer isn't supported by test server (NT4)");
+ }
- if ((r.in.level == 2) && (W_ERROR_EQUAL(r.out.result, WERR_UNKNOWN_LEVEL))) {
- break;
- }
+ 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;
- if (print_server && W_ERROR_EQUAL(r.out.result, WERR_BADFID))
- torture_fail(tctx, "EnumForms on the PrintServer isn't supported by test server (NT4)");
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_spoolss_EnumForms_r(b, tctx, &r),
+ "EnumForms failed");
- if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
- int j;
- DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed);
- data_blob_clear(&blob);
- r.in.buffer = &blob;
- r.in.offered = needed;
+ torture_assert(tctx, info, "No forms returned");
+ }
+
+ torture_assert_werr_ok(tctx, r.out.result, "EnumForms failed");
+
+ CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumForms, info, r.in.level, count, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
+
+ if (info_p) {
+ *info_p = info;
+ }
+ if (count_p) {
+ *count_p = count;
+ }
+
+ return true;
+}
+
+static bool test_EnumForms_all(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ struct policy_handle *handle,
+ bool print_server)
+{
+ uint32_t levels[] = { 1, 2 };
+ int i, j;
- status = dcerpc_spoolss_EnumForms_r(b, tctx, &r);
+ for (i=0; i<ARRAY_SIZE(levels); i++) {
+
+ uint32_t count = 0;
+ union spoolss_FormInfo *info = NULL;
- torture_assert(tctx, info, "No forms returned");
+ torture_assert(tctx,
+ test_EnumForms(tctx, b, handle, print_server, levels[i], &count, &info),
+ "failed to enum forms");
- for (j = 0; j < count; j++) {
- if (!print_server)
- ret &= test_GetForm(tctx, b, handle, info[j].info1.form_name, levels[i]);
+ for (j = 0; j < count; j++) {
+ if (!print_server) {
+ torture_assert(tctx,
+ test_GetForm(tctx, b, handle, info[j].info1.form_name, levels[i]),
+ "failed to get form");
}
}
+ }
+
+ return true;
+}
- torture_assert_ntstatus_ok(tctx, status, "EnumForms failed");
+static bool test_EnumForms_find_one(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ struct policy_handle *handle,
+ bool print_server,
+ const char *form_name)
+{
+ union spoolss_FormInfo *info;
+ uint32_t count;
+ bool found = false;
+ int i;
- torture_assert_werr_ok(tctx, r.out.result, "EnumForms failed");
+ torture_assert(tctx,
+ test_EnumForms(tctx, b, handle, print_server, 1, &count, &info),
+ "failed to enumerate forms");
- CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumForms, info, r.in.level, count, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
+ for (i=0; i<count; i++) {
+ if (strequal(form_name, info[i].info1.form_name)) {
+ found = true;
+ break;
+ }
}
- return true;
+ return found;
}
static bool test_DeleteForm(struct torture_context *tctx,
struct dcerpc_binding_handle *b,
struct policy_handle *handle,
- const char *form_name)
+ const char *form_name,
+ WERROR expected_result)
{
- NTSTATUS status;
struct spoolss_DeleteForm r;
r.in.handle = handle;
r.in.form_name = form_name;
- status = dcerpc_spoolss_DeleteForm_r(b, tctx, &r);
+ torture_comment(tctx, "Testing DeleteForm(%s)\n", form_name);
- torture_assert_ntstatus_ok(tctx, status, "DeleteForm failed");
-
- torture_assert_werr_ok(tctx, r.out.result, "DeleteForm failed");
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_spoolss_DeleteForm_r(b, tctx, &r),
+ "DeleteForm failed");
+ torture_assert_werr_equal(tctx, r.out.result, expected_result,
+ "DeleteForm gave unexpected result");
+ if (W_ERROR_IS_OK(r.out.result)) {
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_spoolss_DeleteForm_r(b, tctx, &r),
+ "2nd DeleteForm failed");
+ torture_assert_werr_equal(tctx, r.out.result, WERR_INVALID_FORM_NAME,
+ "2nd DeleteForm failed");
+ }
return true;
}
static bool test_AddForm(struct torture_context *tctx,
struct dcerpc_binding_handle *b,
- struct policy_handle *handle, bool print_server)
+ struct policy_handle *handle,
+ uint32_t level,
+ union spoolss_AddFormInfo *info,
+ WERROR expected_result)
{
struct spoolss_AddForm r;
- struct spoolss_AddFormInfo1 addform;
- const char *form_name = "testform3";
- NTSTATUS status;
- bool ret = true;
+
+ if (level != 1) {
+ torture_skip(tctx, "only level 1 supported");
+ }
+
+ r.in.handle = handle;
+ r.in.level = level;
+ r.in.info = *info;
+
+ 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);
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_AddForm_r(b, tctx, &r),
+ "AddForm failed");
+ torture_assert_werr_equal(tctx, r.out.result, expected_result,
+ "AddForm gave unexpected result");
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_AddForm_r(b, tctx, &r),
+ "2nd AddForm failed");
+ if (W_ERROR_EQUAL(expected_result, WERR_INVALID_PARAM)) {
+ torture_assert_werr_equal(tctx, r.out.result, WERR_INVALID_PARAM,
+ "2nd AddForm gave unexpected result");
+ } else {
+ torture_assert_werr_equal(tctx, r.out.result, WERR_FILE_EXISTS,
+ "2nd AddForm gave unexpected result");
+ }
+
+ return true;
+}
+
+static bool test_SetForm(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ struct policy_handle *handle,
+ const char *form_name,
+ uint32_t level,
+ union spoolss_AddFormInfo *info)
+{
+ struct spoolss_SetForm r;
r.in.handle = handle;
- r.in.level = 1;
- r.in.info.info1 = &addform;
- addform.flags = SPOOLSS_FORM_USER;
- addform.form_name = form_name;
- addform.size.width = 50;
- addform.size.height = 25;
- addform.area.left = 5;
- addform.area.top = 10;
- addform.area.right = 45;
- addform.area.bottom = 15;
+ r.in.form_name = form_name;
+ r.in.level = level;
+ r.in.info = *info;
- status = dcerpc_spoolss_AddForm_r(b, tctx, &r);
+ torture_comment(tctx, "Testing SetForm(%s) level %d\n",
+ form_name, r.in.level);
- torture_assert_ntstatus_ok(tctx, status, "AddForm failed");
+ torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_SetForm_r(b, tctx, &r),
+ "SetForm failed");
- torture_assert_werr_ok(tctx, r.out.result, "AddForm failed");
+ torture_assert_werr_ok(tctx, r.out.result,
+ "SetForm failed");
- if (!print_server) ret &= test_GetForm(tctx, b, handle, form_name, 1);
+ return true;
+}
- {
- struct spoolss_SetForm sf;
- struct spoolss_AddFormInfo1 setform;
+static bool test_GetForm_winreg(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ struct policy_handle *handle,
+ const char *key_name,
+ const char *form_name,
+ enum winreg_Type *w_type,
+ uint32_t *w_size,
+ uint32_t *w_length,
+ uint8_t **w_data);
- sf.in.handle = handle;
- sf.in.form_name = form_name;
- sf.in.level = 1;
- sf.in.info.info1= &setform;
- setform.flags = addform.flags;
- setform.form_name = addform.form_name;
- setform.size = addform.size;
- setform.area = addform.area;
+static bool test_Forms_args(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ struct policy_handle *handle,
+ bool print_server,
+ const char *printer_name,
+ struct dcerpc_binding_handle *winreg_handle,
+ struct policy_handle *hive_handle,
+ const char *form_name,
+ struct spoolss_AddFormInfo1 *info1,
+ WERROR expected_add_result,
+ WERROR expected_delete_result)
+{
+ union spoolss_FormInfo info;
+ union spoolss_AddFormInfo add_info;
- setform.size.width = 1234;
+ enum winreg_Type w_type;
+ uint32_t w_size;
+ uint32_t w_length;
+ uint8_t *w_data;
- status = dcerpc_spoolss_SetForm_r(b, tctx, &sf);
+ add_info.info1 = info1;
- torture_assert_ntstatus_ok(tctx, status, "SetForm failed");
+ torture_assert(tctx,
+ test_AddForm(tctx, b, handle, 1, &add_info, expected_add_result),
+ "failed to add form");
- torture_assert_werr_ok(tctx, r.out.result, "SetForm failed");
- }
+ if (winreg_handle && hive_handle && W_ERROR_IS_OK(expected_add_result)) {
- if (!print_server) ret &= test_GetForm(tctx, b, handle, form_name, 1);
+ torture_assert(tctx,
+ test_GetForm_winreg(tctx, winreg_handle, hive_handle, TOP_LEVEL_CONTROL_FORMS_KEY, form_name, &w_type, &w_size, &w_length, &w_data),
+ "failed to get form via winreg");
+
+ torture_assert_int_equal(tctx, w_type, REG_BINARY, "unexpected type");
+ torture_assert_int_equal(tctx, w_size, 0x20, "unexpected size");
+ torture_assert_int_equal(tctx, w_length, 0x20, "unexpected length");
+ torture_assert_mem_equal(tctx, &w_data[0], &add_info.info1->size.width, 4, "width mismatch");
+ torture_assert_mem_equal(tctx, &w_data[4], &add_info.info1->size.height, 4, "height mismatch");
+ torture_assert_mem_equal(tctx, &w_data[8], &add_info.info1->area.left, 4, "left mismatch");
+ torture_assert_mem_equal(tctx, &w_data[12], &add_info.info1->area.top, 4, "top mismatch");
+ torture_assert_mem_equal(tctx, &w_data[16], &add_info.info1->area.right, 4, "right mismatch");
+ torture_assert_mem_equal(tctx, &w_data[20], &add_info.info1->area.bottom, 4, "bottom mismatch");
+ /* skip index here */
+ torture_assert_mem_equal(tctx, &w_data[28], &add_info.info1->flags, 4, "flags mismatch");
+ }
+
+ if (!print_server && W_ERROR_IS_OK(expected_add_result)) {
+ torture_assert(tctx,
+ test_GetForm_args(tctx, b, handle, form_name, 1, &info),
+ "failed to get added form");
- {
- struct spoolss_EnumForms e;
- union spoolss_FormInfo *info;
- uint32_t needed;
- uint32_t count;
- bool found = false;
+ torture_assert_int_equal(tctx, info.info1.size.width, add_info.info1->size.width, "width mismatch");
+ torture_assert_int_equal(tctx, info.info1.size.height, add_info.info1->size.height, "height mismatch");
+ torture_assert_int_equal(tctx, info.info1.area.left, add_info.info1->area.left, "left mismatch");
+ torture_assert_int_equal(tctx, info.info1.area.top, add_info.info1->area.top, "top mismatch");
+ torture_assert_int_equal(tctx, info.info1.area.right, add_info.info1->area.right, "right mismatch");
+ torture_assert_int_equal(tctx, info.info1.area.bottom, add_info.info1->area.bottom, "bottom mismatch");
+ torture_assert_int_equal(tctx, info.info1.flags, add_info.info1->flags, "flags mismatch");
+
+ if (winreg_handle && hive_handle) {
+ torture_assert_mem_equal(tctx, &w_data[0], &info.info1.size.width, 4, "width mismatch");
+ torture_assert_mem_equal(tctx, &w_data[4], &info.info1.size.height, 4, "height mismatch");
+ torture_assert_mem_equal(tctx, &w_data[8], &info.info1.area.left, 4, "left mismatch");
+ torture_assert_mem_equal(tctx, &w_data[12], &info.info1.area.top, 4, "top mismatch");
+ torture_assert_mem_equal(tctx, &w_data[16], &info.info1.area.right, 4, "right mismatch");
+ torture_assert_mem_equal(tctx, &w_data[20], &info.info1.area.bottom, 4, "bottom mismatch");
+ /* skip index here */
+ torture_assert_mem_equal(tctx, &w_data[28], &info.info1.flags, 4, "flags mismatch");
+ }
+
+ add_info.info1->size.width = 1234;
- e.in.handle = handle;
- e.in.level = 1;
- e.in.buffer = NULL;
- e.in.offered = 0;
- e.out.needed = &needed;
- e.out.count = &count;
- e.out.info = &info;
+ torture_assert(tctx,
+ test_SetForm(tctx, b, handle, form_name, 1, &add_info),
+ "failed to set form");
+ torture_assert(tctx,
+ test_GetForm_args(tctx, b, handle, form_name, 1, &info),
+ "failed to get setted form");
- torture_comment(tctx, "Testing EnumForms level 1\n");
+ torture_assert_int_equal(tctx, info.info1.size.width, add_info.info1->size.width, "width mismatch");
+ }
- status = dcerpc_spoolss_EnumForms_r(b, tctx, &e);
- torture_assert_ntstatus_ok(tctx, status, "EnumForms failed");
+ if (!W_ERROR_EQUAL(expected_add_result, WERR_INVALID_PARAM)) {
+ torture_assert(tctx,
+ test_EnumForms_find_one(tctx, b, handle, print_server, form_name),
+ "Newly added form not found in enum call");
+ }
- if (print_server && W_ERROR_EQUAL(e.out.result, WERR_BADFID))
- torture_fail(tctx, "EnumForms on the PrintServer isn't supported by test server (NT4)");
+ torture_assert(tctx,
+ test_DeleteForm(tctx, b, handle, form_name, expected_delete_result),
+ "failed to delete form");
- if (W_ERROR_EQUAL(e.out.result, WERR_INSUFFICIENT_BUFFER)) {
- int j;
- DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed);
- data_blob_clear(&blob);
- e.in.buffer = &blob;
- e.in.offered = needed;
+ return true;
+}
- status = dcerpc_spoolss_EnumForms_r(b, tctx, &e);
+static bool test_Forms(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ struct policy_handle *handle,
+ bool print_server,
+ const char *printer_name,
+ struct dcerpc_binding_handle *winreg_handle,
+ struct policy_handle *hive_handle)
+{
+ const struct spoolss_FormSize size = {
+ .width = 50,
+ .height = 25
+ };
+ const struct spoolss_FormArea area = {
+ .left = 5,
+ .top = 10,
+ .right = 45,
+ .bottom = 15
+ };
+ int i;
- torture_assert(tctx, info, "No forms returned");
+ struct {
+ struct spoolss_AddFormInfo1 info1;
+ WERROR expected_add_result;
+ WERROR expected_delete_result;
+ } forms[] = {
+ {
+ .info1 = {
+ .flags = SPOOLSS_FORM_USER,
+ .form_name = "testform_user",
+ .size = size,
+ .area = area,
+ },
+ .expected_add_result = WERR_OK,
+ .expected_delete_result = WERR_OK
+ },
+/*
+ weird, we can add a builtin form but we can never remove it
+ again - gd
- for (j = 0; j < count; j++) {
- if (strequal(form_name, info[j].info1.form_name)) {
- found = true;
- break;
- }
- }
+ {
+ .info1 = {
+ .flags = SPOOLSS_FORM_BUILTIN,
+ .form_name = "testform_builtin",
+ .size = size,
+ .area = area,
+ },
+ .expected_add_result = WERR_OK,
+ .expected_delete_result = WERR_INVALID_PARAM,
+ },
+*/
+ {
+ .info1 = {
+ .flags = SPOOLSS_FORM_PRINTER,
+ .form_name = "testform_printer",
+ .size = size,
+ .area = area,
+ },
+ .expected_add_result = WERR_OK,
+ .expected_delete_result = WERR_OK
+ },
+ {
+ .info1 = {
+ .flags = SPOOLSS_FORM_USER,
+ .form_name = "Letter",
+ .size = size,
+ .area = area,
+ },
+ .expected_add_result = WERR_FILE_EXISTS,
+ .expected_delete_result = WERR_INVALID_PARAM
+ },
+ {
+ .info1 = {
+ .flags = SPOOLSS_FORM_BUILTIN,
+ .form_name = "Letter",
+ .size = size,
+ .area = area,
+ },
+ .expected_add_result = WERR_FILE_EXISTS,
+ .expected_delete_result = WERR_INVALID_PARAM
+ },
+ {
+ .info1 = {
+ .flags = SPOOLSS_FORM_PRINTER,
+ .form_name = "Letter",
+ .size = size,
+ .area = area,
+ },
+ .expected_add_result = WERR_FILE_EXISTS,
+ .expected_delete_result = WERR_INVALID_PARAM
+ },
+ {
+ .info1 = {
+ .flags = 12345,
+ .form_name = "invalid_flags",
+ .size = size,
+ .area = area,
+ },
+ .expected_add_result = WERR_INVALID_PARAM,
+ .expected_delete_result = WERR_INVALID_FORM_NAME
}
- torture_assert(tctx, found, "Newly added form not found in enum call");
- }
- if (!test_DeleteForm(tctx, b, handle, form_name)) {
- ret = false;
+ };
+
+ for (i=0; i < ARRAY_SIZE(forms); i++) {
+ torture_assert(tctx,
+ test_Forms_args(tctx, b, handle, print_server, printer_name,
+ winreg_handle, hive_handle,
+ forms[i].info1.form_name,
+ &forms[i].info1,
+ forms[i].expected_add_result,
+ forms[i].expected_delete_result),
+ talloc_asprintf(tctx, "failed to test form '%s'", forms[i].info1.form_name));
}
- return ret;
+ return true;
}
static bool test_EnumPorts_old(struct torture_context *tctx,
torture_assert_ntstatus_ok(tctx, status, "EnumPorts failed");
if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
- DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed);
- data_blob_clear(&blob);
+ DATA_BLOB blob = data_blob_talloc_zero(tctx, needed);
r.in.buffer = &blob;
r.in.offered = needed;
return true;
}
-static bool test_GetJob(struct torture_context *tctx,
- struct dcerpc_binding_handle *b,
- struct policy_handle *handle, uint32_t job_id)
+static bool test_GetJob_args(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ struct policy_handle *handle,
+ uint32_t job_id,
+ uint32_t level,
+ union spoolss_JobInfo *info_p)
{
NTSTATUS status;
struct spoolss_GetJob r;
union spoolss_JobInfo info;
uint32_t needed;
- uint32_t levels[] = {1, 2 /* 3, 4 */};
- uint32_t i;
r.in.handle = handle;
r.in.job_id = job_id;
- r.in.level = 0;
+ r.in.level = level;
r.in.buffer = NULL;
r.in.offered = 0;
r.out.needed = &needed;
r.out.info = &info;
- torture_comment(tctx, "Testing GetJob level %d\n", r.in.level);
+ torture_comment(tctx, "Testing GetJob(%d), level %d\n", job_id, r.in.level);
status = dcerpc_spoolss_GetJob_r(b, tctx, &r);
- torture_assert_werr_equal(tctx, r.out.result, WERR_UNKNOWN_LEVEL, "Unexpected return code");
-
- for (i = 0; i < ARRAY_SIZE(levels); i++) {
-
- torture_comment(tctx, "Testing GetJob level %d\n", r.in.level);
-
- needed = 0;
+ torture_assert_ntstatus_ok(tctx, status, "GetJob failed");
+ if (level == 0) {
+ torture_assert_werr_equal(tctx, r.out.result, WERR_UNKNOWN_LEVEL, "Unexpected return code");
+ }
- r.in.level = levels[i];
- r.in.offered = 0;
- r.in.buffer = NULL;
+ 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;
status = dcerpc_spoolss_GetJob_r(b, tctx, &r);
torture_assert_ntstatus_ok(tctx, status, "GetJob failed");
+ }
- if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
- DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed);
- data_blob_clear(&blob);
- r.in.buffer = &blob;
- r.in.offered = needed;
+ torture_assert_werr_ok(tctx, r.out.result, "GetJob failed");
+ torture_assert(tctx, r.out.info, "No job info returned");
- status = dcerpc_spoolss_GetJob_r(b, tctx, &r);
- torture_assert_ntstatus_ok(tctx, status, "GetJob failed");
+ CHECK_NEEDED_SIZE_LEVEL(spoolss_JobInfo, r.out.info, r.in.level, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
- }
- torture_assert(tctx, r.out.info, "No job info returned");
- torture_assert_werr_ok(tctx, r.out.result, "GetJob failed");
+ if (info_p) {
+ *info_p = *r.out.info;
+ }
+
+ return true;
+}
- CHECK_NEEDED_SIZE_LEVEL(spoolss_JobInfo, r.out.info, r.in.level, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
+static bool test_GetJob(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ struct policy_handle *handle,
+ uint32_t job_id)
+{
+ uint32_t levels[] = {0, 1, 2 /* 3, 4 */};
+ uint32_t i;
+
+ for (i=0; i < ARRAY_SIZE(levels); i++) {
+ torture_assert(tctx,
+ test_GetJob_args(tctx, b, handle, job_id, levels[i], NULL),
+ "GetJob failed");
}
return true;
switch (command) {
case SPOOLSS_JOB_CONTROL_PAUSE:
- torture_comment(tctx, "Testing SetJob(%d) SPOOLSS_JOB_CONTROL_PAUSE\n", job_id);
+ torture_comment(tctx, "Testing SetJob(%d), SPOOLSS_JOB_CONTROL_PAUSE\n", job_id);
break;
case SPOOLSS_JOB_CONTROL_RESUME:
torture_comment(tctx, "Testing SetJob(%d), SPOOLSS_JOB_CONTROL_RESUME\n", job_id);
}
-static bool test_EnumJobs(struct torture_context *tctx,
- struct dcerpc_binding_handle *b,
- struct policy_handle *handle)
+static bool test_EnumJobs_args(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ struct policy_handle *handle,
+ uint32_t level,
+ uint32_t *count_p,
+ union spoolss_JobInfo **info_p)
{
NTSTATUS status;
struct spoolss_EnumJobs r;
r.in.handle = handle;
r.in.firstjob = 0;
r.in.numjobs = 0xffffffff;
- r.in.level = 1;
+ r.in.level = level;
r.in.buffer = NULL;
r.in.offered = 0;
r.out.needed = &needed;
r.out.count = &count;
r.out.info = &info;
- torture_comment(tctx, "Testing EnumJobs\n");
+ torture_comment(tctx, "Testing EnumJobs level %d\n", level);
status = dcerpc_spoolss_EnumJobs_r(b, tctx, &r);
torture_assert_ntstatus_ok(tctx, status, "EnumJobs failed");
if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
- int j;
- DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed);
- data_blob_clear(&blob);
+ DATA_BLOB blob = data_blob_talloc_zero(tctx, needed);
r.in.buffer = &blob;
r.in.offered = needed;
CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumJobs, *r.out.info, r.in.level, count, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
- for (j = 0; j < count; j++) {
-
- torture_assert(tctx, test_GetJob(tctx, b, handle, info[j].info1.job_id),
- "failed to call test_GetJob");
-
- /* FIXME - gd */
- if (!torture_setting_bool(tctx, "samba3", false)) {
- test_SetJob(tctx, b, handle, info[j].info1.job_id, SPOOLSS_JOB_CONTROL_PAUSE);
- test_SetJob(tctx, b, handle, info[j].info1.job_id, SPOOLSS_JOB_CONTROL_RESUME);
- }
- }
-
} else {
torture_assert_werr_ok(tctx, r.out.result, "EnumJobs failed");
}
+ if (count_p) {
+ *count_p = count;
+ }
+ if (info_p) {
+ *info_p = info;
+ }
+
return true;
}
-static bool test_DoPrintTest(struct torture_context *tctx,
- struct dcerpc_binding_handle *b,
- struct policy_handle *handle)
+static bool test_DoPrintTest_add_one_job(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ struct policy_handle *handle,
+ uint32_t *job_id)
{
- bool ret = true;
NTSTATUS status;
struct spoolss_StartDocPrinter s;
struct spoolss_DocumentInfo1 info1;
struct spoolss_EndPagePrinter ep;
struct spoolss_EndDocPrinter e;
int i;
- uint32_t job_id;
uint32_t num_written;
torture_comment(tctx, "Testing StartDocPrinter\n");
s.in.handle = handle;
s.in.level = 1;
s.in.info.info1 = &info1;
- s.out.job_id = &job_id;
+ s.out.job_id = job_id;
info1.document_name = "TorturePrintJob";
info1.output_file = NULL;
info1.datatype = "RAW";
torture_assert_werr_ok(tctx, s.out.result, "StartDocPrinter failed");
for (i=1; i < 4; i++) {
- torture_comment(tctx, "Testing StartPagePrinter: Page[%d]\n", i);
+ 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");
- torture_comment(tctx, "Testing WritePrinter: Page[%d]\n", i);
+ torture_comment(tctx, "Testing WritePrinter: Page[%d], JobId[%d]\n", i, *job_id);
w.in.handle = handle;
w.in.data = data_blob_string_const(talloc_asprintf(tctx,"TortureTestPage: %d\nData\n",i));
torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_WritePrinter failed");
torture_assert_werr_ok(tctx, w.out.result, "WritePrinter failed");
- torture_comment(tctx, "Testing EndPagePrinter: Page[%d]\n", i);
+ torture_comment(tctx, "Testing EndPagePrinter: Page[%d], JobId[%d]\n", i, *job_id);
ep.in.handle = handle;
torture_assert_werr_ok(tctx, ep.out.result, "EndPagePrinter failed");
}
- torture_comment(tctx, "Testing EndDocPrinter\n");
+ torture_comment(tctx, "Testing EndDocPrinter: JobId[%d]\n", *job_id);
e.in.handle = handle;
torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EndDocPrinter failed");
torture_assert_werr_ok(tctx, e.out.result, "EndDocPrinter failed");
- ret &= test_AddJob(tctx, b, handle);
- ret &= test_EnumJobs(tctx, b, handle);
+ return true;
+}
+
+static bool test_DoPrintTest_check_jobs(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ struct policy_handle *handle,
+ uint32_t num_jobs,
+ uint32_t *job_ids)
+{
+ uint32_t count;
+ union spoolss_JobInfo *info = NULL;
+ int i;
+
+ torture_assert(tctx,
+ test_AddJob(tctx, b, handle),
+ "AddJob failed");
+
+ torture_assert(tctx,
+ test_EnumJobs_args(tctx, b, handle, 1, &count, &info),
+ "EnumJobs level 1 failed");
+
+ torture_assert_int_equal(tctx, count, num_jobs, "unexpected number of jobs in queue");
+
+ for (i=0; i < num_jobs; i++) {
+ union spoolss_JobInfo ginfo;
+
+ torture_assert_int_equal(tctx, info[i].info1.job_id, job_ids[i], "job id mismatch");
+
+ torture_assert(tctx,
+ test_GetJob_args(tctx, b, handle, info[i].info1.job_id, 1, &ginfo),
+ "failed to call test_GetJob");
+
+ torture_assert_int_equal(tctx, ginfo.info1.job_id, info[i].info1.job_id, "job id mismatch");
+ }
+
+ for (i=0; i < num_jobs; i++) {
+ torture_assert(tctx,
+ test_SetJob(tctx, b, handle, info[i].info1.job_id, SPOOLSS_JOB_CONTROL_PAUSE),
+ "failed to pause printjob");
+ torture_assert(tctx,
+ test_SetJob(tctx, b, handle, info[i].info1.job_id, SPOOLSS_JOB_CONTROL_RESUME),
+ "failed to resume printjob");
+ }
+
+ return true;
+}
+
+static bool test_DoPrintTest(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ struct policy_handle *handle)
+{
+ bool ret = true;
+ uint32_t num_jobs = 8;
+ uint32_t *job_ids;
+ int i;
+
+ job_ids = talloc_zero_array(tctx, uint32_t, num_jobs);
- ret &= test_SetJob(tctx, b, handle, job_id, SPOOLSS_JOB_CONTROL_DELETE);
+ for (i=0; i < num_jobs; i++) {
+ ret &= test_DoPrintTest_add_one_job(tctx, b, handle, &job_ids[i]);
+ }
+
+ ret &= test_DoPrintTest_check_jobs(tctx, b, handle, num_jobs, job_ids);
+
+ for (i=0; i < num_jobs; i++) {
+ ret &= test_SetJob(tctx, b, handle, job_ids[i], SPOOLSS_JOB_CONTROL_DELETE);
+ }
return ret;
}
status = dcerpc_spoolss_GetPrinterDataEx_r(b, tctx, &r);
if (!NT_STATUS_IS_OK(status)) {
- if (NT_STATUS_EQUAL(status,NT_STATUS_NET_WRITE_FAULT) &&
- p->last_fault_code == DCERPC_FAULT_OP_RNG_ERROR) {
+ if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
torture_skip(tctx, "GetPrinterDataEx not supported by server\n");
}
torture_assert_ntstatus_ok(tctx, status, "GetPrinterDataEx failed");
return true;
}
+static bool test_get_environment(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ struct policy_handle *handle,
+ const char **architecture)
+{
+ DATA_BLOB blob;
+ enum winreg_Type type;
+ uint8_t *data;
+ uint32_t needed;
+
+ torture_assert(tctx,
+ test_GetPrinterData(tctx, b, handle, "Architecture", &type, &data, &needed),
+ "failed to get Architecture");
+
+ torture_assert_int_equal(tctx, type, REG_SZ, "unexpected type");
+
+ blob = data_blob_const(data, needed);
+ *architecture = reg_val_data_string(tctx, lp_iconv_convenience(tctx->lp_ctx), REG_SZ, blob);
+
+ return true;
+}
+
static bool test_GetPrinterData_list(struct torture_context *tctx,
struct dcerpc_pipe *p,
struct policy_handle *handle,
}
}
-static bool test_winreg_OpenKey(struct torture_context *tctx,
- struct dcerpc_binding_handle *b,
- struct policy_handle *hive_handle,
- const char *keyname,
- struct policy_handle *key_handle)
+static bool test_winreg_OpenKey_opts(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ struct policy_handle *hive_handle,
+ const char *keyname,
+ uint32_t options,
+ struct policy_handle *key_handle)
{
struct winreg_OpenKey r;
r.in.parent_handle = hive_handle;
init_winreg_String(&r.in.keyname, keyname);
- r.in.options = REG_KEYTYPE_NON_VOLATILE;
+ r.in.options = options;
r.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
r.out.handle = key_handle;
return true;
}
+static bool test_winreg_OpenKey(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ struct policy_handle *hive_handle,
+ const char *keyname,
+ struct policy_handle *key_handle)
+{
+ return test_winreg_OpenKey_opts(tctx, b, hive_handle, keyname,
+ REG_OPTION_NON_VOLATILE, key_handle);
+}
+
static bool test_winreg_CloseKey(struct torture_context *tctx,
struct dcerpc_binding_handle *b,
struct policy_handle *handle)
struct policy_handle key_handle;
printer_key = talloc_asprintf(tctx, "%s\\%s\\%s",
- TOP_LEVEL_PRINTER_KEY, printer_name, key_name);
+ TOP_LEVEL_PRINT_PRINTERS_KEY, printer_name, key_name);
torture_assert(tctx,
test_winreg_OpenKey(tctx, b, handle, printer_key, &key_handle), "");
return true;
}
-static bool test_SetPrinterData(struct torture_context *tctx,
- struct dcerpc_binding_handle *b,
+static bool test_GetForm_winreg(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
struct policy_handle *handle,
- const char *value_name,
- enum winreg_Type type,
- uint8_t *data,
- uint32_t offered)
+ const char *key_name,
+ const char *form_name,
+ enum winreg_Type *w_type,
+ uint32_t *w_size,
+ uint32_t *w_length,
+ uint8_t **w_data)
{
- struct spoolss_SetPrinterData r;
+ struct policy_handle key_handle;
- r.in.handle = handle;
- r.in.value_name = value_name;
- r.in.type = type;
- r.in.data = data;
- r.in.offered = offered;
+ torture_assert(tctx,
+ test_winreg_OpenKey(tctx, b, handle, key_name, &key_handle), "");
- torture_comment(tctx, "Testing SetPrinterData(%s)\n",
- r.in.value_name);
+ torture_assert(tctx,
+ test_winreg_QueryValue(tctx, b, &key_handle, form_name, w_type, w_size, w_length, w_data), "");
- torture_assert_ntstatus_ok(tctx,
- dcerpc_spoolss_SetPrinterData_r(b, tctx, &r),
- "SetPrinterData failed");
- torture_assert_werr_ok(tctx, r.out.result,
- "SetPrinterData failed");
+ torture_assert(tctx,
+ test_winreg_CloseKey(tctx, b, &key_handle), "");
return true;
}
-static bool test_SetPrinterData_matrix(struct torture_context *tctx,
+static bool test_winreg_symbolic_link(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ struct policy_handle *handle,
+ const char *symlink_keyname,
+ const char *symlink_destination)
+{
+ /* check if the first key is a symlink to the second key */
+
+ enum winreg_Type w_type;
+ uint32_t w_size;
+ uint32_t w_length;
+ uint8_t *w_data;
+ struct policy_handle key_handle;
+ DATA_BLOB blob;
+ const char *str;
+
+ if (torture_setting_bool(tctx, "samba3", false)) {
+ torture_skip(tctx, "skip winreg symlink test against samba");
+ }
+
+ torture_assert(tctx,
+ test_winreg_OpenKey_opts(tctx, b, handle, symlink_keyname, REG_OPTION_OPEN_LINK, &key_handle),
+ "failed to open key link");
+
+ torture_assert(tctx,
+ test_winreg_QueryValue(tctx, b, &key_handle,
+ "SymbolicLinkValue",
+ &w_type, &w_size, &w_length, &w_data),
+ "failed to query for 'SymbolicLinkValue' attribute");
+
+ torture_assert_int_equal(tctx, w_type, REG_LINK, "unexpected type");
+
+ blob = data_blob(w_data, w_size);
+ str = reg_val_data_string(tctx, lp_iconv_convenience(tctx->lp_ctx), REG_SZ, blob);
+
+ torture_assert_str_equal(tctx, str, symlink_destination, "unexpected symlink target string");
+
+ torture_assert(tctx,
+ test_winreg_CloseKey(tctx, b, &key_handle),
+ "failed to close key link");
+
+ return true;
+}
+
+static const char *strip_unc(const char *unc)
+{
+ char *name;
+
+ if (!unc) {
+ return NULL;
+ }
+
+ if (unc[0] == '\\' && unc[1] == '\\') {
+ unc +=2;
+ }
+
+ name = strchr(unc, '\\');
+ if (name) {
+ return name+1;
+ }
+
+ return unc;
+}
+
+static bool test_GetPrinterInfo_winreg(struct torture_context *tctx,
struct dcerpc_binding_handle *b,
struct policy_handle *handle,
const char *printer_name,
struct dcerpc_binding_handle *winreg_handle,
struct policy_handle *hive_handle)
{
- const char *values[] = {
- "spootyfoot",
- "spooty\\foot",
-#if 0
- /* FIXME: not working with s3 atm. */
- "spooty,foot",
- "spooty,fo,ot",
-#endif
- "spooty foot",
-#if 0
- /* FIXME: not working with s3 atm. */
- "spooty\\fo,ot",
- "spooty,fo\\ot"
-#endif
+ union spoolss_PrinterInfo info;
+ const char *keys[] = {
+ TOP_LEVEL_CONTROL_PRINTERS_KEY,
+ TOP_LEVEL_PRINT_PRINTERS_KEY
};
int i;
+ const char *printername, *sharename;
- for (i=0; i < ARRAY_SIZE(values); i++) {
+ torture_comment(tctx, "Testing Printer Info and winreg consistency\n");
- enum winreg_Type type;
- DATA_BLOB blob;
- uint8_t *data;
- uint32_t needed;
+ torture_assert(tctx,
+ test_GetPrinter_level(tctx, b, handle, 2, &info),
+ "failed to get printer info level 2");
+
+ printername = strip_unc(info.info2.printername);
+ sharename = strip_unc(info.info2.sharename);
+
+#define test_sz(wname, iname) \
+do {\
+ DATA_BLOB blob;\
+ const char *str;\
+ enum winreg_Type w_type;\
+ uint32_t w_size;\
+ uint32_t w_length;\
+ uint8_t *w_data;\
+ torture_assert(tctx,\
+ test_winreg_QueryValue(tctx, winreg_handle, &key_handle, wname,\
+ &w_type, &w_size, &w_length, &w_data),\
+ "failed to query winreg");\
+ torture_assert_int_equal(tctx, w_type, REG_SZ, "unexpected type");\
+ blob = data_blob(w_data, w_size);\
+ str = reg_val_data_string(tctx, lp_iconv_convenience(tctx->lp_ctx), REG_SZ, blob);\
+ if (w_size == 2 && iname == NULL) {\
+ /*torture_comment(tctx, "%s: \"\", %s: (null)\n", #wname, #iname);\ */\
+ } else {\
+ torture_assert_str_equal(tctx, str, iname,\
+ talloc_asprintf(tctx, "%s - %s mismatch", #wname, #iname));\
+ }\
+} while(0);
+
+#define test_dword(wname, iname) \
+do {\
+ uint32_t value;\
+ enum winreg_Type w_type;\
+ uint32_t w_size;\
+ uint32_t w_length;\
+ uint8_t *w_data;\
+ torture_assert(tctx,\
+ test_winreg_QueryValue(tctx, winreg_handle, &key_handle, wname,\
+ &w_type, &w_size, &w_length, &w_data),\
+ "failed to query winreg");\
+ torture_assert_int_equal(tctx, w_type, REG_DWORD, "unexpected type");\
+ torture_assert_int_equal(tctx, w_size, 4, "unexpected size");\
+ torture_assert_int_equal(tctx, w_length, 4, "unexpected length");\
+ value = IVAL(w_data, 0);\
+ torture_assert_int_equal(tctx, value, iname,\
+ talloc_asprintf(tctx, "%s - %s mismatch", #wname, #iname));\
+} while(0);
+
+#define test_dm(wname, iname) \
+do {\
+ DATA_BLOB blob;\
+ struct spoolss_DeviceMode dm;\
+ enum ndr_err_code ndr_err;\
+ enum winreg_Type w_type;\
+ uint32_t w_size;\
+ uint32_t w_length;\
+ uint8_t *w_data;\
+ torture_assert(tctx,\
+ test_winreg_QueryValue(tctx, winreg_handle, &key_handle, wname,\
+ &w_type, &w_size, &w_length, &w_data),\
+ "failed to query winreg");\
+ torture_assert_int_equal(tctx, w_type, REG_BINARY, "unexpected type");\
+ blob = data_blob(w_data, w_size);\
+ ndr_err = ndr_pull_struct_blob(&blob, tctx, lp_iconv_convenience(tctx->lp_ctx), &dm,\
+ (ndr_pull_flags_fn_t)ndr_pull_spoolss_DeviceMode);\
+ torture_assert_ndr_success(tctx, ndr_err, "failed to unmarshall dm");\
+ torture_assert(tctx, test_devicemode_equal(tctx, &dm, iname),\
+ "dm unequal");\
+} while(0);
+
+#define test_sd(wname, iname) \
+do {\
+ DATA_BLOB blob;\
+ struct security_descriptor sd;\
+ enum ndr_err_code ndr_err;\
+ enum winreg_Type w_type;\
+ uint32_t w_size;\
+ uint32_t w_length;\
+ uint8_t *w_data;\
+ torture_assert(tctx,\
+ test_winreg_QueryValue(tctx, winreg_handle, &key_handle, wname,\
+ &w_type, &w_size, &w_length, &w_data),\
+ "failed to query winreg");\
+ torture_assert_int_equal(tctx, w_type, REG_BINARY, "unexpected type");\
+ blob = data_blob(w_data, w_size);\
+ ndr_err = ndr_pull_struct_blob(&blob, tctx, lp_iconv_convenience(tctx->lp_ctx), &sd,\
+ (ndr_pull_flags_fn_t)ndr_pull_security_descriptor);\
+ torture_assert_ndr_success(tctx, ndr_err, "failed to unmarshall sd");\
+ torture_assert(tctx, test_security_descriptor_equal(tctx, &sd, iname),\
+ "sd unequal");\
+} while(0);
+
+#define test_multi_sz(wname, iname) \
+do {\
+ DATA_BLOB blob;\
+ const char **array;\
+ enum winreg_Type w_type;\
+ uint32_t w_size;\
+ uint32_t w_length;\
+ uint8_t *w_data;\
+ int i;\
+ torture_assert(tctx,\
+ test_winreg_QueryValue(tctx, winreg_handle, &key_handle, wname,\
+ &w_type, &w_size, &w_length, &w_data),\
+ "failed to query winreg");\
+ torture_assert_int_equal(tctx, w_type, REG_MULTI_SZ, "unexpected type");\
+ blob = data_blob(w_data, w_size);\
+ torture_assert(tctx, \
+ pull_reg_multi_sz(tctx, lp_iconv_convenience(tctx->lp_ctx), &blob, &array),\
+ "failed to pull multi sz");\
+ for (i=0; array[i] != NULL; i++) {\
+ torture_assert_str_equal(tctx, array[i], iname[i],\
+ talloc_asprintf(tctx, "%s - %s mismatch", #wname, iname[i]));\
+ }\
+} while(0);
- torture_assert(tctx,
- reg_string_to_val(tctx, lp_iconv_convenience(tctx->lp_ctx),
- "REG_SZ", "dog", &type, &blob), "");
+
+ if (!test_winreg_symbolic_link(tctx, winreg_handle, hive_handle,
+ TOP_LEVEL_CONTROL_PRINTERS_KEY,
+ "\\Registry\\Machine\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Print\\Printers"))
+ {
+ torture_warning(tctx, "failed to check for winreg symlink");
+ }
+
+
+ for (i=0; i < ARRAY_SIZE(keys); i++) {
+
+ const char *printer_key;
+ struct policy_handle key_handle;
+
+ printer_key = talloc_asprintf(tctx, "%s\\%s",
+ keys[i], printer_name);
torture_assert(tctx,
- test_SetPrinterData(tctx, b, handle, values[i], REG_SZ, blob.data, blob.length),
- "SetPrinterData failed");
+ test_winreg_OpenKey(tctx, winreg_handle, hive_handle, printer_key, &key_handle), "");
+
+ test_sz("Name", printername);
+ test_sz("Share Name", sharename);
+ test_sz("Port", info.info2.portname);
+ test_sz("Printer Driver", info.info2.drivername);
+ test_sz("Description", info.info2.comment);
+ test_sz("Location", info.info2.location);
+ test_sz("Separator File", info.info2.sepfile);
+ test_sz("Print Processor", info.info2.printprocessor);
+ test_sz("Datatype", info.info2.datatype);
+ test_sz("Parameters", info.info2.parameters);
+ /* winreg: 0, spoolss not */
+/* test_dword("Attributes", info.info2.attributes); */
+ test_dword("Priority", info.info2.priority);
+ test_dword("Default Priority", info.info2.defaultpriority);
+ /* winreg: 60, spoolss: 0 */
+/* test_dword("StartTime", info.info2.starttime); */
+/* test_dword("UntilTime", info.info2.untiltime); */
+ /* winreg != spoolss */
+/* test_dword("Status", info.info2.status); */
+ test_dm("Default DevMode", info.info2.devmode);
+ test_sd("Security", info.info2.secdesc);
torture_assert(tctx,
- test_GetPrinterData(tctx, b, handle, values[i], &type, &data, &needed),
- "GetPrinterData failed");
+ test_winreg_CloseKey(tctx, winreg_handle, &key_handle), "");
+ }
- torture_assert_int_equal(tctx, type, REG_SZ, "type mismatch");
- torture_assert_int_equal(tctx, needed, blob.length, "size mismatch");
- torture_assert_mem_equal(tctx, data, blob.data, blob.length, "buffer mismatch");
+#undef test_dm
+#undef test_sd
- if (winreg_handle && hive_handle) {
+ torture_comment(tctx, "Printer Info and winreg consistency test succeeded\n\n");
- enum winreg_Type w_type;
- uint32_t w_size;
- uint32_t w_length;
- uint8_t *w_data;
+ return true;
+}
- torture_assert(tctx,
- test_winreg_query_printerdata(tctx, winreg_handle, hive_handle,
- printer_name, "PrinterDriverData", values[i],
- &w_type, &w_size, &w_length, &w_data), "");
+static bool test_GetPrinterDriver2_level(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ struct policy_handle *handle,
+ const char *driver_name,
+ const char *architecture,
+ uint32_t level,
+ uint32_t client_major_version,
+ uint32_t client_minor_version,
+ union spoolss_DriverInfo *info_p,
+ WERROR *result);
+
+static const char *strip_path(const char *path)
+{
+ char *p;
- torture_assert_int_equal(tctx, w_type, REG_SZ, "winreg type mismatch");
- torture_assert_int_equal(tctx, w_size, blob.length, "winreg size mismatch");
- torture_assert_int_equal(tctx, w_length, blob.length, "winreg length mismatch");
- torture_assert_mem_equal(tctx, w_data, blob.data, blob.length, "winreg buffer mismatch");
- }
+ if (path == NULL) {
+ return NULL;
+ }
- torture_assert(tctx,
- test_DeletePrinterData(tctx, b, handle, values[i]),
- "DeletePrinterData failed");
+ p = strrchr(path, '\\');
+ if (p) {
+ return p+1;
}
- return true;
+ return path;
}
+static const char **strip_paths(const char **path_array)
+{
+ int i;
-static bool test_EnumPrinterKey(struct torture_context *tctx,
- struct dcerpc_binding_handle *b,
- struct policy_handle *handle,
- const char *key_name,
- const char ***array);
+ if (path_array == NULL) {
+ return NULL;
+ }
-static bool test_SetPrinterDataEx(struct torture_context *tctx,
- struct dcerpc_binding_handle *b,
+ for (i=0; path_array[i] != NULL; i++) {
+ path_array[i] = strip_path(path_array[i]);
+ }
+
+ return path_array;
+}
+
+static const char *driver_winreg_date(TALLOC_CTX *mem_ctx, NTTIME nt)
+{
+ time_t t;
+ struct tm *tm;
+ t = nt_time_to_unix(nt);
+ tm = localtime(&t);
+
+ return talloc_asprintf(mem_ctx, "%02d/%02d/%04d",
+ tm->tm_mon + 1, tm->tm_mday, tm->tm_year + 1900);
+}
+
+static const char *driver_winreg_version(TALLOC_CTX *mem_ctx, uint64_t v)
+{
+ return talloc_asprintf(mem_ctx, "%u.%u.%u.%u",
+ (unsigned)((v >> 48) & 0xFFFF),
+ (unsigned)((v >> 32) & 0xFFFF),
+ (unsigned)((v >> 16) & 0xFFFF),
+ (unsigned)(v & 0xFFFF));
+}
+
+static bool test_GetDriverInfo_winreg(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ struct policy_handle *handle,
+ const char *printer_name,
+ const char *driver_name,
+ const char *environment,
+ struct dcerpc_binding_handle *winreg_handle,
+ struct policy_handle *hive_handle)
+{
+ WERROR result;
+ union spoolss_DriverInfo info;
+ const char *driver_key;
+ struct policy_handle key_handle;
+
+ const char *driver_path;
+ const char *data_file;
+ const char *config_file;
+ const char *help_file;
+ const char **dependent_files;
+
+ const char *driver_date;
+ const char *inbox_driver_date;
+
+ const char *driver_version;
+ const char *inbox_driver_version;
+
+ torture_comment(tctx, "Testing Driver Info and winreg consistency\n");
+
+ driver_key = talloc_asprintf(tctx, "%s\\%s\\Drivers\\Version-%d\\%s",
+ TOP_LEVEL_CONTROL_ENVIRONMENTS_KEY,
+ environment,
+ 3,
+ driver_name);
+
+ torture_assert(tctx,
+ 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;
+ }
+
+ torture_assert(tctx,
+ test_GetPrinterDriver2_level(tctx, b, handle, driver_name, environment, 8, 3, 0, &info, &result),
+ "failed to get driver info level 8");
+
+ if (W_ERROR_EQUAL(result, WERR_INVALID_LEVEL)) {
+ goto try_level6;
+ }
+
+ driver_path = strip_path(info.info8.driver_path);
+ data_file = strip_path(info.info8.data_file);
+ config_file = strip_path(info.info8.config_file);
+ help_file = strip_path(info.info8.help_file);
+ dependent_files = strip_paths(info.info8.dependent_files);
+
+ driver_date = driver_winreg_date(tctx, info.info8.driver_date);
+ inbox_driver_date = driver_winreg_date(tctx, info.info8.min_inbox_driver_ver_date);
+
+ driver_version = driver_winreg_version(tctx, info.info8.driver_version);
+ inbox_driver_version = driver_winreg_version(tctx, info.info8.min_inbox_driver_ver_version);
+
+ test_sz("Configuration File", config_file);
+ test_sz("Data File", data_file);
+ test_sz("Datatype", info.info8.default_datatype);
+ test_sz("Driver", driver_path);
+ test_sz("DriverDate", driver_date);
+ test_sz("DriverVersion", driver_version);
+ test_sz("HardwareID", info.info8.hardware_id);
+ test_sz("Help File", help_file);
+ test_sz("InfPath", info.info8.inf_path);
+ test_sz("Manufacturer", info.info8.manufacturer_name);
+ test_sz("MinInboxDriverVerDate", inbox_driver_date);
+ test_sz("MinInboxDriverVerVersion", inbox_driver_version);
+ test_sz("Monitor", info.info8.monitor_name);
+ test_sz("OEM URL", info.info8.manufacturer_url);
+ test_sz("Print Processor", info.info8.print_processor);
+ test_sz("Provider", info.info8.provider);
+ test_sz("VendorSetup", info.info8.vendor_setup);
+ test_multi_sz("ColorProfiles", info.info8.color_profiles);
+ test_multi_sz("Dependent Files", dependent_files);
+ test_multi_sz("CoreDependencies", info.info8.core_driver_dependencies);
+ test_multi_sz("Previous Names", info.info8.previous_names);
+/* test_dword("Attributes", ?); */
+ test_dword("PrinterDriverAttributes", info.info8.printer_driver_attributes);
+ test_dword("Version", info.info8.version);
+/* test_dword("TempDir", ?); */
+
+ try_level6:
+
+ torture_assert(tctx,
+ test_GetPrinterDriver2_level(tctx, b, handle, driver_name, environment, 6, 3, 0, &info, &result),
+ "failed to get driver info level 6");
+
+ driver_path = strip_path(info.info6.driver_path);
+ data_file = strip_path(info.info6.data_file);
+ config_file = strip_path(info.info6.config_file);
+ help_file = strip_path(info.info6.help_file);
+ dependent_files = strip_paths(info.info6.dependent_files);
+
+ driver_date = driver_winreg_date(tctx, info.info6.driver_date);
+
+ driver_version = driver_winreg_version(tctx, info.info6.driver_version);
+
+ test_sz("Configuration File", config_file);
+ test_sz("Data File", data_file);
+ test_sz("Datatype", info.info6.default_datatype);
+ test_sz("Driver", driver_path);
+ test_sz("DriverDate", driver_date);
+ test_sz("DriverVersion", driver_version);
+ test_sz("HardwareID", info.info6.hardware_id);
+ test_sz("Help File", help_file);
+ test_sz("Manufacturer", info.info6.manufacturer_name);
+ test_sz("Monitor", info.info6.monitor_name);
+ test_sz("OEM URL", info.info6.manufacturer_url);
+ test_sz("Provider", info.info6.provider);
+ test_multi_sz("Dependent Files", dependent_files);
+ test_multi_sz("Previous Names", info.info6.previous_names);
+/* test_dword("Attributes", ?); */
+ test_dword("Version", info.info6.version);
+/* test_dword("TempDir", ?); */
+
+ try_level3:
+
+ torture_assert(tctx,
+ test_GetPrinterDriver2_level(tctx, b, handle, driver_name, environment, 3, 3, 0, &info, &result),
+ "failed to get driver info level 3");
+
+ driver_path = strip_path(info.info3.driver_path);
+ data_file = strip_path(info.info3.data_file);
+ config_file = strip_path(info.info3.config_file);
+ help_file = strip_path(info.info3.help_file);
+ dependent_files = strip_paths(info.info3.dependent_files);
+
+ test_sz("Configuration File", config_file);
+ test_sz("Data File", data_file);
+ test_sz("Datatype", info.info3.default_datatype);
+ test_sz("Driver", driver_path);
+ test_sz("Help File", help_file);
+ test_sz("Monitor", info.info3.monitor_name);
+ test_multi_sz("Dependent Files", dependent_files);
+/* test_dword("Attributes", ?); */
+ test_dword("Version", info.info3.version);
+/* test_dword("TempDir", ?); */
+
+
+ torture_assert(tctx,
+ test_winreg_CloseKey(tctx, winreg_handle, &key_handle), "");
+
+ torture_comment(tctx, "Driver Info and winreg consistency test succeeded\n\n");
+
+ return true;
+}
+
+#undef test_sz
+#undef test_dword
+
+static bool test_SetPrinterData(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ struct policy_handle *handle,
+ const char *value_name,
+ enum winreg_Type type,
+ uint8_t *data,
+ uint32_t offered)
+{
+ struct spoolss_SetPrinterData r;
+
+ r.in.handle = handle;
+ r.in.value_name = value_name;
+ r.in.type = type;
+ r.in.data = data;
+ r.in.offered = offered;
+
+ torture_comment(tctx, "Testing SetPrinterData(%s)\n",
+ r.in.value_name);
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_spoolss_SetPrinterData_r(b, tctx, &r),
+ "SetPrinterData failed");
+ torture_assert_werr_ok(tctx, r.out.result,
+ "SetPrinterData failed");
+
+ return true;
+}
+
+static bool test_SetPrinterData_matrix(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ struct policy_handle *handle,
+ const char *printer_name,
+ struct dcerpc_binding_handle *winreg_handle,
+ struct policy_handle *hive_handle)
+{
+ const char *values[] = {
+ "spootyfoot",
+ "spooty\\foot",
+#if 0
+ /* FIXME: not working with s3 atm. */
+ "spooty,foot",
+ "spooty,fo,ot",
+#endif
+ "spooty foot",
+#if 0
+ /* FIXME: not working with s3 atm. */
+ "spooty\\fo,ot",
+ "spooty,fo\\ot"
+#endif
+ };
+ int i;
+
+ for (i=0; i < ARRAY_SIZE(values); i++) {
+
+ enum winreg_Type type;
+ DATA_BLOB blob;
+ uint8_t *data;
+ uint32_t needed;
+
+ torture_assert(tctx,
+ reg_string_to_val(tctx, lp_iconv_convenience(tctx->lp_ctx),
+ "REG_SZ", "dog", &type, &blob), "");
+
+ torture_assert(tctx,
+ test_SetPrinterData(tctx, b, handle, values[i], REG_SZ, blob.data, blob.length),
+ "SetPrinterData failed");
+
+ torture_assert(tctx,
+ test_GetPrinterData(tctx, b, handle, values[i], &type, &data, &needed),
+ "GetPrinterData failed");
+
+ torture_assert_int_equal(tctx, type, REG_SZ, "type mismatch");
+ torture_assert_int_equal(tctx, needed, blob.length, "size mismatch");
+ torture_assert_mem_equal(tctx, data, blob.data, blob.length, "buffer mismatch");
+
+ if (winreg_handle && hive_handle) {
+
+ enum winreg_Type w_type;
+ uint32_t w_size;
+ uint32_t w_length;
+ uint8_t *w_data;
+
+ torture_assert(tctx,
+ test_winreg_query_printerdata(tctx, winreg_handle, hive_handle,
+ printer_name, "PrinterDriverData", values[i],
+ &w_type, &w_size, &w_length, &w_data), "");
+
+ torture_assert_int_equal(tctx, w_type, REG_SZ, "winreg type mismatch");
+ torture_assert_int_equal(tctx, w_size, blob.length, "winreg size mismatch");
+ torture_assert_int_equal(tctx, w_length, blob.length, "winreg length mismatch");
+ torture_assert_mem_equal(tctx, w_data, blob.data, blob.length, "winreg buffer mismatch");
+ }
+
+ torture_assert(tctx,
+ test_DeletePrinterData(tctx, b, handle, values[i]),
+ "DeletePrinterData failed");
+ }
+
+ return true;
+}
+
+
+static bool test_EnumPrinterKey(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ struct policy_handle *handle,
+ const char *key_name,
+ const char ***array);
+
+static bool test_SetPrinterDataEx(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
struct policy_handle *handle,
const char *key_name,
const char *value_name,
return ret;
}
+static bool test_Forms_winreg(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ struct policy_handle *handle,
+ bool print_server,
+ const char *printer_name)
+{
+ struct dcerpc_pipe *p2;
+ bool ret = true;
+ struct policy_handle hive_handle;
+ struct dcerpc_binding_handle *b2;
+
+ torture_assert_ntstatus_ok(tctx,
+ torture_rpc_connection(tctx, &p2, &ndr_table_winreg),
+ "could not open winreg pipe");
+ b2 = p2->binding_handle;
+
+ torture_assert(tctx, test_winreg_OpenHKLM(tctx, b2, &hive_handle), "");
+
+ ret = test_Forms(tctx, b, handle, print_server, printer_name, b2, &hive_handle);
+
+ test_winreg_CloseKey(tctx, b2, &hive_handle);
+
+ talloc_free(p2);
+
+ return ret;
+}
+
+static bool test_PrinterInfo_winreg(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ struct policy_handle *handle,
+ const char *printer_name)
+{
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ struct dcerpc_pipe *p2;
+ bool ret = true;
+ struct policy_handle hive_handle;
+ struct dcerpc_binding_handle *b2;
+
+ torture_assert_ntstatus_ok(tctx,
+ torture_rpc_connection(tctx, &p2, &ndr_table_winreg),
+ "could not open winreg pipe");
+ b2 = p2->binding_handle;
+
+ torture_assert(tctx, test_winreg_OpenHKLM(tctx, b2, &hive_handle), "");
+
+ ret = test_GetPrinterInfo_winreg(tctx, b, handle, printer_name, b2, &hive_handle);
+
+ test_winreg_CloseKey(tctx, b2, &hive_handle);
+
+ talloc_free(p2);
+
+ return ret;
+}
+
+static bool test_DriverInfo_winreg(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ struct policy_handle *handle,
+ const char *printer_name,
+ const char *driver_name,
+ const char *environment)
+{
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ struct dcerpc_pipe *p2;
+ bool ret = true;
+ struct policy_handle hive_handle;
+ struct dcerpc_binding_handle *b2;
+
+ torture_assert_ntstatus_ok(tctx,
+ torture_rpc_connection(tctx, &p2, &ndr_table_winreg),
+ "could not open winreg pipe");
+ b2 = p2->binding_handle;
+
+ torture_assert(tctx, test_winreg_OpenHKLM(tctx, b2, &hive_handle), "");
+
+ ret = test_GetDriverInfo_winreg(tctx, b, handle, printer_name, driver_name, environment, b2, &hive_handle);
+
+ test_winreg_CloseKey(tctx, b2, &hive_handle);
+
+ talloc_free(p2);
+
+ return ret;
+}
+
static bool test_GetChangeID_PrinterData(struct torture_context *tctx,
struct dcerpc_binding_handle *b,
struct policy_handle *handle,
return true;
}
- torture_comment(tctx, "testing close on secondary pipe\n");
+ 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");
cp.out.handle = handle;
status = dcerpc_spoolss_ClosePrinter_r(p2->binding_handle, tctx, &cp);
- torture_assert_ntstatus_equal(tctx, status, NT_STATUS_NET_WRITE_FAULT,
+ torture_assert_ntstatus_equal(tctx, status, NT_STATUS_RPC_SS_CONTEXT_MISMATCH,
"ERROR: Allowed close on secondary connection");
- torture_assert_int_equal(tctx, p2->last_fault_code, DCERPC_FAULT_CONTEXT_MISMATCH,
- "Unexpected fault code");
-
talloc_free(p2);
return true;
return ret;
}
+static bool test_OpenPrinter_badname_list(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ const char *server_name)
+{
+ const char *badnames[] = {
+ "__INVALID_PRINTER__",
+ "\\\\__INVALID_HOST__",
+ "",
+ "\\\\\\",
+ "\\\\\\__INVALID_PRINTER__"
+ };
+ const char *badname;
+ int i;
+
+ for (i=0; i < ARRAY_SIZE(badnames); i++) {
+ torture_assert(tctx,
+ test_OpenPrinter_badname(tctx, b, badnames[i]),
+ "");
+ }
+
+ badname = talloc_asprintf(tctx, "\\\\%s\\", server_name);
+ torture_assert(tctx,
+ test_OpenPrinter_badname(tctx, b, badname),
+ "");
+
+ badname = talloc_asprintf(tctx, "\\\\%s\\__INVALID_PRINTER__", server_name);
+ torture_assert(tctx,
+ test_OpenPrinter_badname(tctx, b, badname),
+ "");
+
+ return true;
+}
+
static bool test_OpenPrinter(struct torture_context *tctx,
struct dcerpc_pipe *p,
const char *name,
ret = false;
}
- if (!test_EnumForms(tctx, b, &handle, false)) {
+ if (!test_EnumForms_all(tctx, b, &handle, false)) {
+ ret = false;
+ }
+
+ if (!test_Forms(tctx, b, &handle, false, name, NULL, NULL)) {
ret = false;
}
- if (!test_AddForm(tctx, b, &handle, false)) {
+ if (!test_Forms_winreg(tctx, b, &handle, false, name)) {
ret = false;
}
torture_assert_ntstatus_ok(tctx, status, "EnumPrinters failed");
if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
- DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed);
- data_blob_clear(&blob);
+ DATA_BLOB blob = data_blob_talloc_zero(tctx, needed);
r.in.buffer = &blob;
r.in.offered = needed;
status = dcerpc_spoolss_EnumPrinters_r(b, tctx, &r);
torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_GetPrinterDriver_r(b, tctx, &r),
"failed to call GetPrinterDriver");
if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
- DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed);
- data_blob_clear(&blob);
+ DATA_BLOB blob = data_blob_talloc_zero(tctx, needed);
r.in.buffer = &blob;
r.in.offered = needed;
torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_GetPrinterDriver_r(b, tctx, &r),
return true;
}
-static bool test_GetPrinterDriver2(struct torture_context *tctx,
- struct dcerpc_binding_handle *b,
- struct policy_handle *handle,
- const char *driver_name,
- const char *architecture)
+static bool test_GetPrinterDriver2_level(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ struct policy_handle *handle,
+ const char *driver_name,
+ const char *architecture,
+ uint32_t level,
+ uint32_t client_major_version,
+ uint32_t client_minor_version,
+ union spoolss_DriverInfo *info_p,
+ WERROR *result_p)
+
{
struct spoolss_GetPrinterDriver2 r;
- uint16_t levels[] = {1, 2, 3, 4, 5, 6, 8, 101 };
uint32_t needed;
uint32_t server_major_version;
uint32_t server_minor_version;
- int i;
r.in.handle = handle;
r.in.architecture = architecture;
- r.in.client_major_version = 3;
- r.in.client_minor_version = 0;
+ r.in.client_major_version = client_major_version;
+ r.in.client_minor_version = client_minor_version;
+ r.in.buffer = NULL;
+ r.in.offered = 0;
+ r.in.level = level;
r.out.needed = &needed;
r.out.server_major_version = &server_major_version;
r.out.server_minor_version = &server_minor_version;
- for (i=0;i<ARRAY_SIZE(levels);i++) {
+ torture_comment(tctx, "Testing GetPrinterDriver2(%s) level %d\n",
+ driver_name, r.in.level);
- r.in.buffer = NULL;
- r.in.offered = 0;
- r.in.level = levels[i];
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_spoolss_GetPrinterDriver2_r(b, tctx, &r),
+ "failed to call GetPrinterDriver2");
+ 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_GetPrinterDriver2_r(b, tctx, &r),
+ "failed to call GetPrinterDriver2");
+ }
- torture_comment(tctx, "Testing GetPrinterDriver2(%s) level %d\n",
- driver_name, r.in.level);
+ if (result_p) {
+ *result_p = r.out.result;
+ }
- torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_GetPrinterDriver2_r(b, tctx, &r),
- "failed to call GetPrinterDriver2");
- if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
- DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed);
- data_blob_clear(&blob);
- r.in.buffer = &blob;
- r.in.offered = needed;
- torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_GetPrinterDriver2_r(b, tctx, &r),
- "failed to call GetPrinterDriver2");
+ if (W_ERROR_EQUAL(r.out.result, WERR_INVALID_LEVEL)) {
+ switch (r.in.level) {
+ case 101:
+ case 8:
+ torture_comment(tctx,
+ "level %d not implemented, not considering as an error\n",
+ r.in.level);
+ return true;
+ default:
+ break;
}
+ }
- if (W_ERROR_EQUAL(r.out.result, WERR_INVALID_LEVEL)) {
- switch (r.in.level) {
- case 101:
- case 8:
- continue;
- default:
- break;
- }
- }
+ torture_assert_werr_ok(tctx, r.out.result,
+ "failed to call GetPrinterDriver2");
- torture_assert_werr_ok(tctx, r.out.result,
- "failed to call GetPrinterDriver2");
+ CHECK_NEEDED_SIZE_LEVEL(spoolss_DriverInfo, r.out.info, r.in.level, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
+
+ if (info_p) {
+ *info_p = *r.out.info;
+ }
- CHECK_NEEDED_SIZE_LEVEL(spoolss_DriverInfo, r.out.info, r.in.level, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
+ return true;
+}
+
+static bool test_GetPrinterDriver2(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ struct policy_handle *handle,
+ const char *driver_name,
+ const char *architecture)
+{
+ uint16_t levels[] = {1, 2, 3, 4, 5, 6, 8, 101 };
+ int i;
+
+
+ for (i=0;i<ARRAY_SIZE(levels);i++) {
+
+ torture_assert(tctx,
+ test_GetPrinterDriver2_level(tctx, b, handle, driver_name, architecture, levels[i], 3, 0, NULL, NULL),
+ "");
}
return true;
struct dcerpc_pipe *p,
const char *environment)
{
- struct spoolss_EnumPrinterDrivers r;
- NTSTATUS status;
uint16_t levels[] = {1, 2, 3, 4, 5, 6};
int i;
struct dcerpc_binding_handle *b = p->binding_handle;
+ const char *server_name = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
for (i=0;i<ARRAY_SIZE(levels);i++) {
- uint32_t needed;
uint32_t count;
union spoolss_DriverInfo *info;
- r.in.server = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
- r.in.environment = environment;
- r.in.level = levels[i];
- r.in.buffer = NULL;
- r.in.offered = 0;
- r.out.needed = &needed;
- r.out.count = &count;
- r.out.info = &info;
-
- torture_comment(tctx, "Testing EnumPrinterDrivers level %u\n", r.in.level);
-
- status = dcerpc_spoolss_EnumPrinterDrivers_r(b, tctx, &r);
-
- torture_assert_ntstatus_ok(tctx, status, "EnumPrinterDrivers failed");
-
- if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
- DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed);
- data_blob_clear(&blob);
- r.in.buffer = &blob;
- r.in.offered = needed;
- status = dcerpc_spoolss_EnumPrinterDrivers_r(b, tctx, &r);
- }
-
- torture_assert_ntstatus_ok(tctx, status, "EnumPrinterDrivers failed");
-
- torture_assert_werr_ok(tctx, r.out.result, "EnumPrinterDrivers failed");
+ torture_assert(tctx,
+ test_EnumPrinterDrivers_args(tctx, b, server_name, environment, levels[i], &count, &info),
+ "failed to enumerate drivers");
if (!info) {
torture_comment(tctx, "No printer drivers returned\n");
break;
}
-
- CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumPrinterDrivers, info, r.in.level, count, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
}
return true;
"failed to enum printers");
if (W_ERROR_EQUAL(e.out.result, WERR_INSUFFICIENT_BUFFER)) {
- DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed);
- data_blob_clear(&blob);
+ DATA_BLOB blob = data_blob_talloc_zero(tctx, needed);
e.in.buffer = &blob;
e.in.offered = needed;
return true;
}
-static bool test_AddPrinterEx(struct torture_context *tctx,
- struct dcerpc_pipe *p,
- struct policy_handle *handle_p,
- const char *printername,
- const char *drivername,
- const char *portname)
-{
- bool ret = true;
-
- if (!torture_setting_bool(tctx, "samba3", false)) {
- if (!test_AddPrinter_wellknown(tctx, p, TORTURE_WELLKNOWN_PRINTER_EX, true)) {
- torture_comment(tctx, "failed to add printer to well known list\n");
- ret = false;
- }
- }
-
- if (!test_AddPrinter_normal(tctx, p, handle_p,
- printername, drivername, portname,
- true)) {
- torture_comment(tctx, "failed to add printer to printer list\n");
- ret = false;
- }
-
- return ret;
-}
-
-static bool test_AddPrinter(struct torture_context *tctx,
- struct dcerpc_pipe *p,
- struct policy_handle *handle_p,
- const char *printername,
- const char *drivername,
- const char *portname)
-{
- bool ret = true;
-
- if (!torture_setting_bool(tctx, "samba3", false)) {
- if (!test_AddPrinter_wellknown(tctx, p, TORTURE_WELLKNOWN_PRINTER, false)) {
- torture_comment(tctx, "failed to add printer to well known list\n");
- ret = false;
- }
- }
-
- if (!test_AddPrinter_normal(tctx, p, handle_p,
- printername, drivername, portname,
- false)) {
- torture_comment(tctx, "failed to add printer to printer list\n");
- ret = false;
- }
-
- return ret;
-}
-
static bool test_printer_info(struct torture_context *tctx,
struct dcerpc_binding_handle *b,
struct policy_handle *handle)
static bool test_one_printer(struct torture_context *tctx,
struct dcerpc_pipe *p,
struct policy_handle *handle,
- const char *name)
+ const char *name,
+ const char *drivername,
+ const char *environment,
+ bool have_driver)
{
bool ret = true;
struct dcerpc_binding_handle *b = p->binding_handle;
+ if (!test_PausePrinter(tctx, b, handle)) {
+ ret = false;
+ }
+
+ if (!test_DoPrintTest(tctx, b, handle)) {
+ ret = false;
+ }
+
+ if (!test_ResumePrinter(tctx, b, handle)) {
+ ret = false;
+ }
+
if (!test_printer_info(tctx, b, handle)) {
ret = false;
}
ret = false;
}
+ if (!test_PrinterInfo_winreg(tctx, p, handle, name)) {
+ ret = false;
+ }
+
if (!test_ChangeID(tctx, p, handle)) {
ret = false;
}
ret = false;
}
+ if (have_driver) {
+ if (!test_DriverInfo_winreg(tctx, p, handle, name, drivername, environment)) {
+ ret = false;
+ }
+ }
+
if (!test_printer_rename(tctx, p, handle, name)) {
ret = false;
}
return ret;
}
-static bool test_printer(struct torture_context *tctx,
- struct dcerpc_pipe *p)
+static bool test_csetprinter(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ struct policy_handle *handle,
+ const char *printername,
+ const char *drivername,
+ const char *portname)
+{
+ union spoolss_PrinterInfo info;
+ struct policy_handle new_handle, new_handle2;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ torture_comment(tctx, "Testing c_setprinter\n");
+
+ torture_assert(tctx,
+ test_GetPrinter_level(tctx, b, handle, 0, &info),
+ "failed to get level 0 printer info");
+ torture_comment(tctx, "csetprinter on initial printer handle: %d\n",
+ info.info0.c_setprinter);
+
+ /* check if c_setprinter on 1st handle increases after a printer has
+ * been added */
+
+ torture_assert(tctx,
+ test_AddPrinter_normal(tctx, p, &new_handle, printername, drivername, portname, false),
+ "failed to add new printer");
+ torture_assert(tctx,
+ test_GetPrinter_level(tctx, b, handle, 0, &info),
+ "failed to get level 0 printer info");
+ torture_comment(tctx, "csetprinter on initial printer handle (after add): %d\n",
+ info.info0.c_setprinter);
+
+ /* check if c_setprinter on new handle increases after a printer has
+ * been added */
+
+ torture_assert(tctx,
+ test_GetPrinter_level(tctx, b, &new_handle, 0, &info),
+ "failed to get level 0 printer info");
+ torture_comment(tctx, "csetprinter on created handle: %d\n",
+ info.info0.c_setprinter);
+
+ /* open the new printer and check if c_setprinter increases */
+
+ torture_assert(tctx,
+ call_OpenPrinterEx(tctx, p, printername, NULL, &new_handle2),
+ "failed to open created printer");
+ torture_assert(tctx,
+ test_GetPrinter_level(tctx, b, &new_handle2, 0, &info),
+ "failed to get level 0 printer info");
+ torture_comment(tctx, "csetprinter on new handle (after openprinter): %d\n",
+ info.info0.c_setprinter);
+
+ /* cleanup */
+
+ torture_assert(tctx,
+ test_ClosePrinter(tctx, b, &new_handle2),
+ "failed to close printer");
+ torture_assert(tctx,
+ test_DeletePrinter(tctx, b, &new_handle),
+ "failed to delete new printer");
+
+ return true;
+}
+
+static bool test_add_printer_args_with_driver(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ struct torture_printer_context *t)
{
bool ret = true;
- struct policy_handle handle[2];
+ struct policy_handle handle;
bool found = false;
- const char *drivername = "Microsoft XPS Document Writer";
- const char *portname = "LPT1:";
struct dcerpc_binding_handle *b = p->binding_handle;
+ const char *printer_name = t->info2.printername;
+ const char *driver_name = t->added_driver ? t->driver.info8.driver_name : t->info2.drivername;
+ const char *port_name = t->info2.portname;
+ const char *printer_name2 = talloc_asprintf(tctx, "%s2", printer_name);
- /* test printer created via AddPrinter */
+ if (t->wellknown) {
+ torture_assert(tctx,
+ test_AddPrinter_wellknown(tctx, p, printer_name, t->ex),
+ "failed to add wellknown printer");
+ } else {
+ torture_assert(tctx,
+ test_AddPrinter_normal(tctx, p, &handle, printer_name, driver_name, port_name, t->ex),
+ "failed to add printer");
+ }
- if (!test_AddPrinter(tctx, p, &handle[0], TORTURE_PRINTER, drivername, portname)) {
- return false;
+ if (!test_csetprinter(tctx, p, &handle, printer_name2, driver_name, port_name)) {
+ ret = false;
}
- if (!test_one_printer(tctx, p, &handle[0], TORTURE_PRINTER)) {
+ if (!test_one_printer(tctx, p, &handle, printer_name, driver_name, t->driver.remote.environment, t->have_driver)) {
ret = false;
}
- if (!test_DeletePrinter(tctx, b, &handle[0])) {
+ if (!test_DeletePrinter(tctx, b, &handle)) {
ret = false;
}
if (!test_EnumPrinters_findname(tctx, b, PRINTER_ENUM_LOCAL, 1,
- TORTURE_PRINTER, &found)) {
+ printer_name, &found)) {
ret = false;
}
torture_assert(tctx, !found, "deleted printer still there");
- /* test printer created via AddPrinterEx */
+ return ret;
+}
+
+static bool compose_local_driver_directory(struct torture_context *tctx,
+ const char *environment,
+ const char *local_dir,
+ const char **path)
+{
+ char *p;
- if (!test_AddPrinterEx(tctx, p, &handle[1], TORTURE_PRINTER_EX, drivername, portname)) {
- return false;
+ p = strrchr(local_dir, '/');
+ if (!p) {
+ return NULL;
}
+ p++;
- if (!test_one_printer(tctx, p, &handle[1], TORTURE_PRINTER_EX)) {
- ret = false;
+ if (strequal(environment, "Windows x64")) {
+ if (!strequal(p, "x64")) {
+ *path = talloc_asprintf(tctx, "%s/x64", local_dir);
+ }
+ } else if (strequal(environment, "Windows NT x86")) {
+ if (!strequal(p, "i386")) {
+ *path = talloc_asprintf(tctx, "%s/i386", local_dir);
+ }
+ } else {
+ torture_assert(tctx, "unknown environment: '%s'\n", environment);
}
- if (!test_DeletePrinter(tctx, b, &handle[1])) {
- ret = false;
+ return true;
+}
+
+static bool test_add_printer_args(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ struct torture_printer_context *t)
+{
+ bool ret = true;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ const char *server_name_slash = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
+
+ if (t->wellknown && torture_setting_bool(tctx, "samba3", false)) {
+ torture_skip(tctx, "skipping AddPrinter level 1 against samba");
}
- if (!test_EnumPrinters_findname(tctx, b, PRINTER_ENUM_LOCAL, 1,
- TORTURE_PRINTER_EX, &found)) {
- ret = false;
+ torture_assert(tctx,
+ fillup_printserver_info(tctx, p, &t->driver),
+ "failed to fillup printserver info");
+
+ t->driver.info8.architecture = talloc_strdup(t, t->driver.remote.environment);
+
+ torture_assert(tctx,
+ compose_local_driver_directory(tctx, t->driver.remote.environment,
+ t->driver.local.driver_directory,
+ &t->driver.local.driver_directory),
+ "failed to compose local driver directory");
+
+ if (test_EnumPrinterDrivers_findone(tctx, b, server_name_slash, t->driver.remote.environment, 3, t->info2.drivername)) {
+ t->have_driver = true;
+ goto try_run;
}
- torture_assert(tctx, !found, "deleted printer still there");
+ torture_comment(tctx, "driver '%s' (architecture: %s, version: 3) does not exist on the server\n",
+ t->info2.drivername, t->driver.remote.environment);
+ torture_comment(tctx, "trying to upload own driver\n");
+
+ if (!directory_exist(t->driver.local.driver_directory)) {
+ torture_warning(tctx, "no local driver is available!");
+ t->have_driver = false;
+ goto try_run;
+ }
+
+ torture_assert(tctx,
+ upload_printer_driver(tctx, dcerpc_server_name(p), &t->driver),
+ "failed to upload printer driver");
+
+ torture_assert(tctx,
+ test_AddPrinterDriver_args_level_3(tctx, b, server_name_slash, &t->driver.info8, 0, false),
+ "failed to add driver");
+
+ t->added_driver = true;
+ t->have_driver = true;
+
+ try_run:
+ ret = test_add_printer_args_with_driver(tctx, p, t);
+
+ if (t->added_driver) {
+ torture_assert(tctx,
+ remove_printer_driver(tctx, dcerpc_server_name(p), &t->driver),
+ "failed to remove printer driver");
+ }
return ret;
}
+static bool test_add_printer(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ void *private_data)
+{
+ struct torture_printer_context *t =
+ (struct torture_printer_context *)talloc_get_type_abort(private_data, struct torture_printer_context);
+
+ t->ex = false;
+ t->wellknown = false;
+ t->info2.printername = TORTURE_PRINTER;
+
+ return test_add_printer_args(tctx, p, t);
+}
+
+static bool test_add_printer_wellknown(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ void *private_data)
+{
+ struct torture_printer_context *t =
+ (struct torture_printer_context *)talloc_get_type_abort(private_data, struct torture_printer_context);
+
+ t->ex = false;
+ t->wellknown = true;
+ t->info2.printername = TORTURE_WELLKNOWN_PRINTER;
+
+ return test_add_printer_args(tctx, p, t);
+}
+
+static bool test_add_printer_ex(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ void *private_data)
+{
+ struct torture_printer_context *t =
+ (struct torture_printer_context *)talloc_get_type_abort(private_data, struct torture_printer_context);
+
+ t->ex = true;
+ t->wellknown = false;
+ t->info2.printername = TORTURE_PRINTER_EX;
+
+ return test_add_printer_args(tctx, p, t);
+}
+
+static bool test_add_printer_ex_wellknown(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ void *private_data)
+{
+ struct torture_printer_context *t =
+ (struct torture_printer_context *)talloc_get_type_abort(private_data, struct torture_printer_context);
+
+ t->ex = true;
+ t->wellknown = true;
+ t->info2.printername = TORTURE_WELLKNOWN_PRINTER_EX;
+
+ return test_add_printer_args(tctx, p, t);
+}
+
static bool test_architecture_buffer(struct torture_context *tctx,
struct dcerpc_pipe *p)
{
ret &= test_OpenPrinter_server(torture, p, &ctx->server_handle);
ret &= test_GetPrinterData_list(torture, p, &ctx->server_handle, &environment);
- ret &= test_EnumForms(torture, b, &ctx->server_handle, true);
- ret &= test_AddForm(torture, b, &ctx->server_handle, true);
+ ret &= test_EnumForms_all(torture, b, &ctx->server_handle, true);
+ ret &= test_Forms(torture, b, &ctx->server_handle, true, NULL, NULL, NULL);
+ ret &= test_Forms_winreg(torture, b, &ctx->server_handle, true, NULL);
ret &= test_EnumPorts(torture, b, ctx);
- ret &= test_GetPrinterDriverDirectory(torture, p, ctx, environment);
- ret &= test_GetPrintProcessorDirectory(torture, p, ctx, environment);
+ ret &= test_GetPrinterDriverDirectory(torture, p, environment);
+ ret &= test_GetPrintProcessorDirectory(torture, p, environment);
ret &= test_EnumPrinterDrivers(torture, p, ctx, environment);
ret &= test_EnumPrinterDrivers(torture, p, ctx, SPOOLSS_ARCHITECTURE_ALL);
ret &= test_EnumMonitors(torture, b, ctx);
ret &= test_EnumPrintProcessors(torture, b, ctx, environment);
- ret &= test_EnumPrintProcDataTypes(torture, b, ctx);
+ ret &= test_EnumPrintProcDataTypes(torture, b);
ret &= test_EnumPrinters(torture, b, ctx);
- ret &= test_OpenPrinter_badname(torture, b, "__INVALID_PRINTER__");
- ret &= test_OpenPrinter_badname(torture, b, "\\\\__INVALID_HOST__");
- ret &= test_OpenPrinter_badname(torture, b, "");
- ret &= test_OpenPrinter_badname(torture, b, "\\\\\\");
- ret &= test_OpenPrinter_badname(torture, b, "\\\\\\__INVALID_PRINTER__");
- ret &= test_OpenPrinter_badname(torture, b, talloc_asprintf(torture, "\\\\%s\\", dcerpc_server_name(p)));
- ret &= test_OpenPrinter_badname(torture, b,
- talloc_asprintf(torture, "\\\\%s\\__INVALID_PRINTER__", dcerpc_server_name(p)));
-
+ ret &= test_OpenPrinter_badname_list(torture, b, dcerpc_server_name(p));
ret &= test_AddPort(torture, p);
ret &= test_EnumPorts_old(torture, p);
struct torture_rpc_tcase *tcase = torture_suite_add_rpc_iface_tcase(suite,
"printer", &ndr_table_spoolss);
- torture_rpc_tcase_add_test(tcase, "printer", test_printer);
+ struct torture_printer_context *t;
+
+ t = talloc_zero(mem_ctx, struct torture_printer_context);
+
+ t->driver.info8.version = SPOOLSS_DRIVER_VERSION_200X;
+ t->driver.info8.driver_name = TORTURE_DRIVER;
+ t->driver.info8.driver_path = "pscript5.dll";
+ t->driver.info8.data_file = "cups6.ppd";
+ t->driver.info8.config_file = "ps5ui.dll";
+ t->driver.info8.help_file = "pscript.hlp";
+ t->driver.info8.default_datatype = "RAW";
+ t->driver.info8.dependent_files = talloc_zero(t, struct spoolss_StringArray);
+ t->driver.info8.dependent_files->string = talloc_zero_array(t, const char *, 8 + 1);
+ t->driver.info8.dependent_files->string[0] = "pscript5.dll";
+ t->driver.info8.dependent_files->string[1] = "cups6.ppd";
+ t->driver.info8.dependent_files->string[2] = "ps5ui.dll";
+ t->driver.info8.dependent_files->string[3] = "pscript.hlp";
+ t->driver.info8.dependent_files->string[4] = "pscript.ntf";
+ t->driver.info8.dependent_files->string[5] = "cups6.ini";
+ t->driver.info8.dependent_files->string[6] = "cupsps6.dll";
+ t->driver.info8.dependent_files->string[7] = "cupsui6.dll";
+
+ t->driver.local.driver_directory= "/usr/share/cups/drivers";
+
+ t->info2.drivername = "Microsoft XPS Document Writer";
+ t->info2.portname = "LPT1:";
+
+ torture_rpc_tcase_add_test_ex(tcase, "add_printer", test_add_printer, t);
+ torture_rpc_tcase_add_test_ex(tcase, "add_printer_wellknown", test_add_printer_wellknown, t);
+ torture_rpc_tcase_add_test_ex(tcase, "add_printer_ex", test_add_printer_ex, t);
+ torture_rpc_tcase_add_test_ex(tcase, "add_printer_ex_wellknown", test_add_printer_ex_wellknown, t);
+
+ return suite;
+}
+
+static bool test_GetPrinterDriverDirectory_getdir(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ const char *server,
+ const char *environment,
+ const char **dir_p)
+{
+ struct spoolss_GetPrinterDriverDirectory r;
+ uint32_t needed;
+
+ r.in.server = server;
+ r.in.environment = environment;
+ r.in.level = 1;
+ r.in.buffer = NULL;
+ r.in.offered = 0;
+ r.out.needed = &needed;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_spoolss_GetPrinterDriverDirectory_r(b, tctx, &r),
+ "failed to query driver directory");
+
+ 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_GetPrinterDriverDirectory_r(b, tctx, &r),
+ "failed to query driver directory");
+ }
+
+ torture_assert_werr_ok(tctx, r.out.result,
+ "failed to query driver directory");
+
+ if (dir_p) {
+ *dir_p = r.out.info->info1.directory_name;
+ }
+
+ return true;
+}
+
+static const char *get_driver_from_info(struct spoolss_AddDriverInfoCtr *info_ctr)
+{
+ if (info_ctr == NULL) {
+ return NULL;
+ }
+
+ switch (info_ctr->level) {
+ case 1:
+ return info_ctr->info.info1->driver_name;
+ case 2:
+ return info_ctr->info.info2->driver_name;
+ case 3:
+ return info_ctr->info.info3->driver_name;
+ case 4:
+ return info_ctr->info.info4->driver_name;
+ case 6:
+ return info_ctr->info.info6->driver_name;
+ case 8:
+ return info_ctr->info.info8->driver_name;
+ default:
+ return NULL;
+ }
+}
+
+static const char *get_environment_from_info(struct spoolss_AddDriverInfoCtr *info_ctr)
+{
+ if (info_ctr == NULL) {
+ return NULL;
+ }
+
+ switch (info_ctr->level) {
+ case 2:
+ return info_ctr->info.info2->architecture;
+ case 3:
+ return info_ctr->info.info3->architecture;
+ case 4:
+ return info_ctr->info.info4->architecture;
+ case 6:
+ return info_ctr->info.info6->architecture;
+ case 8:
+ return info_ctr->info.info8->architecture;
+ default:
+ return NULL;
+ }
+}
+
+
+static bool test_AddPrinterDriver_exp(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ const char *servername,
+ struct spoolss_AddDriverInfoCtr *info_ctr,
+ WERROR expected_result)
+{
+ struct spoolss_AddPrinterDriver r;
+ const char *drivername = get_driver_from_info(info_ctr);
+ const char *environment = get_environment_from_info(info_ctr);
+
+ r.in.servername = servername;
+ r.in.info_ctr = info_ctr;
+
+ torture_comment(tctx, "Testing AddPrinterDriver(%s) level: %d, environment: '%s'\n",
+ drivername, info_ctr->level, environment);
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_spoolss_AddPrinterDriver_r(b, tctx, &r),
+ "spoolss_AddPrinterDriver failed");
+ torture_assert_werr_equal(tctx, r.out.result, expected_result,
+ "spoolss_AddPrinterDriver failed with unexpected result");
+
+ return true;
+
+}
+
+static bool test_AddPrinterDriverEx_exp(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ const char *servername,
+ struct spoolss_AddDriverInfoCtr *info_ctr,
+ uint32_t flags,
+ WERROR expected_result)
+{
+ struct spoolss_AddPrinterDriverEx r;
+ const char *drivername = get_driver_from_info(info_ctr);
+ const char *environment = get_environment_from_info(info_ctr);
+
+ r.in.servername = servername;
+ r.in.info_ctr = info_ctr;
+ r.in.flags = flags;
+
+ torture_comment(tctx, "Testing AddPrinterDriverEx(%s) level: %d, environment: '%s'\n",
+ drivername, info_ctr->level, environment);
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_spoolss_AddPrinterDriverEx_r(b, tctx, &r),
+ "AddPrinterDriverEx failed");
+ torture_assert_werr_equal(tctx, r.out.result, expected_result,
+ "AddPrinterDriverEx failed with unexpected result");
+
+ return true;
+}
+
+static bool test_AddPrinterDriver_args_level_1(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ const char *server_name,
+ struct spoolss_AddDriverInfo8 *r,
+ uint32_t flags,
+ bool ex)
+{
+ struct spoolss_AddDriverInfoCtr info_ctr;
+ struct spoolss_AddDriverInfo1 info1;
+
+ ZERO_STRUCT(info1);
+
+ info_ctr.level = 1;
+ info_ctr.info.info1 = &info1;
+
+ if (ex) {
+ torture_assert(tctx,
+ test_AddPrinterDriverEx_exp(tctx, b, server_name, &info_ctr, flags, WERR_UNKNOWN_LEVEL),
+ "failed to test AddPrinterDriverEx level 1");
+ } else {
+ torture_assert(tctx,
+ test_AddPrinterDriver_exp(tctx, b, server_name, &info_ctr, WERR_UNKNOWN_LEVEL),
+ "failed to test AddPrinterDriver level 1");
+ }
+
+ info1.driver_name = r->driver_name;
+
+ if (ex) {
+ torture_assert(tctx,
+ test_AddPrinterDriverEx_exp(tctx, b, server_name, &info_ctr, flags, WERR_UNKNOWN_LEVEL),
+ "failed to test AddPrinterDriverEx level 1");
+ } else {
+ torture_assert(tctx,
+ test_AddPrinterDriver_exp(tctx, b, server_name, &info_ctr, WERR_UNKNOWN_LEVEL),
+ "failed to test AddPrinterDriver level 1");
+ }
+
+ return true;
+}
+
+static bool test_AddPrinterDriver_args_level_2(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ const char *server_name,
+ struct spoolss_AddDriverInfo8 *r,
+ uint32_t flags,
+ bool ex)
+{
+ struct spoolss_AddDriverInfoCtr info_ctr;
+ struct spoolss_AddDriverInfo2 info2;
+
+ ZERO_STRUCT(info2);
+
+ info_ctr.level = 2;
+ info_ctr.info.info2 = &info2;
+
+ if (ex) {
+ torture_assert(tctx,
+ test_AddPrinterDriverEx_exp(tctx, b, server_name, &info_ctr, flags, WERR_INVALID_PARAM),
+ "failed to test AddPrinterDriverEx level 2");
+ } else {
+ torture_assert(tctx,
+ test_AddPrinterDriver_exp(tctx, b, server_name, &info_ctr, WERR_INVALID_PARAM),
+ "failed to test AddPrinterDriver level 2");
+ }
+
+ info2.driver_name = r->driver_name;
+
+ if (ex) {
+ torture_assert(tctx,
+ test_AddPrinterDriverEx_exp(tctx, b, server_name, &info_ctr, flags, WERR_INVALID_PARAM),
+ "failed to test AddPrinterDriverEx level 2");
+ } else {
+ torture_assert(tctx,
+ test_AddPrinterDriver_exp(tctx, b, server_name, &info_ctr, WERR_INVALID_PARAM),
+ "failed to test AddPrinterDriver level 2");
+ }
+
+ info2.version = r->version;
+
+ if (ex) {
+ torture_assert(tctx,
+ test_AddPrinterDriverEx_exp(tctx, b, server_name, &info_ctr, flags, WERR_INVALID_PARAM),
+ "failed to test AddPrinterDriverEx level 2");
+ } else {
+ torture_assert(tctx,
+ test_AddPrinterDriver_exp(tctx, b, server_name, &info_ctr, WERR_INVALID_PARAM),
+ "failed to test AddPrinterDriver level 2");
+ }
+
+ info2.architecture = r->architecture;
+
+ if (ex) {
+ torture_assert(tctx,
+ test_AddPrinterDriverEx_exp(tctx, b, server_name, &info_ctr, flags, WERR_INVALID_PARAM),
+ "failed to test AddPrinterDriverEx level 2");
+ } else {
+ torture_assert(tctx,
+ test_AddPrinterDriver_exp(tctx, b, server_name, &info_ctr, WERR_INVALID_PARAM),
+ "failed to test AddPrinterDriver level 2");
+ }
+
+ info2.driver_path = r->driver_path;
+
+ if (ex) {
+ torture_assert(tctx,
+ test_AddPrinterDriverEx_exp(tctx, b, server_name, &info_ctr, flags, WERR_INVALID_PARAM),
+ "failed to test AddPrinterDriverEx level 2");
+ } else {
+ torture_assert(tctx,
+ test_AddPrinterDriver_exp(tctx, b, server_name, &info_ctr, WERR_INVALID_PARAM),
+ "failed to test AddPrinterDriver level 2");
+ }
+
+ info2.data_file = r->data_file;
+
+ if (ex) {
+ torture_assert(tctx,
+ test_AddPrinterDriverEx_exp(tctx, b, server_name, &info_ctr, flags, WERR_INVALID_PARAM),
+ "failed to test AddPrinterDriverEx level 2");
+ } else {
+ torture_assert(tctx,
+ test_AddPrinterDriver_exp(tctx, b, server_name, &info_ctr, WERR_INVALID_PARAM),
+ "failed to test AddPrinterDriver level 2");
+ }
+
+ info2.config_file = r->config_file;
+
+ if (ex) {
+ torture_assert(tctx,
+ test_AddPrinterDriverEx_exp(tctx, b, server_name, &info_ctr, 0, WERR_INVALID_PARAM),
+ "failed to test AddPrinterDriverEx");
+ }
+
+ if (ex) {
+ torture_assert(tctx,
+ test_AddPrinterDriverEx_exp(tctx, b, server_name, &info_ctr, flags, WERR_OK),
+ "failed to test AddPrinterDriverEx level 2");
+ } else {
+ torture_assert(tctx,
+ test_AddPrinterDriver_exp(tctx, b, server_name, &info_ctr, WERR_OK),
+ "failed to test AddPrinterDriver level 2");
+ }
+
+ torture_assert(tctx,
+ test_EnumPrinterDrivers_findone(tctx, b, server_name, r->architecture, 2, r->driver_name),
+ "failed to find added printer driver");
+
+ return true;
+}
+
+static bool test_AddPrinterDriver_args_level_3(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ const char *server_name,
+ struct spoolss_AddDriverInfo8 *r,
+ uint32_t flags,
+ bool ex)
+{
+ struct spoolss_AddDriverInfoCtr info_ctr;
+ struct spoolss_AddDriverInfo3 info3;
+
+ info3.driver_name = r->driver_name;
+ info3.version = r->version;
+ info3.architecture = r->architecture;
+ info3.driver_path = r->driver_path;
+ info3.data_file = r->data_file;
+ info3.config_file = r->config_file;
+ info3.help_file = r->help_file;
+ info3.monitor_name = r->monitor_name;
+ info3.default_datatype = r->default_datatype;
+ info3._ndr_size_dependent_files = r->_ndr_size_dependent_files;
+ info3.dependent_files = r->dependent_files;
+
+ info_ctr.level = 3;
+ info_ctr.info.info3 = &info3;
+
+ if (ex) {
+ torture_assert(tctx,
+ test_AddPrinterDriverEx_exp(tctx, b, server_name, &info_ctr, flags, WERR_OK),
+ "failed to test AddPrinterDriverEx level 3");
+ } else {
+ torture_assert(tctx,
+ test_AddPrinterDriver_exp(tctx, b, server_name, &info_ctr, WERR_OK),
+ "failed to test AddPrinterDriver level 3");
+ }
+
+ torture_assert(tctx,
+ test_EnumPrinterDrivers_findone(tctx, b, server_name, r->architecture, 3, r->driver_name),
+ "failed to find added printer driver");
+
+ return true;
+}
+
+static bool test_AddPrinterDriver_args_level_4(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ const char *server_name,
+ struct spoolss_AddDriverInfo8 *r,
+ uint32_t flags,
+ bool ex)
+{
+ struct spoolss_AddDriverInfoCtr info_ctr;
+ struct spoolss_AddDriverInfo4 info4;
+
+ info4.version = r->version;
+ info4.driver_name = r->driver_name;
+ info4.architecture = r->architecture;
+ info4.driver_path = r->driver_path;
+ info4.data_file = r->data_file;
+ info4.config_file = r->config_file;
+ info4.help_file = r->help_file;
+ info4.monitor_name = r->monitor_name;
+ info4.default_datatype = r->default_datatype;
+ info4._ndr_size_dependent_files = r->_ndr_size_dependent_files;
+ info4.dependent_files = r->dependent_files;
+ info4._ndr_size_previous_names = r->_ndr_size_previous_names;
+ info4.previous_names = r->previous_names;
+
+ info_ctr.level = 4;
+ info_ctr.info.info4 = &info4;
+
+ if (ex) {
+ torture_assert(tctx,
+ test_AddPrinterDriverEx_exp(tctx, b, server_name, &info_ctr, flags, WERR_OK),
+ "failed to test AddPrinterDriverEx level 4");
+ } else {
+ torture_assert(tctx,
+ test_AddPrinterDriver_exp(tctx, b, server_name, &info_ctr, WERR_OK),
+ "failed to test AddPrinterDriver level 4");
+ }
+
+ torture_assert(tctx,
+ test_EnumPrinterDrivers_findone(tctx, b, server_name, r->architecture, 4, r->driver_name),
+ "failed to find added printer driver");
+
+ return true;
+}
+
+static bool test_AddPrinterDriver_args_level_6(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ const char *server_name,
+ struct spoolss_AddDriverInfo8 *r,
+ uint32_t flags,
+ bool ex)
+{
+ struct spoolss_AddDriverInfoCtr info_ctr;
+ struct spoolss_AddDriverInfo6 info6;
+
+ info6.version = r->version;
+ info6.driver_name = r->driver_name;
+ info6.architecture = r->architecture;
+ info6.driver_path = r->driver_path;
+ info6.data_file = r->data_file;
+ info6.config_file = r->config_file;
+ info6.help_file = r->help_file;
+ info6.monitor_name = r->monitor_name;
+ info6.default_datatype = r->default_datatype;
+ info6._ndr_size_dependent_files = r->_ndr_size_dependent_files;
+ info6.dependent_files = r->dependent_files;
+ info6._ndr_size_previous_names = r->_ndr_size_previous_names;
+ info6.previous_names = r->previous_names;
+ info6.driver_date = r->driver_date;
+ info6.driver_version = r->driver_version;
+ info6.manufacturer_name = r->manufacturer_name;
+ info6.manufacturer_url = r->manufacturer_url;
+ info6.hardware_id = r->hardware_id;
+ info6.provider = r->provider;
+
+ info_ctr.level = 6;
+ info_ctr.info.info6 = &info6;
+
+ if (ex) {
+ torture_assert(tctx,
+ test_AddPrinterDriverEx_exp(tctx, b, server_name, &info_ctr, flags, WERR_OK),
+ "failed to test AddPrinterDriverEx level 6");
+ } else {
+ torture_assert(tctx,
+ test_AddPrinterDriver_exp(tctx, b, server_name, &info_ctr, WERR_UNKNOWN_LEVEL),
+ "failed to test AddPrinterDriver level 6");
+ }
+
+ /* spoolss_AddPrinterDriver does not deal with level 6 or 8 - gd */
+
+ if (!ex) {
+ return true;
+ }
+
+ torture_assert(tctx,
+ test_EnumPrinterDrivers_findone(tctx, b, server_name, r->architecture, 6, r->driver_name),
+ "failed to find added printer driver");
+
+ return true;
+}
+
+static bool test_AddPrinterDriver_args_level_8(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ const char *server_name,
+ struct spoolss_AddDriverInfo8 *r,
+ uint32_t flags,
+ bool ex)
+{
+ struct spoolss_AddDriverInfoCtr info_ctr;
+
+ info_ctr.level = 8;
+ info_ctr.info.info8 = r;
+
+ if (ex) {
+ torture_assert(tctx,
+ test_AddPrinterDriverEx_exp(tctx, b, server_name, &info_ctr, flags, WERR_OK),
+ "failed to test AddPrinterDriverEx level 8");
+ } else {
+ torture_assert(tctx,
+ test_AddPrinterDriver_exp(tctx, b, server_name, &info_ctr, WERR_UNKNOWN_LEVEL),
+ "failed to test AddPrinterDriver level 8");
+ }
+
+ /* spoolss_AddPrinterDriver does not deal with level 6 or 8 - gd */
+
+ if (!ex) {
+ return true;
+ }
+
+ torture_assert(tctx,
+ test_EnumPrinterDrivers_findone(tctx, b, server_name, r->architecture, 8, r->driver_name),
+ "failed to find added printer driver");
+
+ return true;
+}
+
+static bool test_DeletePrinterDriver_exp(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ const char *server,
+ const char *driver,
+ const char *environment,
+ WERROR expected_result)
+{
+ struct spoolss_DeletePrinterDriver r;
+
+ r.in.server = server;
+ r.in.architecture = environment;
+ r.in.driver = driver;
+
+ torture_comment(tctx, "Testing DeletePrinterDriver(%s)\n", driver);
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_spoolss_DeletePrinterDriver_r(b, tctx, &r),
+ "DeletePrinterDriver failed");
+ torture_assert_werr_equal(tctx, r.out.result, expected_result,
+ "DeletePrinterDriver failed with unexpected result");
+
+ return true;
+}
+
+static bool test_DeletePrinterDriverEx_exp(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ const char *server,
+ const char *driver,
+ const char *environment,
+ uint32_t delete_flags,
+ uint32_t version,
+ WERROR expected_result)
+{
+ struct spoolss_DeletePrinterDriverEx r;
+
+ r.in.server = server;
+ r.in.architecture = environment;
+ r.in.driver = driver;
+ r.in.delete_flags = delete_flags;
+ r.in.version = version;
+
+ torture_comment(tctx, "Testing DeletePrinterDriverEx(%s)\n", driver);
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_spoolss_DeletePrinterDriverEx_r(b, tctx, &r),
+ "DeletePrinterDriverEx failed");
+ torture_assert_werr_equal(tctx, r.out.result, expected_result,
+ "DeletePrinterDriverEx failed with unexpected result");
+
+ return true;
+}
+
+static bool test_DeletePrinterDriver(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ const char *server_name,
+ const char *driver,
+ const char *environment)
+{
+ torture_assert(tctx,
+ test_DeletePrinterDriver_exp(tctx, b, server_name, driver, "FOOBAR", WERR_INVALID_ENVIRONMENT),
+ "failed to delete driver");
+
+ torture_assert(tctx,
+ test_DeletePrinterDriver_exp(tctx, b, server_name, driver, environment, WERR_OK),
+ "failed to delete driver");
+
+ if (test_EnumPrinterDrivers_findone(tctx, b, server_name, environment, 1, driver)) {
+ torture_fail(tctx, "deleted driver still enumerated");
+ }
+
+ torture_assert(tctx,
+ test_DeletePrinterDriver_exp(tctx, b, server_name, driver, environment, WERR_UNKNOWN_PRINTER_DRIVER),
+ "2nd delete failed");
+
+ return true;
+}
+
+static bool test_DeletePrinterDriverEx(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ const char *server_name,
+ const char *driver,
+ const char *environment,
+ uint32_t delete_flags,
+ uint32_t version)
+{
+ torture_assert(tctx,
+ test_DeletePrinterDriverEx_exp(tctx, b, server_name, driver, "FOOBAR", delete_flags, version, WERR_INVALID_ENVIRONMENT),
+ "failed to delete driver");
+
+ torture_assert(tctx,
+ test_DeletePrinterDriverEx_exp(tctx, b, server_name, driver, environment, delete_flags, version, WERR_OK),
+ "failed to delete driver");
+
+ if (test_EnumPrinterDrivers_findone(tctx, b, server_name, environment, 1, driver)) {
+ torture_fail(tctx, "deleted driver still enumerated");
+ }
+
+ torture_assert(tctx,
+ test_DeletePrinterDriverEx_exp(tctx, b, server_name, driver, environment, delete_flags, version, WERR_UNKNOWN_PRINTER_DRIVER),
+ "2nd delete failed");
+
+ return true;
+}
+
+static bool test_PrinterDriver_args(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ const char *server_name,
+ uint32_t level,
+ struct spoolss_AddDriverInfo8 *r,
+ uint32_t add_flags,
+ uint32_t delete_flags,
+ uint32_t delete_version,
+ bool ex)
+{
+ bool ret = true;
+
+ switch (level) {
+ case 1:
+ ret = test_AddPrinterDriver_args_level_1(tctx, b, server_name, r, add_flags, ex);
+ break;
+ case 2:
+ ret = test_AddPrinterDriver_args_level_2(tctx, b, server_name, r, add_flags, ex);
+ break;
+ case 3:
+ ret = test_AddPrinterDriver_args_level_3(tctx, b, server_name, r, add_flags, ex);
+ break;
+ case 4:
+ ret = test_AddPrinterDriver_args_level_4(tctx, b, server_name, r, add_flags, ex);
+ break;
+ case 6:
+ ret = test_AddPrinterDriver_args_level_6(tctx, b, server_name, r, add_flags, ex);
+ break;
+ case 8:
+ ret = test_AddPrinterDriver_args_level_8(tctx, b, server_name, r, add_flags, ex);
+ break;
+ default:
+ return false;
+ }
+
+ if (ret == false) {
+ return ret;
+ }
+
+ if (level == 1) {
+ return ret;
+ }
+
+ /* spoolss_AddPrinterDriver does not deal with level 6 or 8 - gd */
+
+ if (!ex && (level == 6 || level == 8)) {
+ return ret;
+ }
+
+ if (ex) {
+ return test_DeletePrinterDriverEx(tctx, b, server_name, r->driver_name, r->architecture, delete_flags, r->version);
+ } else {
+ return test_DeletePrinterDriver(tctx, b, server_name, r->driver_name, r->architecture);
+ }
+}
+
+static bool fillup_printserver_info(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ struct torture_driver_context *d)
+{
+ struct policy_handle server_handle;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ const char *server_name_slash = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
+
+ torture_assert(tctx,
+ test_OpenPrinter_server(tctx, p, &server_handle),
+ "failed to open printserver");
+ torture_assert(tctx,
+ test_get_environment(tctx, b, &server_handle, &d->remote.environment),
+ "failed to get environment");
+ torture_assert(tctx,
+ test_ClosePrinter(tctx, b, &server_handle),
+ "failed to close printserver");
+
+ torture_assert(tctx,
+ test_GetPrinterDriverDirectory_getdir(tctx, b, server_name_slash,
+ d->local.environment ? d->local.environment : d->remote.environment,
+ &d->remote.driver_directory),
+ "failed to get driver directory");
+
+ return true;
+}
+
+static const char *driver_directory_dir(const char *driver_directory)
+{
+ char *p;
+
+ p = strrchr(driver_directory, '\\');
+ if (p) {
+ return p+1;
+ }
+
+ return NULL;
+}
+
+static const char *driver_directory_share(struct torture_context *tctx,
+ const char *driver_directory)
+{
+ const char *p;
+ char *tok;
+
+ if (driver_directory[0] == '\\' && driver_directory[1] == '\\') {
+ driver_directory += 2;
+ }
+
+ p = talloc_strdup(tctx, driver_directory);
+
+ torture_assert(tctx,
+ next_token_talloc(tctx, &p, &tok, "\\"),
+ "cannot explode uri");
+ torture_assert(tctx,
+ next_token_talloc(tctx, &p, &tok, "\\"),
+ "cannot explode uri");
+
+ return tok;
+}
+
+static bool upload_printer_driver_file(struct torture_context *tctx,
+ struct smbcli_state *cli,
+ struct torture_driver_context *d,
+ const char *file_name)
+{
+ XFILE *f;
+ int fnum;
+ uint8_t *buf;
+ int maxwrite = 64512;
+ off_t nread = 0;
+ size_t start = 0;
+ const char *remote_dir = driver_directory_dir(d->remote.driver_directory);
+ const char *local_name = talloc_asprintf(tctx, "%s/%s", d->local.driver_directory, file_name);
+ const char *remote_name = talloc_asprintf(tctx, "%s\\%s", remote_dir, file_name);
+
+ if (!file_name) {
+ return true;
+ }
+
+ torture_comment(tctx, "Uploading %s to %s\n", local_name, remote_name);
+
+ fnum = smbcli_open(cli->tree, remote_name, O_RDWR|O_CREAT|O_TRUNC, DENY_NONE);
+ if (fnum == -1) {
+ torture_fail(tctx, talloc_asprintf(tctx, "failed to open remote file: %s\n", remote_name));
+ }
+
+ f = x_fopen(local_name, O_RDONLY, 0);
+ if (f == NULL) {
+ torture_fail(tctx, talloc_asprintf(tctx, "failed to open local file: %s\n", local_name));
+ }
+
+ buf = talloc_array(tctx, uint8_t, maxwrite);
+ if (!buf) {
+ return false;
+ }
+
+ while (!x_feof(f)) {
+ int n = maxwrite;
+ int ret;
+
+ if ((n = x_fread(buf, 1, n, f)) < 1) {
+ if((n == 0) && x_feof(f))
+ break; /* Empty local file. */
+
+ torture_warning(tctx,
+ "failed to read file: %s\n", strerror(errno));
+ break;
+ }
+
+ ret = smbcli_write(cli->tree, fnum, 0, buf, nread + start, n);
+
+ if (n != ret) {
+ torture_warning(tctx,
+ "failed to write file: %s\n", smbcli_errstr(cli->tree));
+ break;
+ }
+
+ nread += n;
+ }
+
+ x_fclose(f);
+
+ torture_assert_ntstatus_ok(tctx,
+ smbcli_close(cli->tree, fnum),
+ "failed to close file");
+
+ return true;
+}
+
+static bool connect_printer_driver_share(struct torture_context *tctx,
+ const char *server_name,
+ const char *share_name,
+ struct smbcli_state **cli)
+{
+ struct smbcli_options smb_options;
+ struct smbcli_session_options smb_session_options;
+
+ torture_comment(tctx, "Connecting printer driver share '%s' on '%s'\n",
+ share_name, server_name);
+
+ lp_smbcli_options(tctx->lp_ctx, &smb_options);
+ lp_smbcli_session_options(tctx->lp_ctx, &smb_session_options);
+
+ torture_assert_ntstatus_ok(tctx,
+ smbcli_full_connection(tctx, cli, server_name,
+ lp_smb_ports(tctx->lp_ctx),
+ share_name, NULL,
+ lp_socket_options(tctx->lp_ctx),
+ cmdline_credentials,
+ lp_resolve_context(tctx->lp_ctx),
+ tctx->ev,
+ &smb_options,
+ &smb_session_options,
+ lp_iconv_convenience(tctx->lp_ctx),
+ lp_gensec_settings(tctx, tctx->lp_ctx)),
+ "failed to open driver share");
+
+ return true;
+}
+
+static bool upload_printer_driver(struct torture_context *tctx,
+ const char *server_name,
+ struct torture_driver_context *d)
+{
+ 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, "Uploading printer driver files to \\\\%s\\%s\n",
+ server_name, share_name);
+
+ torture_assert(tctx,
+ upload_printer_driver_file(tctx, cli, d, d->info8.driver_path),
+ "failed to upload driver_path");
+ torture_assert(tctx,
+ upload_printer_driver_file(tctx, cli, d, d->info8.data_file),
+ "failed to upload data_file");
+ torture_assert(tctx,
+ upload_printer_driver_file(tctx, cli, d, d->info8.config_file),
+ "failed to upload config_file");
+ torture_assert(tctx,
+ upload_printer_driver_file(tctx, cli, d, d->info8.help_file),
+ "failed to upload help_file");
+ if (d->info8.dependent_files) {
+ for (i=0; d->info8.dependent_files->string && d->info8.dependent_files->string[i] != NULL; i++) {
+ torture_assert(tctx,
+ upload_printer_driver_file(tctx, cli, d, d->info8.dependent_files->string[i]),
+ "failed to upload dependent_files");
+ }
+ }
+
+ talloc_free(cli);
+
+ return true;
+}
+
+static bool remove_printer_driver_file(struct torture_context *tctx,
+ struct smbcli_state *cli,
+ struct torture_driver_context *d,
+ const char *file_name)
+{
+ const char *remote_name;
+ const char *remote_dir = driver_directory_dir(d->remote.driver_directory);
+
+ if (!file_name) {
+ return true;
+ }
+
+ remote_name = talloc_asprintf(tctx, "%s\\%s", remote_dir, file_name);
+
+ torture_comment(tctx, "Removing %s\n", remote_name);
+
+ torture_assert_ntstatus_ok(tctx,
+ smbcli_unlink(cli->tree, remote_name),
+ "failed to unlink");
+
+ return true;
+}
+
+static bool remove_printer_driver(struct torture_context *tctx,
+ const char *server_name,
+ struct torture_driver_context *d)
+{
+ 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, "Removing printer driver files from \\\\%s\\%s\n",
+ server_name, share_name);
+
+ torture_assert(tctx,
+ remove_printer_driver_file(tctx, cli, d, d->info8.driver_path),
+ "failed to remove driver_path");
+ torture_assert(tctx,
+ remove_printer_driver_file(tctx, cli, d, d->info8.data_file),
+ "failed to remove data_file");
+ torture_assert(tctx,
+ remove_printer_driver_file(tctx, cli, d, d->info8.config_file),
+ "failed to remove config_file");
+ torture_assert(tctx,
+ remove_printer_driver_file(tctx, cli, d, d->info8.help_file),
+ "failed to remove help_file");
+ if (d->info8.dependent_files) {
+ for (i=0; d->info8.dependent_files->string && d->info8.dependent_files->string[i] != NULL; i++) {
+ if (strequal(d->info8.dependent_files->string[i], d->info8.driver_path) ||
+ strequal(d->info8.dependent_files->string[i], d->info8.data_file) ||
+ strequal(d->info8.dependent_files->string[i], d->info8.config_file) ||
+ strequal(d->info8.dependent_files->string[i], d->info8.help_file)) {
+ continue;
+ }
+ torture_assert(tctx,
+ remove_printer_driver_file(tctx, cli, d, d->info8.dependent_files->string[i]),
+ "failed to remove dependent_files");
+ }
+ }
+
+ talloc_free(cli);
+
+ return true;
+
+}
+
+static bool test_add_driver_arg(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ struct torture_driver_context *d)
+{
+ bool ret = true;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ const char *server_name_slash = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
+ uint32_t levels[] = { 1, 2, 3, 4, 6, 8 };
+ int i;
+ struct spoolss_AddDriverInfo8 info8;
+ uint32_t add_flags = APD_COPY_NEW_FILES;
+ uint32_t delete_flags = 0;
+
+ torture_comment(tctx, "Testing PrinterDriver%s '%s' for environment '%s'\n",
+ d->ex ? "Ex" : "", d->info8.driver_name, 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");
+
+ 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;
+
+ for (i=0; i < ARRAY_SIZE(levels); i++) {
+
+ if (torture_setting_bool(tctx, "samba3", false)) {
+ switch (levels[i]) {
+ case 2:
+ case 4:
+ case 8:
+ torture_comment(tctx, "skipping level %d against samba\n", levels[i]);
+ continue;
+ default:
+ break;
+ }
+ }
+
+ torture_comment(tctx,
+ "Testing PrinterDriver%s '%s' add & delete level %d\n",
+ d->ex ? "Ex" : "", info8.driver_name, levels[i]);
+
+ ret &= test_PrinterDriver_args(tctx, b, server_name_slash, levels[i], &info8, add_flags, delete_flags, d->info8.version, d->ex);
+ }
+
+ info8.driver_path = talloc_asprintf(tctx, "%s\\%s", d->remote.driver_directory, d->info8.driver_path);
+ info8.data_file = talloc_asprintf(tctx, "%s\\%s", d->remote.driver_directory, d->info8.data_file);
+ info8.config_file = talloc_asprintf(tctx, "%s\\%s", d->remote.driver_directory, d->info8.config_file);
+
+ for (i=0; i < ARRAY_SIZE(levels); i++) {
+
+ if (torture_setting_bool(tctx, "samba3", false)) {
+ switch (levels[i]) {
+ case 2:
+ case 4:
+ case 8:
+ torture_comment(tctx, "skipping level %d against samba\n", levels[i]);
+ continue;
+ default:
+ break;
+ }
+ }
+
+
+ torture_comment(tctx,
+ "Testing PrinterDriver%s '%s' add & delete level %d (full unc paths)\n",
+ d->ex ? "Ex" : "", info8.driver_name, levels[i]);
+
+ ret &= test_PrinterDriver_args(tctx, b, server_name_slash, levels[i], &info8, add_flags, delete_flags, d->info8.version, d->ex);
+ }
+
+ torture_assert(tctx,
+ remove_printer_driver(tctx, dcerpc_server_name(p), d),
+ "failed to remove printer driver");
+
+ torture_comment(tctx, "\n");
+
+ return ret;
+}
+
+static bool test_add_driver_ex_64(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ void *private_data)
+{
+ struct torture_driver_context *d =
+ (struct torture_driver_context *)talloc_get_type_abort(private_data, struct torture_driver_context);
+
+ d->local.environment = talloc_strdup(d, "Windows x64");
+ d->local.driver_directory = talloc_strdup(d, "/usr/share/cups/drivers/x64");
+ d->info8.driver_name = TORTURE_DRIVER_EX;
+ d->ex = true;
+
+ return test_add_driver_arg(tctx, p, d);
+}
+
+static bool test_add_driver_ex_32(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ void *private_data)
+{
+ struct torture_driver_context *d =
+ (struct torture_driver_context *)talloc_get_type_abort(private_data, struct torture_driver_context);
+
+ d->local.environment = talloc_strdup(d, "Windows NT x86");
+ d->local.driver_directory = talloc_strdup(d, "/usr/share/cups/drivers/i386");
+ d->info8.driver_name = TORTURE_DRIVER_EX;
+ d->ex = true;
+
+ return test_add_driver_arg(tctx, p, d);
+}
+
+static bool test_add_driver_64(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ void *private_data)
+{
+ struct torture_driver_context *d =
+ (struct torture_driver_context *)talloc_get_type_abort(private_data, struct torture_driver_context);
+
+ d->local.environment = talloc_strdup(d, "Windows x64");
+ d->local.driver_directory = talloc_strdup(d, "/usr/share/cups/drivers/x64");
+ d->info8.driver_name = TORTURE_DRIVER;
+ d->ex = false;
+
+ return test_add_driver_arg(tctx, p, d);
+}
+
+static bool test_add_driver_32(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ void *private_data)
+{
+ struct torture_driver_context *d =
+ (struct torture_driver_context *)talloc_get_type_abort(private_data, struct torture_driver_context);
+
+ d->local.environment = talloc_strdup(d, "Windows NT x86");
+ d->local.driver_directory = talloc_strdup(d, "/usr/share/cups/drivers/i386");
+ d->info8.driver_name = TORTURE_DRIVER;
+ d->ex = false;
+
+ return test_add_driver_arg(tctx, p, d);
+}
+
+struct torture_suite *torture_rpc_spoolss_driver(TALLOC_CTX *mem_ctx)
+{
+ struct torture_suite *suite = torture_suite_create(mem_ctx, "SPOOLSS-DRIVER");
+
+ struct torture_rpc_tcase *tcase = torture_suite_add_rpc_iface_tcase(suite,
+ "driver", &ndr_table_spoolss);
+ struct torture_driver_context *t;
+
+ t = talloc_zero(mem_ctx, struct torture_driver_context);
+
+ t->info8.version = SPOOLSS_DRIVER_VERSION_200X;
+ t->info8.driver_name = NULL;
+ t->info8.architecture = NULL;
+ t->info8.driver_path = talloc_strdup(t, "pscript5.dll");
+ t->info8.data_file = talloc_strdup(t, "cups6.ppd");
+ t->info8.config_file = talloc_strdup(t, "cupsui6.dll");
+
+ torture_rpc_tcase_add_test_ex(tcase, "add_driver_64", test_add_driver_64, t);
+ torture_rpc_tcase_add_test_ex(tcase, "add_driver_ex_64", test_add_driver_ex_64, t);
+
+ torture_rpc_tcase_add_test_ex(tcase, "add_driver_32", test_add_driver_32, t);
+ torture_rpc_tcase_add_test_ex(tcase, "add_driver_ex_32", test_add_driver_ex_32, t);
return suite;
}