s4-smbtorture: skip driverName and printerName DsSpooler tests for now.
[Samba/ekacnet.git] / source4 / torture / rpc / spoolss.c
blob07b799416f1b68f6174ba3b7e8c85efb1e2ca3b7
1 /*
2 Unix SMB/CIFS implementation.
3 test suite for spoolss rpc operations
5 Copyright (C) Tim Potter 2003
6 Copyright (C) Stefan Metzmacher 2005
7 Copyright (C) Jelmer Vernooij 2007
8 Copyright (C) Guenther Deschner 2009-2010
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 3 of the License, or
13 (at your option) any later version.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program. If not, see <http://www.gnu.org/licenses/>.
24 #include "includes.h"
25 #include "torture/torture.h"
26 #include "librpc/gen_ndr/ndr_misc.h"
27 #include "librpc/gen_ndr/ndr_spoolss.h"
28 #include "librpc/gen_ndr/ndr_spoolss_c.h"
29 #include "librpc/gen_ndr/ndr_winreg_c.h"
30 #include "librpc/gen_ndr/ndr_security.h"
31 #include "libcli/security/security.h"
32 #include "torture/rpc/torture_rpc.h"
33 #include "param/param.h"
34 #include "lib/registry/registry.h"
35 #include "libcli/libcli.h"
36 #include "libcli/raw/raw_proto.h"
37 #include "libcli/resolve/resolve.h"
38 #include "lib/cmdline/popt_common.h"
39 #include "system/filesys.h"
41 #define TORTURE_WELLKNOWN_PRINTER "torture_wkn_printer"
42 #define TORTURE_PRINTER "torture_printer"
43 #define TORTURE_WELLKNOWN_PRINTER_EX "torture_wkn_printer_ex"
44 #define TORTURE_PRINTER_EX "torture_printer_ex"
45 #define TORTURE_DRIVER "torture_driver"
46 #define TORTURE_DRIVER_EX "torture_driver_ex"
48 #define TOP_LEVEL_PRINT_KEY "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Print"
49 #define TOP_LEVEL_PRINT_PRINTERS_KEY TOP_LEVEL_PRINT_KEY "\\Printers"
50 #define TOP_LEVEL_CONTROL_KEY "SYSTEM\\CurrentControlSet\\Control\\Print"
51 #define TOP_LEVEL_CONTROL_FORMS_KEY TOP_LEVEL_CONTROL_KEY "\\Forms"
52 #define TOP_LEVEL_CONTROL_PRINTERS_KEY TOP_LEVEL_CONTROL_KEY "\\Printers"
53 #define TOP_LEVEL_CONTROL_ENVIRONMENTS_KEY TOP_LEVEL_CONTROL_KEY "\\Environments"
55 struct test_spoolss_context {
56 /* print server handle */
57 struct policy_handle server_handle;
59 /* for EnumPorts */
60 uint32_t port_count[3];
61 union spoolss_PortInfo *ports[3];
63 /* for EnumPrinterDrivers */
64 uint32_t driver_count[8];
65 union spoolss_DriverInfo *drivers[8];
67 /* for EnumMonitors */
68 uint32_t monitor_count[3];
69 union spoolss_MonitorInfo *monitors[3];
71 /* for EnumPrintProcessors */
72 uint32_t print_processor_count[2];
73 union spoolss_PrintProcessorInfo *print_processors[2];
75 /* for EnumPrinters */
76 uint32_t printer_count[6];
77 union spoolss_PrinterInfo *printers[6];
80 struct torture_driver_context {
81 struct {
82 const char *driver_directory;
83 const char *environment;
84 } local;
85 struct {
86 const char *driver_directory;
87 const char *environment;
88 } remote;
89 struct spoolss_AddDriverInfo8 info8;
90 bool ex;
93 struct torture_printer_context {
94 struct spoolss_SetPrinterInfo2 info2;
95 struct torture_driver_context driver;
96 bool ex;
97 bool wellknown;
98 bool added_driver;
99 bool have_driver;
100 struct spoolss_DeviceMode *devmode;
103 static bool upload_printer_driver(struct torture_context *tctx,
104 const char *server_name,
105 struct torture_driver_context *d);
106 static bool remove_printer_driver(struct torture_context *tctx,
107 const char *server_name,
108 struct torture_driver_context *d);
109 static bool fillup_printserver_info(struct torture_context *tctx,
110 struct dcerpc_pipe *p,
111 struct torture_driver_context *d);
112 static bool test_AddPrinterDriver_args_level_3(struct torture_context *tctx,
113 struct dcerpc_binding_handle *b,
114 const char *server_name,
115 struct spoolss_AddDriverInfo8 *r,
116 uint32_t flags,
117 bool ex);
119 #define COMPARE_STRING(tctx, c,r,e) \
120 torture_assert_str_equal(tctx, c.e, r.e, "invalid value")
122 /* not every compiler supports __typeof__() */
123 #if (__GNUC__ >= 3)
124 #define _CHECK_FIELD_SIZE(c,r,e,type) do {\
125 if (sizeof(__typeof__(c.e)) != sizeof(type)) { \
126 torture_fail(tctx, #c "." #e "field is not " #type "\n"); \
128 if (sizeof(__typeof__(r.e)) != sizeof(type)) { \
129 torture_fail(tctx, #r "." #e "field is not " #type "\n"); \
131 } while(0)
132 #else
133 #define _CHECK_FIELD_SIZE(c,r,e,type) do {} while(0)
134 #endif
136 #define COMPARE_UINT32(tctx, c, r, e) do {\
137 _CHECK_FIELD_SIZE(c, r, e, uint32_t); \
138 torture_assert_int_equal(tctx, c.e, r.e, "invalid value"); \
139 } while(0)
141 #define COMPARE_UINT64(tctx, c, r, e) do {\
142 _CHECK_FIELD_SIZE(c, r, e, uint64_t); \
143 torture_assert_int_equal(tctx, c.e, r.e, "invalid value"); \
144 } while(0)
147 #define COMPARE_NTTIME(tctx, c, r, e) do {\
148 _CHECK_FIELD_SIZE(c, r, e, NTTIME); \
149 torture_assert_int_equal(tctx, c.e, r.e, "invalid value"); \
150 } while(0)
152 #define COMPARE_STRING_ARRAY(tctx, c,r,e) do {\
153 int __i; \
154 if (!c.e && !r.e) { \
155 break; \
157 if (c.e && !r.e) { \
158 torture_fail(tctx, #r "." #e " field is NULL and " #c "." #e " is not\n"); \
160 if (!c.e && r.e) { \
161 torture_fail(tctx, #c "." #e " field is NULL and " #r "." #e " is not\n"); \
163 for (__i=0;c.e[__i] != NULL; __i++) { \
164 torture_assert_str_equal(tctx, c.e[__i], r.e[__i], "invalid value"); \
166 } while(0)
168 #define CHECK_ALIGN(size, n) do {\
169 if (size % n) {\
170 torture_warning(tctx, "%d is *NOT* %d byte aligned, should be %d",\
171 size, n, size + n - (size % n));\
173 } while(0)
175 #define DO_ROUND(size, n) (((size)+((n)-1)) & ~((n)-1))
177 #define CHECK_NEEDED_SIZE_ENUM_LEVEL(fn, info, level, count, needed, align) do { \
178 if (torture_setting_bool(tctx, "spoolss_check_size", false)) {\
179 uint32_t size = ndr_size_##fn##_info(tctx, level, count, info);\
180 uint32_t round_size = DO_ROUND(size, align);\
181 if (round_size != needed) {\
182 torture_warning(tctx, __location__": "#fn" level %d (count: %d) got unexpected needed size: %d, we calculated: %d", level, count, needed, round_size);\
183 CHECK_ALIGN(size, align);\
186 } while(0)
188 #define CHECK_NEEDED_SIZE_ENUM(fn, info, count, needed, align) do { \
189 if (torture_setting_bool(tctx, "spoolss_check_size", false)) {\
190 uint32_t size = ndr_size_##fn##_info(tctx, count, info);\
191 uint32_t round_size = DO_ROUND(size, align);\
192 if (round_size != needed) {\
193 torture_warning(tctx, __location__": "#fn" (count: %d) got unexpected needed size: %d, we calculated: %d", count, needed, round_size);\
194 CHECK_ALIGN(size, align);\
197 } while(0)
199 #define CHECK_NEEDED_SIZE_LEVEL(fn, info, level, needed, align) do { \
200 if (torture_setting_bool(tctx, "spoolss_check_size", false)) {\
201 uint32_t size = ndr_size_##fn(info, level, 0);\
202 uint32_t round_size = DO_ROUND(size, align);\
203 if (round_size != needed) {\
204 torture_warning(tctx, __location__": "#fn" level %d got unexpected needed size: %d, we calculated: %d", level, needed, round_size);\
205 CHECK_ALIGN(size, align);\
208 } while(0)
210 static bool PrinterInfo_to_SetPrinterInfo(struct torture_context *tctx,
211 const union spoolss_PrinterInfo *i,
212 uint32_t level,
213 union spoolss_SetPrinterInfo *s)
215 switch (level) {
216 case 0:
217 s->info0 = talloc(tctx, struct spoolss_SetPrinterInfo0);
218 break;
219 case 2:
220 s->info2 = talloc(tctx, struct spoolss_SetPrinterInfo2);
221 s->info2->servername = i->info2.servername;
222 s->info2->printername = i->info2.printername;
223 s->info2->sharename = i->info2.sharename;
224 s->info2->portname = i->info2.portname;
225 s->info2->drivername = i->info2.drivername;
226 s->info2->comment = i->info2.comment;
227 s->info2->location = i->info2.location;
228 s->info2->devmode_ptr = 0;
229 s->info2->sepfile = i->info2.sepfile;
230 s->info2->printprocessor = i->info2.printprocessor;
231 s->info2->datatype = i->info2.datatype;
232 s->info2->parameters = i->info2.parameters;
233 s->info2->secdesc_ptr = 0;
234 s->info2->attributes = i->info2.attributes;
235 s->info2->priority = i->info2.priority;
236 s->info2->defaultpriority = i->info2.defaultpriority;
237 s->info2->starttime = i->info2.starttime;
238 s->info2->untiltime = i->info2.untiltime;
239 s->info2->status = i->info2.status;
240 s->info2->cjobs = i->info2.cjobs;
241 s->info2->averageppm = i->info2.averageppm;
242 break;
243 case 3:
244 case 4:
245 case 5:
246 case 6:
247 case 7:
248 case 8:
249 case 9:
250 default:
251 return false;
254 return true;
257 static bool test_OpenPrinter_server(struct torture_context *tctx,
258 struct dcerpc_pipe *p,
259 struct policy_handle *server_handle)
261 NTSTATUS status;
262 struct spoolss_OpenPrinter op;
263 struct dcerpc_binding_handle *b = p->binding_handle;
265 op.in.printername = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
266 op.in.datatype = NULL;
267 op.in.devmode_ctr.devmode= NULL;
268 op.in.access_mask = 0;
269 op.out.handle = server_handle;
271 torture_comment(tctx, "Testing OpenPrinter(%s)\n", op.in.printername);
273 status = dcerpc_spoolss_OpenPrinter_r(b, tctx, &op);
274 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_OpenPrinter failed");
275 torture_assert_werr_ok(tctx, op.out.result, "dcerpc_spoolss_OpenPrinter failed");
277 return true;
280 static bool test_EnumPorts(struct torture_context *tctx,
281 struct dcerpc_binding_handle *b,
282 struct test_spoolss_context *ctx)
284 NTSTATUS status;
285 struct spoolss_EnumPorts r;
286 uint16_t levels[] = { 1, 2 };
287 int i, j;
289 for (i=0;i<ARRAY_SIZE(levels);i++) {
290 int level = levels[i];
291 DATA_BLOB blob;
292 uint32_t needed;
293 uint32_t count;
294 union spoolss_PortInfo *info;
296 r.in.servername = "";
297 r.in.level = level;
298 r.in.buffer = NULL;
299 r.in.offered = 0;
300 r.out.needed = &needed;
301 r.out.count = &count;
302 r.out.info = &info;
304 torture_comment(tctx, "Testing EnumPorts level %u\n", r.in.level);
306 status = dcerpc_spoolss_EnumPorts_r(b, ctx, &r);
307 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EnumPorts failed");
308 if (W_ERROR_IS_OK(r.out.result)) {
309 /* TODO: do some more checks here */
310 continue;
312 torture_assert_werr_equal(tctx, r.out.result, WERR_INSUFFICIENT_BUFFER,
313 "EnumPorts unexpected return code");
315 blob = data_blob_talloc_zero(ctx, needed);
316 r.in.buffer = &blob;
317 r.in.offered = needed;
319 status = dcerpc_spoolss_EnumPorts_r(b, ctx, &r);
320 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EnumPorts failed");
322 torture_assert_werr_ok(tctx, r.out.result, "EnumPorts failed");
324 torture_assert(tctx, info, "EnumPorts returned no info");
326 CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumPorts, info, r.in.level, count, needed, 4);
328 ctx->port_count[level] = count;
329 ctx->ports[level] = info;
332 for (i=1;i<ARRAY_SIZE(levels);i++) {
333 int level = levels[i];
334 int old_level = levels[i-1];
335 torture_assert_int_equal(tctx, ctx->port_count[level], ctx->port_count[old_level],
336 "EnumPorts invalid value");
338 /* if the array sizes are not the same we would maybe segfault in the following code */
340 for (i=0;i<ARRAY_SIZE(levels);i++) {
341 int level = levels[i];
342 for (j=0;j<ctx->port_count[level];j++) {
343 union spoolss_PortInfo *cur = &ctx->ports[level][j];
344 union spoolss_PortInfo *ref = &ctx->ports[2][j];
345 switch (level) {
346 case 1:
347 COMPARE_STRING(tctx, cur->info1, ref->info2, port_name);
348 break;
349 case 2:
350 /* level 2 is our reference, and it makes no sense to compare it to itself */
351 break;
356 return true;
359 static bool test_GetPrintProcessorDirectory(struct torture_context *tctx,
360 struct dcerpc_pipe *p,
361 const char *environment)
363 NTSTATUS status;
364 struct dcerpc_binding_handle *b = p->binding_handle;
365 struct spoolss_GetPrintProcessorDirectory r;
366 struct {
367 uint16_t level;
368 const char *server;
369 } levels[] = {{
370 .level = 1,
371 .server = NULL
373 .level = 1,
374 .server = ""
376 .level = 78,
377 .server = ""
379 .level = 1,
380 .server = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p))
382 .level = 1024,
383 .server = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p))
386 int i;
387 uint32_t needed;
389 for (i=0;i<ARRAY_SIZE(levels);i++) {
390 int level = levels[i].level;
391 DATA_BLOB blob;
393 r.in.server = levels[i].server;
394 r.in.environment = environment;
395 r.in.level = level;
396 r.in.buffer = NULL;
397 r.in.offered = 0;
398 r.out.needed = &needed;
400 torture_comment(tctx, "Testing GetPrintProcessorDirectory level %u\n", r.in.level);
402 status = dcerpc_spoolss_GetPrintProcessorDirectory_r(b, tctx, &r);
403 torture_assert_ntstatus_ok(tctx, status,
404 "dcerpc_spoolss_GetPrintProcessorDirectory failed");
405 torture_assert_werr_equal(tctx, r.out.result, WERR_INSUFFICIENT_BUFFER,
406 "GetPrintProcessorDirectory unexpected return code");
408 blob = data_blob_talloc_zero(tctx, needed);
409 r.in.buffer = &blob;
410 r.in.offered = needed;
412 status = dcerpc_spoolss_GetPrintProcessorDirectory_r(b, tctx, &r);
413 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_GetPrintProcessorDirectory failed");
415 torture_assert_werr_ok(tctx, r.out.result, "GetPrintProcessorDirectory failed");
417 CHECK_NEEDED_SIZE_LEVEL(spoolss_PrintProcessorDirectoryInfo, r.out.info, r.in.level, needed, 2);
420 return true;
424 static bool test_GetPrinterDriverDirectory(struct torture_context *tctx,
425 struct dcerpc_pipe *p,
426 const char *environment)
428 NTSTATUS status;
429 struct dcerpc_binding_handle *b = p->binding_handle;
430 struct spoolss_GetPrinterDriverDirectory r;
431 struct {
432 uint16_t level;
433 const char *server;
434 } levels[] = {{
435 .level = 1,
436 .server = NULL
438 .level = 1,
439 .server = ""
441 .level = 78,
442 .server = ""
444 .level = 1,
445 .server = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p))
447 .level = 1024,
448 .server = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p))
451 int i;
452 uint32_t needed;
454 for (i=0;i<ARRAY_SIZE(levels);i++) {
455 int level = levels[i].level;
456 DATA_BLOB blob;
458 r.in.server = levels[i].server;
459 r.in.environment = environment;
460 r.in.level = level;
461 r.in.buffer = NULL;
462 r.in.offered = 0;
463 r.out.needed = &needed;
465 torture_comment(tctx, "Testing GetPrinterDriverDirectory level %u\n", r.in.level);
467 status = dcerpc_spoolss_GetPrinterDriverDirectory_r(b, tctx, &r);
468 torture_assert_ntstatus_ok(tctx, status,
469 "dcerpc_spoolss_GetPrinterDriverDirectory failed");
470 torture_assert_werr_equal(tctx, r.out.result, WERR_INSUFFICIENT_BUFFER,
471 "GetPrinterDriverDirectory unexpected return code");
473 blob = data_blob_talloc_zero(tctx, needed);
474 r.in.buffer = &blob;
475 r.in.offered = needed;
477 status = dcerpc_spoolss_GetPrinterDriverDirectory_r(b, tctx, &r);
478 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_GetPrinterDriverDirectory failed");
480 torture_assert_werr_ok(tctx, r.out.result, "GetPrinterDriverDirectory failed");
482 CHECK_NEEDED_SIZE_LEVEL(spoolss_DriverDirectoryInfo, r.out.info, r.in.level, needed, 2);
485 return true;
488 static bool test_EnumPrinterDrivers_args(struct torture_context *tctx,
489 struct dcerpc_binding_handle *b,
490 const char *server_name,
491 const char *environment,
492 uint32_t level,
493 uint32_t *count_p,
494 union spoolss_DriverInfo **info_p)
496 struct spoolss_EnumPrinterDrivers r;
497 uint32_t needed;
498 uint32_t count;
499 union spoolss_DriverInfo *info;
501 r.in.server = server_name;
502 r.in.environment = environment;
503 r.in.level = level;
504 r.in.buffer = NULL;
505 r.in.offered = 0;
506 r.out.needed = &needed;
507 r.out.count = &count;
508 r.out.info = &info;
510 torture_comment(tctx, "Testing EnumPrinterDrivers(%s) level %u\n",
511 r.in.environment, r.in.level);
513 torture_assert_ntstatus_ok(tctx,
514 dcerpc_spoolss_EnumPrinterDrivers_r(b, tctx, &r),
515 "EnumPrinterDrivers failed");
516 if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
517 DATA_BLOB blob = data_blob_talloc_zero(tctx, needed);
518 r.in.buffer = &blob;
519 r.in.offered = needed;
521 torture_assert_ntstatus_ok(tctx,
522 dcerpc_spoolss_EnumPrinterDrivers_r(b, tctx, &r),
523 "EnumPrinterDrivers failed");
526 torture_assert_werr_ok(tctx, r.out.result,
527 "EnumPrinterDrivers failed");
529 if (count_p) {
530 *count_p = count;
532 if (info_p) {
533 *info_p = info;
536 CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumPrinterDrivers, info, r.in.level, count, needed, 4);
538 return true;
542 static bool test_EnumPrinterDrivers_findone(struct torture_context *tctx,
543 struct dcerpc_binding_handle *b,
544 const char *server_name,
545 const char *environment,
546 uint32_t level,
547 const char *driver_name)
549 uint32_t count;
550 union spoolss_DriverInfo *info;
551 int i;
553 torture_assert(tctx,
554 test_EnumPrinterDrivers_args(tctx, b, server_name, environment, level, &count, &info),
555 "failed to enumerate printer drivers");
557 for (i=0; i < count; i++) {
558 const char *driver_name_ret;
559 switch (level) {
560 case 1:
561 driver_name_ret = info[i].info1.driver_name;
562 break;
563 case 2:
564 driver_name_ret = info[i].info2.driver_name;
565 break;
566 case 3:
567 driver_name_ret = info[i].info3.driver_name;
568 break;
569 case 4:
570 driver_name_ret = info[i].info4.driver_name;
571 break;
572 case 5:
573 driver_name_ret = info[i].info5.driver_name;
574 break;
575 case 6:
576 driver_name_ret = info[i].info6.driver_name;
577 break;
578 case 7:
579 driver_name_ret = info[i].info7.driver_name;
580 break;
581 case 8:
582 driver_name_ret = info[i].info8.driver_name;
583 break;
584 default:
585 break;
587 if (strequal(driver_name, driver_name_ret)) {
588 return true;
592 return false;
595 static bool test_EnumPrinterDrivers(struct torture_context *tctx,
596 struct dcerpc_pipe *p,
597 struct test_spoolss_context *ctx,
598 const char *architecture)
600 struct dcerpc_binding_handle *b = p->binding_handle;
601 uint16_t levels[] = { 1, 2, 3, 4, 5, 6, 8 };
602 int i, j;
604 /* FIXME: gd, come back and fix "" as server, and handle
605 * priority of returned error codes in torture test and samba 3
606 * server */
607 const char *server_name = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
609 for (i=0;i<ARRAY_SIZE(levels);i++) {
610 int level = levels[i];
611 uint32_t count;
612 union spoolss_DriverInfo *info;
614 torture_assert(tctx,
615 test_EnumPrinterDrivers_args(tctx, b, server_name, architecture, level, &count, &info),
616 "failed to enumerate drivers");
618 ctx->driver_count[level] = count;
619 ctx->drivers[level] = info;
622 for (i=1;i<ARRAY_SIZE(levels);i++) {
623 int level = levels[i];
624 int old_level = levels[i-1];
626 torture_assert_int_equal(tctx, ctx->driver_count[level], ctx->driver_count[old_level],
627 "EnumPrinterDrivers invalid value");
630 for (i=0;i<ARRAY_SIZE(levels);i++) {
631 int level = levels[i];
633 for (j=0;j<ctx->driver_count[level];j++) {
634 union spoolss_DriverInfo *cur = &ctx->drivers[level][j];
635 union spoolss_DriverInfo *ref = &ctx->drivers[8][j];
637 switch (level) {
638 case 1:
639 COMPARE_STRING(tctx, cur->info1, ref->info8, driver_name);
640 break;
641 case 2:
642 COMPARE_UINT32(tctx, cur->info2, ref->info8, version);
643 COMPARE_STRING(tctx, cur->info2, ref->info8, driver_name);
644 COMPARE_STRING(tctx, cur->info2, ref->info8, architecture);
645 COMPARE_STRING(tctx, cur->info2, ref->info8, driver_path);
646 COMPARE_STRING(tctx, cur->info2, ref->info8, data_file);
647 COMPARE_STRING(tctx, cur->info2, ref->info8, config_file);
648 break;
649 case 3:
650 COMPARE_UINT32(tctx, cur->info3, ref->info8, version);
651 COMPARE_STRING(tctx, cur->info3, ref->info8, driver_name);
652 COMPARE_STRING(tctx, cur->info3, ref->info8, architecture);
653 COMPARE_STRING(tctx, cur->info3, ref->info8, driver_path);
654 COMPARE_STRING(tctx, cur->info3, ref->info8, data_file);
655 COMPARE_STRING(tctx, cur->info3, ref->info8, config_file);
656 COMPARE_STRING(tctx, cur->info3, ref->info8, help_file);
657 COMPARE_STRING_ARRAY(tctx, cur->info3, ref->info8, dependent_files);
658 COMPARE_STRING(tctx, cur->info3, ref->info8, monitor_name);
659 COMPARE_STRING(tctx, cur->info3, ref->info8, default_datatype);
660 break;
661 case 4:
662 COMPARE_UINT32(tctx, cur->info4, ref->info8, version);
663 COMPARE_STRING(tctx, cur->info4, ref->info8, driver_name);
664 COMPARE_STRING(tctx, cur->info4, ref->info8, architecture);
665 COMPARE_STRING(tctx, cur->info4, ref->info8, driver_path);
666 COMPARE_STRING(tctx, cur->info4, ref->info8, data_file);
667 COMPARE_STRING(tctx, cur->info4, ref->info8, config_file);
668 COMPARE_STRING(tctx, cur->info4, ref->info8, help_file);
669 COMPARE_STRING_ARRAY(tctx, cur->info4, ref->info8, dependent_files);
670 COMPARE_STRING(tctx, cur->info4, ref->info8, monitor_name);
671 COMPARE_STRING(tctx, cur->info4, ref->info8, default_datatype);
672 COMPARE_STRING_ARRAY(tctx, cur->info4, ref->info8, previous_names);
673 break;
674 case 5:
675 COMPARE_UINT32(tctx, cur->info5, ref->info8, version);
676 COMPARE_STRING(tctx, cur->info5, ref->info8, driver_name);
677 COMPARE_STRING(tctx, cur->info5, ref->info8, architecture);
678 COMPARE_STRING(tctx, cur->info5, ref->info8, driver_path);
679 COMPARE_STRING(tctx, cur->info5, ref->info8, data_file);
680 COMPARE_STRING(tctx, cur->info5, ref->info8, config_file);
681 /*COMPARE_UINT32(tctx, cur->info5, ref->info8, driver_attributes);*/
682 /*COMPARE_UINT32(tctx, cur->info5, ref->info8, config_version);*/
683 /*TODO: ! COMPARE_UINT32(tctx, cur->info5, ref->info8, driver_version); */
684 break;
685 case 6:
686 COMPARE_UINT32(tctx, cur->info6, ref->info8, version);
687 COMPARE_STRING(tctx, cur->info6, ref->info8, driver_name);
688 COMPARE_STRING(tctx, cur->info6, ref->info8, architecture);
689 COMPARE_STRING(tctx, cur->info6, ref->info8, driver_path);
690 COMPARE_STRING(tctx, cur->info6, ref->info8, data_file);
691 COMPARE_STRING(tctx, cur->info6, ref->info8, config_file);
692 COMPARE_STRING(tctx, cur->info6, ref->info8, help_file);
693 COMPARE_STRING_ARRAY(tctx, cur->info6, ref->info8, dependent_files);
694 COMPARE_STRING(tctx, cur->info6, ref->info8, monitor_name);
695 COMPARE_STRING(tctx, cur->info6, ref->info8, default_datatype);
696 COMPARE_STRING_ARRAY(tctx, cur->info6, ref->info8, previous_names);
697 COMPARE_NTTIME(tctx, cur->info6, ref->info8, driver_date);
698 COMPARE_UINT64(tctx, cur->info6, ref->info8, driver_version);
699 COMPARE_STRING(tctx, cur->info6, ref->info8, manufacturer_name);
700 COMPARE_STRING(tctx, cur->info6, ref->info8, manufacturer_url);
701 COMPARE_STRING(tctx, cur->info6, ref->info8, hardware_id);
702 COMPARE_STRING(tctx, cur->info6, ref->info8, provider);
703 break;
704 case 8:
705 /* level 8 is our reference, and it makes no sense to compare it to itself */
706 break;
711 return true;
714 static bool test_EnumMonitors(struct torture_context *tctx,
715 struct dcerpc_binding_handle *b,
716 struct test_spoolss_context *ctx)
718 NTSTATUS status;
719 struct spoolss_EnumMonitors r;
720 uint16_t levels[] = { 1, 2 };
721 int i, j;
723 for (i=0;i<ARRAY_SIZE(levels);i++) {
724 int level = levels[i];
725 DATA_BLOB blob;
726 uint32_t needed;
727 uint32_t count;
728 union spoolss_MonitorInfo *info;
730 r.in.servername = "";
731 r.in.level = level;
732 r.in.buffer = NULL;
733 r.in.offered = 0;
734 r.out.needed = &needed;
735 r.out.count = &count;
736 r.out.info = &info;
738 torture_comment(tctx, "Testing EnumMonitors level %u\n", r.in.level);
740 status = dcerpc_spoolss_EnumMonitors_r(b, ctx, &r);
741 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EnumMonitors failed");
742 if (W_ERROR_IS_OK(r.out.result)) {
743 /* TODO: do some more checks here */
744 continue;
746 torture_assert_werr_equal(tctx, r.out.result, WERR_INSUFFICIENT_BUFFER,
747 "EnumMonitors failed");
749 blob = data_blob_talloc_zero(ctx, needed);
750 r.in.buffer = &blob;
751 r.in.offered = needed;
753 status = dcerpc_spoolss_EnumMonitors_r(b, ctx, &r);
754 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EnumMonitors failed");
756 torture_assert_werr_ok(tctx, r.out.result, "EnumMonitors failed");
758 CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumMonitors, info, r.in.level, count, needed, 4);
760 ctx->monitor_count[level] = count;
761 ctx->monitors[level] = info;
764 for (i=1;i<ARRAY_SIZE(levels);i++) {
765 int level = levels[i];
766 int old_level = levels[i-1];
767 torture_assert_int_equal(tctx, ctx->monitor_count[level], ctx->monitor_count[old_level],
768 "EnumMonitors invalid value");
771 for (i=0;i<ARRAY_SIZE(levels);i++) {
772 int level = levels[i];
773 for (j=0;j<ctx->monitor_count[level];j++) {
774 union spoolss_MonitorInfo *cur = &ctx->monitors[level][j];
775 union spoolss_MonitorInfo *ref = &ctx->monitors[2][j];
776 switch (level) {
777 case 1:
778 COMPARE_STRING(tctx, cur->info1, ref->info2, monitor_name);
779 break;
780 case 2:
781 /* level 2 is our reference, and it makes no sense to compare it to itself */
782 break;
787 return true;
790 static bool test_EnumPrintProcessors(struct torture_context *tctx,
791 struct dcerpc_binding_handle *b,
792 struct test_spoolss_context *ctx,
793 const char *environment)
795 NTSTATUS status;
796 struct spoolss_EnumPrintProcessors r;
797 uint16_t levels[] = { 1 };
798 int i, j;
800 for (i=0;i<ARRAY_SIZE(levels);i++) {
801 int level = levels[i];
802 DATA_BLOB blob;
803 uint32_t needed;
804 uint32_t count;
805 union spoolss_PrintProcessorInfo *info;
807 r.in.servername = "";
808 r.in.environment = environment;
809 r.in.level = level;
810 r.in.buffer = NULL;
811 r.in.offered = 0;
812 r.out.needed = &needed;
813 r.out.count = &count;
814 r.out.info = &info;
816 torture_comment(tctx, "Testing EnumPrintProcessors level %u\n", r.in.level);
818 status = dcerpc_spoolss_EnumPrintProcessors_r(b, ctx, &r);
819 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EnumPrintProcessors failed");
820 if (W_ERROR_IS_OK(r.out.result)) {
821 /* TODO: do some more checks here */
822 continue;
824 torture_assert_werr_equal(tctx, r.out.result, WERR_INSUFFICIENT_BUFFER,
825 "EnumPrintProcessors unexpected return code");
827 blob = data_blob_talloc_zero(ctx, needed);
828 r.in.buffer = &blob;
829 r.in.offered = needed;
831 status = dcerpc_spoolss_EnumPrintProcessors_r(b, ctx, &r);
832 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EnumPrintProcessors failed");
834 torture_assert_werr_ok(tctx, r.out.result, "EnumPrintProcessors failed");
836 CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumPrintProcessors, info, r.in.level, count, needed, 4);
838 ctx->print_processor_count[level] = count;
839 ctx->print_processors[level] = info;
842 for (i=1;i<ARRAY_SIZE(levels);i++) {
843 int level = levels[i];
844 int old_level = levels[i-1];
845 torture_assert_int_equal(tctx, ctx->print_processor_count[level], ctx->print_processor_count[old_level],
846 "EnumPrintProcessors failed");
849 for (i=0;i<ARRAY_SIZE(levels);i++) {
850 int level = levels[i];
851 for (j=0;j<ctx->print_processor_count[level];j++) {
852 #if 0
853 union spoolss_PrintProcessorInfo *cur = &ctx->print_processors[level][j];
854 union spoolss_PrintProcessorInfo *ref = &ctx->print_processors[1][j];
855 #endif
856 switch (level) {
857 case 1:
858 /* level 1 is our reference, and it makes no sense to compare it to itself */
859 break;
864 return true;
867 static bool test_EnumPrintProcDataTypes(struct torture_context *tctx,
868 struct dcerpc_binding_handle *b)
870 NTSTATUS status;
871 struct spoolss_EnumPrintProcDataTypes r;
872 uint16_t levels[] = { 1 };
873 int i;
875 for (i=0;i<ARRAY_SIZE(levels);i++) {
876 int level = levels[i];
877 DATA_BLOB blob;
878 uint32_t needed;
879 uint32_t count;
880 union spoolss_PrintProcDataTypesInfo *info;
882 r.in.servername = "";
883 r.in.print_processor_name = "winprint";
884 r.in.level = level;
885 r.in.buffer = NULL;
886 r.in.offered = 0;
887 r.out.needed = &needed;
888 r.out.count = &count;
889 r.out.info = &info;
891 torture_comment(tctx, "Testing EnumPrintProcDataTypes level %u\n", r.in.level);
893 status = dcerpc_spoolss_EnumPrintProcDataTypes_r(b, tctx, &r);
894 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EnumPrintProcDataType failed");
895 if (W_ERROR_IS_OK(r.out.result)) {
896 /* TODO: do some more checks here */
897 continue;
899 torture_assert_werr_equal(tctx, r.out.result, WERR_INSUFFICIENT_BUFFER,
900 "EnumPrintProcDataTypes unexpected return code");
902 blob = data_blob_talloc_zero(tctx, needed);
903 r.in.buffer = &blob;
904 r.in.offered = needed;
906 status = dcerpc_spoolss_EnumPrintProcDataTypes_r(b, tctx, &r);
907 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EnumPrintProcDataTypes failed");
909 torture_assert_werr_ok(tctx, r.out.result, "EnumPrintProcDataTypes failed");
911 CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumPrintProcDataTypes, info, r.in.level, count, needed, 4);
915 return true;
919 static bool test_EnumPrinters(struct torture_context *tctx,
920 struct dcerpc_binding_handle *b,
921 struct test_spoolss_context *ctx)
923 struct spoolss_EnumPrinters r;
924 NTSTATUS status;
925 uint16_t levels[] = { 0, 1, 2, 4, 5 };
926 int i, j;
928 for (i=0;i<ARRAY_SIZE(levels);i++) {
929 int level = levels[i];
930 DATA_BLOB blob;
931 uint32_t needed;
932 uint32_t count;
933 union spoolss_PrinterInfo *info;
935 r.in.flags = PRINTER_ENUM_LOCAL;
936 r.in.server = "";
937 r.in.level = level;
938 r.in.buffer = NULL;
939 r.in.offered = 0;
940 r.out.needed = &needed;
941 r.out.count = &count;
942 r.out.info = &info;
944 torture_comment(tctx, "Testing EnumPrinters level %u\n", r.in.level);
946 status = dcerpc_spoolss_EnumPrinters_r(b, ctx, &r);
947 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EnumPrinters failed");
948 if (W_ERROR_IS_OK(r.out.result)) {
949 /* TODO: do some more checks here */
950 continue;
952 torture_assert_werr_equal(tctx, r.out.result, WERR_INSUFFICIENT_BUFFER,
953 "EnumPrinters unexpected return code");
955 blob = data_blob_talloc_zero(ctx, needed);
956 r.in.buffer = &blob;
957 r.in.offered = needed;
959 status = dcerpc_spoolss_EnumPrinters_r(b, ctx, &r);
960 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EnumPrinters failed");
962 torture_assert_werr_ok(tctx, r.out.result, "EnumPrinters failed");
964 CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumPrinters, info, r.in.level, count, needed, 4);
966 ctx->printer_count[level] = count;
967 ctx->printers[level] = info;
970 for (i=1;i<ARRAY_SIZE(levels);i++) {
971 int level = levels[i];
972 int old_level = levels[i-1];
973 torture_assert_int_equal(tctx, ctx->printer_count[level], ctx->printer_count[old_level],
974 "EnumPrinters invalid value");
977 for (i=0;i<ARRAY_SIZE(levels);i++) {
978 int level = levels[i];
979 for (j=0;j<ctx->printer_count[level];j++) {
980 union spoolss_PrinterInfo *cur = &ctx->printers[level][j];
981 union spoolss_PrinterInfo *ref = &ctx->printers[2][j];
982 switch (level) {
983 case 0:
984 COMPARE_STRING(tctx, cur->info0, ref->info2, printername);
985 COMPARE_STRING(tctx, cur->info0, ref->info2, servername);
986 COMPARE_UINT32(tctx, cur->info0, ref->info2, cjobs);
987 /*COMPARE_UINT32(tctx, cur->info0, ref->info2, total_jobs);
988 COMPARE_UINT32(tctx, cur->info0, ref->info2, total_bytes);
989 COMPARE_SPOOLSS_TIME(cur->info0, ref->info2, spoolss_Time time);
990 COMPARE_UINT32(tctx, cur->info0, ref->info2, global_counter);
991 COMPARE_UINT32(tctx, cur->info0, ref->info2, total_pages);
992 COMPARE_UINT32(tctx, cur->info0, ref->info2, version);
993 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown10);
994 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown11);
995 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown12);
996 COMPARE_UINT32(tctx, cur->info0, ref->info2, session_counter);
997 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown14);
998 COMPARE_UINT32(tctx, cur->info0, ref->info2, printer_errors);
999 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown16);
1000 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown17);
1001 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown18);
1002 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown19);
1003 COMPARE_UINT32(tctx, cur->info0, ref->info2, change_id);
1004 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown21);*/
1005 COMPARE_UINT32(tctx, cur->info0, ref->info2, status);
1006 /*COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown23);
1007 COMPARE_UINT32(tctx, cur->info0, ref->info2, c_setprinter);
1008 COMPARE_UINT16(cur->info0, ref->info2, unknown25);
1009 COMPARE_UINT16(cur->info0, ref->info2, unknown26);
1010 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown27);
1011 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown28);
1012 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown29);*/
1013 break;
1014 case 1:
1015 /*COMPARE_UINT32(tctx, cur->info1, ref->info2, flags);*/
1016 /*COMPARE_STRING(tctx, cur->info1, ref->info2, name);*/
1017 /*COMPARE_STRING(tctx, cur->info1, ref->info2, description);*/
1018 COMPARE_STRING(tctx, cur->info1, ref->info2, comment);
1019 break;
1020 case 2:
1021 /* level 2 is our reference, and it makes no sense to compare it to itself */
1022 break;
1023 case 4:
1024 COMPARE_STRING(tctx, cur->info4, ref->info2, printername);
1025 COMPARE_STRING(tctx, cur->info4, ref->info2, servername);
1026 COMPARE_UINT32(tctx, cur->info4, ref->info2, attributes);
1027 break;
1028 case 5:
1029 COMPARE_STRING(tctx, cur->info5, ref->info2, printername);
1030 COMPARE_STRING(tctx, cur->info5, ref->info2, portname);
1031 COMPARE_UINT32(tctx, cur->info5, ref->info2, attributes);
1032 /*COMPARE_UINT32(tctx, cur->info5, ref->info2, device_not_selected_timeout);
1033 COMPARE_UINT32(tctx, cur->info5, ref->info2, transmission_retry_timeout);*/
1034 break;
1039 /* TODO:
1040 * - verify that the port of a printer was in the list returned by EnumPorts
1043 return true;
1046 static bool test_GetPrinterDriver2(struct torture_context *tctx,
1047 struct dcerpc_binding_handle *b,
1048 struct policy_handle *handle,
1049 const char *driver_name,
1050 const char *environment);
1052 bool test_GetPrinter_level(struct torture_context *tctx,
1053 struct dcerpc_binding_handle *b,
1054 struct policy_handle *handle,
1055 uint32_t level,
1056 union spoolss_PrinterInfo *info)
1058 struct spoolss_GetPrinter r;
1059 uint32_t needed;
1061 r.in.handle = handle;
1062 r.in.level = level;
1063 r.in.buffer = NULL;
1064 r.in.offered = 0;
1065 r.out.needed = &needed;
1067 torture_comment(tctx, "Testing GetPrinter level %u\n", r.in.level);
1069 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_GetPrinter_r(b, tctx, &r),
1070 "GetPrinter failed");
1072 if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
1073 DATA_BLOB blob = data_blob_talloc_zero(tctx, needed);
1074 r.in.buffer = &blob;
1075 r.in.offered = needed;
1077 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_GetPrinter_r(b, tctx, &r),
1078 "GetPrinter failed");
1081 torture_assert_werr_ok(tctx, r.out.result, "GetPrinter failed");
1083 CHECK_NEEDED_SIZE_LEVEL(spoolss_PrinterInfo, r.out.info, r.in.level, needed, 4);
1085 if (info && r.out.info) {
1086 *info = *r.out.info;
1089 return true;
1093 static bool test_GetPrinter(struct torture_context *tctx,
1094 struct dcerpc_binding_handle *b,
1095 struct policy_handle *handle,
1096 const char *environment)
1098 uint32_t levels[] = {0, 1, 2, 3, 4, 5, 6, 7, 8};
1099 int i;
1101 for (i=0;i<ARRAY_SIZE(levels);i++) {
1103 union spoolss_PrinterInfo info;
1105 ZERO_STRUCT(info);
1107 torture_assert(tctx, test_GetPrinter_level(tctx, b, handle, levels[i], &info),
1108 "failed to call GetPrinter");
1110 if ((levels[i] == 2) && info.info2.drivername && strlen(info.info2.drivername)) {
1111 torture_assert(tctx,
1112 test_GetPrinterDriver2(tctx, b, handle, info.info2.drivername, environment),
1113 "failed to call test_GetPrinterDriver2");
1117 return true;
1120 static bool test_SetPrinter(struct torture_context *tctx,
1121 struct dcerpc_binding_handle *b,
1122 struct policy_handle *handle,
1123 struct spoolss_SetPrinterInfoCtr *info_ctr,
1124 struct spoolss_DevmodeContainer *devmode_ctr,
1125 struct sec_desc_buf *secdesc_ctr,
1126 enum spoolss_PrinterControl command)
1128 struct spoolss_SetPrinter r;
1130 r.in.handle = handle;
1131 r.in.info_ctr = info_ctr;
1132 r.in.devmode_ctr = devmode_ctr;
1133 r.in.secdesc_ctr = secdesc_ctr;
1134 r.in.command = command;
1136 torture_comment(tctx, "Testing SetPrinter level %d\n", r.in.info_ctr->level);
1138 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_SetPrinter_r(b, tctx, &r),
1139 "failed to call SetPrinter");
1140 torture_assert_werr_ok(tctx, r.out.result,
1141 "failed to call SetPrinter");
1143 return true;
1146 static bool test_SetPrinter_errors(struct torture_context *tctx,
1147 struct dcerpc_binding_handle *b,
1148 struct policy_handle *handle)
1150 struct spoolss_SetPrinter r;
1151 uint16_t levels[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
1152 int i;
1154 struct spoolss_SetPrinterInfoCtr info_ctr;
1155 struct spoolss_DevmodeContainer devmode_ctr;
1156 struct sec_desc_buf secdesc_ctr;
1158 info_ctr.level = 0;
1159 info_ctr.info.info0 = NULL;
1161 ZERO_STRUCT(devmode_ctr);
1162 ZERO_STRUCT(secdesc_ctr);
1164 r.in.handle = handle;
1165 r.in.info_ctr = &info_ctr;
1166 r.in.devmode_ctr = &devmode_ctr;
1167 r.in.secdesc_ctr = &secdesc_ctr;
1168 r.in.command = 0;
1170 torture_comment(tctx, "Testing SetPrinter all zero\n");
1172 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_SetPrinter_r(b, tctx, &r),
1173 "failed to call SetPrinter");
1174 torture_assert_werr_equal(tctx, r.out.result, WERR_INVALID_PARAM,
1175 "failed to call SetPrinter");
1177 again:
1178 for (i=0; i < ARRAY_SIZE(levels); i++) {
1180 struct spoolss_SetPrinterInfo0 info0;
1181 struct spoolss_SetPrinterInfo1 info1;
1182 struct spoolss_SetPrinterInfo2 info2;
1183 struct spoolss_SetPrinterInfo3 info3;
1184 struct spoolss_SetPrinterInfo4 info4;
1185 struct spoolss_SetPrinterInfo5 info5;
1186 struct spoolss_SetPrinterInfo6 info6;
1187 struct spoolss_SetPrinterInfo7 info7;
1188 struct spoolss_SetPrinterInfo8 info8;
1189 struct spoolss_SetPrinterInfo9 info9;
1192 info_ctr.level = levels[i];
1193 switch (levels[i]) {
1194 case 0:
1195 ZERO_STRUCT(info0);
1196 info_ctr.info.info0 = &info0;
1197 break;
1198 case 1:
1199 ZERO_STRUCT(info1);
1200 info_ctr.info.info1 = &info1;
1201 break;
1202 case 2:
1203 ZERO_STRUCT(info2);
1204 info_ctr.info.info2 = &info2;
1205 break;
1206 case 3:
1207 ZERO_STRUCT(info3);
1208 info_ctr.info.info3 = &info3;
1209 break;
1210 case 4:
1211 ZERO_STRUCT(info4);
1212 info_ctr.info.info4 = &info4;
1213 break;
1214 case 5:
1215 ZERO_STRUCT(info5);
1216 info_ctr.info.info5 = &info5;
1217 break;
1218 case 6:
1219 ZERO_STRUCT(info6);
1220 info_ctr.info.info6 = &info6;
1221 break;
1222 case 7:
1223 ZERO_STRUCT(info7);
1224 info_ctr.info.info7 = &info7;
1225 break;
1226 case 8:
1227 ZERO_STRUCT(info8);
1228 info_ctr.info.info8 = &info8;
1229 break;
1230 case 9:
1231 ZERO_STRUCT(info9);
1232 info_ctr.info.info9 = &info9;
1233 break;
1236 torture_comment(tctx, "Testing SetPrinter level %d, command %d\n",
1237 info_ctr.level, r.in.command);
1239 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_SetPrinter_r(b, tctx, &r),
1240 "failed to call SetPrinter");
1242 switch (r.in.command) {
1243 case SPOOLSS_PRINTER_CONTROL_UNPAUSE: /* 0 */
1244 /* is ignored for all levels other then 0 */
1245 if (info_ctr.level > 0) {
1246 /* ignored then */
1247 break;
1249 case SPOOLSS_PRINTER_CONTROL_PAUSE: /* 1 */
1250 case SPOOLSS_PRINTER_CONTROL_RESUME: /* 2 */
1251 case SPOOLSS_PRINTER_CONTROL_PURGE: /* 3 */
1252 if (info_ctr.level > 0) {
1253 /* is invalid for all levels other then 0 */
1254 torture_assert_werr_equal(tctx, r.out.result, WERR_INVALID_PRINTER_COMMAND,
1255 "unexpected error code returned");
1256 continue;
1257 } else {
1258 torture_assert_werr_ok(tctx, r.out.result,
1259 "failed to call SetPrinter with non 0 command");
1260 continue;
1262 break;
1264 case SPOOLSS_PRINTER_CONTROL_SET_STATUS: /* 4 */
1265 /* FIXME: gd needs further investigation */
1266 default:
1267 torture_assert_werr_equal(tctx, r.out.result, WERR_INVALID_PRINTER_COMMAND,
1268 "unexpected error code returned");
1269 continue;
1272 switch (info_ctr.level) {
1273 case 1:
1274 torture_assert_werr_equal(tctx, r.out.result, WERR_UNKNOWN_LEVEL,
1275 "unexpected error code returned");
1276 break;
1277 case 2:
1278 torture_assert_werr_equal(tctx, r.out.result, WERR_UNKNOWN_PRINTER_DRIVER,
1279 "unexpected error code returned");
1280 break;
1281 case 3:
1282 case 4:
1283 case 5:
1284 case 7:
1285 torture_assert_werr_equal(tctx, r.out.result, WERR_INVALID_PARAM,
1286 "unexpected error code returned");
1287 break;
1288 case 9:
1289 torture_assert_werr_equal(tctx, r.out.result, WERR_NOT_SUPPORTED,
1290 "unexpected error code returned");
1291 break;
1292 default:
1293 torture_assert_werr_ok(tctx, r.out.result,
1294 "failed to call SetPrinter");
1295 break;
1299 if (r.in.command < 5) {
1300 r.in.command++;
1301 goto again;
1304 return true;
1307 static void clear_info2(struct spoolss_SetPrinterInfoCtr *r)
1309 if ((r->level == 2) && (r->info.info2)) {
1310 r->info.info2->secdesc_ptr = 0;
1311 r->info.info2->devmode_ptr = 0;
1315 static bool test_PrinterInfo(struct torture_context *tctx,
1316 struct dcerpc_binding_handle *b,
1317 struct policy_handle *handle)
1319 NTSTATUS status;
1320 struct spoolss_SetPrinter s;
1321 struct spoolss_GetPrinter q;
1322 struct spoolss_GetPrinter q0;
1323 struct spoolss_SetPrinterInfoCtr info_ctr;
1324 union spoolss_PrinterInfo info;
1325 struct spoolss_DevmodeContainer devmode_ctr;
1326 struct sec_desc_buf secdesc_ctr;
1327 uint32_t needed;
1328 bool ret = true;
1329 int i;
1331 uint32_t status_list[] = {
1332 /* these do not stick
1333 PRINTER_STATUS_PAUSED,
1334 PRINTER_STATUS_ERROR,
1335 PRINTER_STATUS_PENDING_DELETION, */
1336 PRINTER_STATUS_PAPER_JAM,
1337 PRINTER_STATUS_PAPER_OUT,
1338 PRINTER_STATUS_MANUAL_FEED,
1339 PRINTER_STATUS_PAPER_PROBLEM,
1340 PRINTER_STATUS_OFFLINE,
1341 PRINTER_STATUS_IO_ACTIVE,
1342 PRINTER_STATUS_BUSY,
1343 PRINTER_STATUS_PRINTING,
1344 PRINTER_STATUS_OUTPUT_BIN_FULL,
1345 PRINTER_STATUS_NOT_AVAILABLE,
1346 PRINTER_STATUS_WAITING,
1347 PRINTER_STATUS_PROCESSING,
1348 PRINTER_STATUS_INITIALIZING,
1349 PRINTER_STATUS_WARMING_UP,
1350 PRINTER_STATUS_TONER_LOW,
1351 PRINTER_STATUS_NO_TONER,
1352 PRINTER_STATUS_PAGE_PUNT,
1353 PRINTER_STATUS_USER_INTERVENTION,
1354 PRINTER_STATUS_OUT_OF_MEMORY,
1355 PRINTER_STATUS_DOOR_OPEN,
1356 PRINTER_STATUS_SERVER_UNKNOWN,
1357 PRINTER_STATUS_POWER_SAVE,
1358 /* these do not stick
1359 0x02000000,
1360 0x04000000,
1361 0x08000000,
1362 0x10000000,
1363 0x20000000,
1364 0x40000000,
1365 0x80000000 */
1367 uint32_t default_attribute = PRINTER_ATTRIBUTE_LOCAL;
1368 uint32_t attribute_list[] = {
1369 PRINTER_ATTRIBUTE_QUEUED,
1370 /* fails with WERR_INVALID_DATATYPE:
1371 PRINTER_ATTRIBUTE_DIRECT, */
1372 /* does not stick
1373 PRINTER_ATTRIBUTE_DEFAULT, */
1374 PRINTER_ATTRIBUTE_SHARED,
1375 /* does not stick
1376 PRINTER_ATTRIBUTE_NETWORK, */
1377 PRINTER_ATTRIBUTE_HIDDEN,
1378 PRINTER_ATTRIBUTE_LOCAL,
1379 PRINTER_ATTRIBUTE_ENABLE_DEVQ,
1380 PRINTER_ATTRIBUTE_KEEPPRINTEDJOBS,
1381 PRINTER_ATTRIBUTE_DO_COMPLETE_FIRST,
1382 PRINTER_ATTRIBUTE_WORK_OFFLINE,
1383 /* does not stick
1384 PRINTER_ATTRIBUTE_ENABLE_BIDI, */
1385 /* fails with WERR_INVALID_DATATYPE:
1386 PRINTER_ATTRIBUTE_RAW_ONLY, */
1387 /* these do not stick
1388 PRINTER_ATTRIBUTE_PUBLISHED,
1389 PRINTER_ATTRIBUTE_FAX,
1390 PRINTER_ATTRIBUTE_TS,
1391 0x00010000,
1392 0x00020000,
1393 0x00040000,
1394 0x00080000,
1395 0x00100000,
1396 0x00200000,
1397 0x00400000,
1398 0x00800000,
1399 0x01000000,
1400 0x02000000,
1401 0x04000000,
1402 0x08000000,
1403 0x10000000,
1404 0x20000000,
1405 0x40000000,
1406 0x80000000 */
1409 ZERO_STRUCT(devmode_ctr);
1410 ZERO_STRUCT(secdesc_ctr);
1412 s.in.handle = handle;
1413 s.in.command = 0;
1414 s.in.info_ctr = &info_ctr;
1415 s.in.devmode_ctr = &devmode_ctr;
1416 s.in.secdesc_ctr = &secdesc_ctr;
1418 q.in.handle = handle;
1419 q.out.info = &info;
1420 q0 = q;
1422 #define TESTGETCALL(call, r) \
1423 r.in.buffer = NULL; \
1424 r.in.offered = 0;\
1425 r.out.needed = &needed; \
1426 status = dcerpc_spoolss_ ##call## _r(b, tctx, &r); \
1427 if (!NT_STATUS_IS_OK(status)) { \
1428 torture_comment(tctx, #call " level %u failed - %s (%s)\n", \
1429 r.in.level, nt_errstr(status), __location__); \
1430 ret = false; \
1431 break; \
1433 if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {\
1434 DATA_BLOB blob = data_blob_talloc_zero(tctx, needed); \
1435 r.in.buffer = &blob; \
1436 r.in.offered = needed; \
1438 status = dcerpc_spoolss_ ##call## _r(b, tctx, &r); \
1439 if (!NT_STATUS_IS_OK(status)) { \
1440 torture_comment(tctx, #call " level %u failed - %s (%s)\n", \
1441 r.in.level, nt_errstr(status), __location__); \
1442 ret = false; \
1443 break; \
1445 if (!W_ERROR_IS_OK(r.out.result)) { \
1446 torture_comment(tctx, #call " level %u failed - %s (%s)\n", \
1447 r.in.level, win_errstr(r.out.result), __location__); \
1448 ret = false; \
1449 break; \
1453 #define TESTSETCALL_EXP(call, r, err) \
1454 clear_info2(&info_ctr);\
1455 status = dcerpc_spoolss_ ##call## _r(b, tctx, &r); \
1456 if (!NT_STATUS_IS_OK(status)) { \
1457 torture_comment(tctx, #call " level %u failed - %s (%s)\n", \
1458 r.in.info_ctr->level, nt_errstr(status), __location__); \
1459 ret = false; \
1460 break; \
1462 if (!W_ERROR_IS_OK(err)) { \
1463 if (!W_ERROR_EQUAL(err, r.out.result)) { \
1464 torture_comment(tctx, #call " level %u failed - %s, expected %s (%s)\n", \
1465 r.in.info_ctr->level, win_errstr(r.out.result), win_errstr(err), __location__); \
1466 ret = false; \
1468 break; \
1470 if (!W_ERROR_IS_OK(r.out.result)) { \
1471 torture_comment(tctx, #call " level %u failed - %s (%s)\n", \
1472 r.in.info_ctr->level, win_errstr(r.out.result), __location__); \
1473 ret = false; \
1474 break; \
1477 #define TESTSETCALL(call, r) \
1478 TESTSETCALL_EXP(call, r, WERR_OK)
1480 #define STRING_EQUAL(s1, s2, field) \
1481 if ((s1 && !s2) || (s2 && !s1) || strcmp(s1, s2)) { \
1482 torture_comment(tctx, "Failed to set %s to '%s' (%s)\n", \
1483 #field, s2, __location__); \
1484 ret = false; \
1485 break; \
1488 #define MEM_EQUAL(s1, s2, length, field) \
1489 if ((s1 && !s2) || (s2 && !s1) || memcmp(s1, s2, length)) { \
1490 torture_comment(tctx, "Failed to set %s to '%s' (%s)\n", \
1491 #field, (const char *)s2, __location__); \
1492 ret = false; \
1493 break; \
1496 #define INT_EQUAL(i1, i2, field) \
1497 if (i1 != i2) { \
1498 torture_comment(tctx, "Failed to set %s to 0x%llx - got 0x%llx (%s)\n", \
1499 #field, (unsigned long long)i2, (unsigned long long)i1, __location__); \
1500 ret = false; \
1501 break; \
1504 #define SD_EQUAL(sd1, sd2, field) \
1505 if (!security_descriptor_equal(sd1, sd2)) { \
1506 torture_comment(tctx, "Failed to set %s (%s)\n", \
1507 #field, __location__); \
1508 ret = false; \
1509 break; \
1512 #define TEST_PRINTERINFO_STRING_EXP_ERR(lvl1, field1, lvl2, field2, value, err) do { \
1513 torture_comment(tctx, "field test %d/%s vs %d/%s\n", lvl1, #field1, lvl2, #field2); \
1514 q.in.level = lvl1; \
1515 TESTGETCALL(GetPrinter, q) \
1516 info_ctr.level = lvl1; \
1517 info_ctr.info.info ## lvl1 = (struct spoolss_SetPrinterInfo ## lvl1 *)(void *)&q.out.info->info ## lvl1; \
1518 info_ctr.info.info ## lvl1->field1 = value;\
1519 TESTSETCALL_EXP(SetPrinter, s, err) \
1520 info_ctr.info.info ## lvl1->field1 = ""; \
1521 TESTGETCALL(GetPrinter, q) \
1522 info_ctr.info.info ## lvl1->field1 = value; \
1523 STRING_EQUAL(info_ctr.info.info ## lvl1->field1, value, field1); \
1524 q.in.level = lvl2; \
1525 TESTGETCALL(GetPrinter, q) \
1526 info_ctr.info.info ## lvl2 = (struct spoolss_SetPrinterInfo ## lvl2 *)(void *)&q.out.info->info ## lvl2; \
1527 STRING_EQUAL(info_ctr.info.info ## lvl2->field2, value, field2); \
1528 } while (0)
1530 #define TEST_PRINTERINFO_STRING(lvl1, field1, lvl2, field2, value) do { \
1531 TEST_PRINTERINFO_STRING_EXP_ERR(lvl1, field1, lvl2, field2, value, WERR_OK); \
1532 } while (0);
1534 #define TEST_PRINTERINFO_INT_EXP(lvl1, field1, lvl2, field2, value, exp_value) do { \
1535 torture_comment(tctx, "field test %d/%s vs %d/%s\n", lvl1, #field1, lvl2, #field2); \
1536 q.in.level = lvl1; \
1537 TESTGETCALL(GetPrinter, q) \
1538 info_ctr.level = lvl1; \
1539 info_ctr.info.info ## lvl1 = (struct spoolss_SetPrinterInfo ## lvl1 *)(void *)&q.out.info->info ## lvl1; \
1540 info_ctr.info.info ## lvl1->field1 = value; \
1541 TESTSETCALL(SetPrinter, s) \
1542 info_ctr.info.info ## lvl1->field1 = 0; \
1543 TESTGETCALL(GetPrinter, q) \
1544 info_ctr.info.info ## lvl1 = (struct spoolss_SetPrinterInfo ## lvl1 *)(void *)&q.out.info->info ## lvl1; \
1545 INT_EQUAL(info_ctr.info.info ## lvl1->field1, exp_value, field1); \
1546 q.in.level = lvl2; \
1547 TESTGETCALL(GetPrinter, q) \
1548 info_ctr.info.info ## lvl2 = (struct spoolss_SetPrinterInfo ## lvl2 *)(void *)&q.out.info->info ## lvl2; \
1549 INT_EQUAL(info_ctr.info.info ## lvl2->field2, exp_value, field1); \
1550 } while (0)
1552 #define TEST_PRINTERINFO_INT(lvl1, field1, lvl2, field2, value) do { \
1553 TEST_PRINTERINFO_INT_EXP(lvl1, field1, lvl2, field2, value, value); \
1554 } while (0)
1556 q0.in.level = 0;
1557 do { TESTGETCALL(GetPrinter, q0) } while (0);
1559 TEST_PRINTERINFO_STRING(2, comment, 1, comment, "xx2-1 comment");
1560 TEST_PRINTERINFO_STRING(2, comment, 2, comment, "xx2-2 comment");
1562 /* level 0 printername does not stick */
1563 /* TEST_PRINTERINFO_STRING(2, printername, 0, printername, "xx2-0 printer"); */
1564 TEST_PRINTERINFO_STRING(2, printername, 1, name, "xx2-1 printer");
1565 TEST_PRINTERINFO_STRING(2, printername, 2, printername, "xx2-2 printer");
1566 TEST_PRINTERINFO_STRING(2, printername, 4, printername, "xx2-4 printer");
1567 TEST_PRINTERINFO_STRING(2, printername, 5, printername, "xx2-5 printer");
1568 /* TEST_PRINTERINFO_STRING(4, printername, 0, printername, "xx4-0 printer"); */
1569 TEST_PRINTERINFO_STRING(4, printername, 1, name, "xx4-1 printer");
1570 TEST_PRINTERINFO_STRING(4, printername, 2, printername, "xx4-2 printer");
1571 TEST_PRINTERINFO_STRING(4, printername, 4, printername, "xx4-4 printer");
1572 TEST_PRINTERINFO_STRING(4, printername, 5, printername, "xx4-5 printer");
1573 /* TEST_PRINTERINFO_STRING(5, printername, 0, printername, "xx5-0 printer"); */
1574 TEST_PRINTERINFO_STRING(5, printername, 1, name, "xx5-1 printer");
1575 TEST_PRINTERINFO_STRING(5, printername, 2, printername, "xx5-2 printer");
1576 TEST_PRINTERINFO_STRING(5, printername, 4, printername, "xx5-4 printer");
1577 TEST_PRINTERINFO_STRING(5, printername, 5, printername, "xx5-5 printer");
1579 /* servername can be set but does not stick
1580 TEST_PRINTERINFO_STRING(2, servername, 0, servername, "xx2-0 servername");
1581 TEST_PRINTERINFO_STRING(2, servername, 2, servername, "xx2-2 servername");
1582 TEST_PRINTERINFO_STRING(2, servername, 4, servername, "xx2-4 servername");
1585 /* passing an invalid port will result in WERR_UNKNOWN_PORT */
1586 TEST_PRINTERINFO_STRING_EXP_ERR(2, portname, 2, portname, "xx2-2 portname", WERR_UNKNOWN_PORT);
1587 TEST_PRINTERINFO_STRING_EXP_ERR(2, portname, 5, portname, "xx2-5 portname", WERR_UNKNOWN_PORT);
1588 TEST_PRINTERINFO_STRING_EXP_ERR(5, portname, 2, portname, "xx5-2 portname", WERR_UNKNOWN_PORT);
1589 TEST_PRINTERINFO_STRING_EXP_ERR(5, portname, 5, portname, "xx5-5 portname", WERR_UNKNOWN_PORT);
1591 TEST_PRINTERINFO_STRING(2, sharename, 2, sharename, "xx2-2 sharename");
1592 /* passing an invalid driver will result in WERR_UNKNOWN_PRINTER_DRIVER */
1593 TEST_PRINTERINFO_STRING_EXP_ERR(2, drivername, 2, drivername, "xx2-2 drivername", WERR_UNKNOWN_PRINTER_DRIVER);
1594 TEST_PRINTERINFO_STRING(2, location, 2, location, "xx2-2 location");
1595 /* passing an invalid sepfile will result in WERR_INVALID_SEPARATOR_FILE */
1596 TEST_PRINTERINFO_STRING_EXP_ERR(2, sepfile, 2, sepfile, "xx2-2 sepfile", WERR_INVALID_SEPARATOR_FILE);
1597 /* passing an invalid printprocessor will result in WERR_UNKNOWN_PRINTPROCESSOR */
1598 TEST_PRINTERINFO_STRING_EXP_ERR(2, printprocessor, 2, printprocessor, "xx2-2 printprocessor", WERR_UNKNOWN_PRINTPROCESSOR);
1599 TEST_PRINTERINFO_STRING(2, datatype, 2, datatype, "xx2-2 datatype");
1600 TEST_PRINTERINFO_STRING(2, parameters, 2, parameters, "xx2-2 parameters");
1602 for (i=0; i < ARRAY_SIZE(attribute_list); i++) {
1603 /* TEST_PRINTERINFO_INT_EXP(2, attributes, 1, flags,
1604 attribute_list[i],
1605 (attribute_list[i] | default_attribute)
1606 ); */
1607 TEST_PRINTERINFO_INT_EXP(2, attributes, 2, attributes,
1608 attribute_list[i],
1609 (attribute_list[i] | default_attribute)
1611 TEST_PRINTERINFO_INT_EXP(2, attributes, 4, attributes,
1612 attribute_list[i],
1613 (attribute_list[i] | default_attribute)
1615 TEST_PRINTERINFO_INT_EXP(2, attributes, 5, attributes,
1616 attribute_list[i],
1617 (attribute_list[i] | default_attribute)
1619 /* TEST_PRINTERINFO_INT_EXP(4, attributes, 1, flags,
1620 attribute_list[i],
1621 (attribute_list[i] | default_attribute)
1622 ); */
1623 TEST_PRINTERINFO_INT_EXP(4, attributes, 2, attributes,
1624 attribute_list[i],
1625 (attribute_list[i] | default_attribute)
1627 TEST_PRINTERINFO_INT_EXP(4, attributes, 4, attributes,
1628 attribute_list[i],
1629 (attribute_list[i] | default_attribute)
1631 TEST_PRINTERINFO_INT_EXP(4, attributes, 5, attributes,
1632 attribute_list[i],
1633 (attribute_list[i] | default_attribute)
1635 /* TEST_PRINTERINFO_INT_EXP(5, attributes, 1, flags,
1636 attribute_list[i],
1637 (attribute_list[i] | default_attribute)
1638 ); */
1639 TEST_PRINTERINFO_INT_EXP(5, attributes, 2, attributes,
1640 attribute_list[i],
1641 (attribute_list[i] | default_attribute)
1643 TEST_PRINTERINFO_INT_EXP(5, attributes, 4, attributes,
1644 attribute_list[i],
1645 (attribute_list[i] | default_attribute)
1647 TEST_PRINTERINFO_INT_EXP(5, attributes, 5, attributes,
1648 attribute_list[i],
1649 (attribute_list[i] | default_attribute)
1653 for (i=0; i < ARRAY_SIZE(status_list); i++) {
1654 /* level 2 sets do not stick
1655 TEST_PRINTERINFO_INT(2, status, 0, status, status_list[i]);
1656 TEST_PRINTERINFO_INT(2, status, 2, status, status_list[i]);
1657 TEST_PRINTERINFO_INT(2, status, 6, status, status_list[i]); */
1658 TEST_PRINTERINFO_INT(6, status, 0, status, status_list[i]);
1659 TEST_PRINTERINFO_INT(6, status, 2, status, status_list[i]);
1660 TEST_PRINTERINFO_INT(6, status, 6, status, status_list[i]);
1663 /* priorities need to be between 0 and 99
1664 passing an invalid priority will result in WERR_INVALID_PRIORITY */
1665 TEST_PRINTERINFO_INT(2, priority, 2, priority, 0);
1666 TEST_PRINTERINFO_INT(2, priority, 2, priority, 1);
1667 TEST_PRINTERINFO_INT(2, priority, 2, priority, 99);
1668 /* TEST_PRINTERINFO_INT(2, priority, 2, priority, 100); */
1669 TEST_PRINTERINFO_INT(2, defaultpriority,2, defaultpriority, 0);
1670 TEST_PRINTERINFO_INT(2, defaultpriority,2, defaultpriority, 1);
1671 TEST_PRINTERINFO_INT(2, defaultpriority,2, defaultpriority, 99);
1672 /* TEST_PRINTERINFO_INT(2, defaultpriority,2, defaultpriority, 100); */
1674 TEST_PRINTERINFO_INT(2, starttime, 2, starttime, __LINE__);
1675 TEST_PRINTERINFO_INT(2, untiltime, 2, untiltime, __LINE__);
1677 /* does not stick
1678 TEST_PRINTERINFO_INT(2, cjobs, 2, cjobs, __LINE__);
1679 TEST_PRINTERINFO_INT(2, averageppm, 2, averageppm, __LINE__); */
1681 /* does not stick
1682 TEST_PRINTERINFO_INT(5, device_not_selected_timeout, 5, device_not_selected_timeout, __LINE__);
1683 TEST_PRINTERINFO_INT(5, transmission_retry_timeout, 5, transmission_retry_timeout, __LINE__); */
1685 /* FIXME: gd also test devmode and secdesc behavior */
1688 /* verify composition of level 1 description field */
1689 const char *description;
1690 const char *tmp;
1692 q0.in.level = 1;
1693 do { TESTGETCALL(GetPrinter, q0) } while (0);
1695 description = talloc_strdup(tctx, q0.out.info->info1.description);
1697 q0.in.level = 2;
1698 do { TESTGETCALL(GetPrinter, q0) } while (0);
1700 tmp = talloc_asprintf(tctx, "%s,%s,%s",
1701 q0.out.info->info2.printername,
1702 q0.out.info->info2.drivername,
1703 q0.out.info->info2.location);
1705 do { STRING_EQUAL(description, tmp, "description")} while (0);
1708 return ret;
1711 #define torture_assert_sid_equal(torture_ctx,got,expected,cmt)\
1712 do { struct dom_sid *__got = (got), *__expected = (expected); \
1713 if (!dom_sid_equal(__got, __expected)) { \
1714 torture_result(torture_ctx, TORTURE_FAIL, \
1715 __location__": "#got" was %s, expected %s: %s", \
1716 dom_sid_string(torture_ctx, __got), dom_sid_string(torture_ctx, __expected), cmt); \
1717 return false; \
1719 } while(0)
1721 static bool test_security_descriptor_equal(struct torture_context *tctx,
1722 const struct security_descriptor *sd1,
1723 const struct security_descriptor *sd2)
1725 if (sd1 == sd2) {
1726 return true;
1729 if (!sd1 || !sd2) {
1730 torture_comment(tctx, "%s\n", __location__);
1731 return false;
1734 torture_assert_int_equal(tctx, sd1->revision, sd2->revision, "revision mismatch");
1735 torture_assert_int_equal(tctx, sd1->type, sd2->type, "type mismatch");
1737 torture_assert_sid_equal(tctx, sd1->owner_sid, sd2->owner_sid, "owner mismatch");
1738 torture_assert_sid_equal(tctx, sd1->group_sid, sd2->group_sid, "group mismatch");
1740 if (!security_acl_equal(sd1->sacl, sd2->sacl)) {
1741 torture_comment(tctx, "%s: sacl mismatch\n", __location__);
1742 NDR_PRINT_DEBUG(security_acl, sd1->sacl);
1743 NDR_PRINT_DEBUG(security_acl, sd2->sacl);
1744 return false;
1746 if (!security_acl_equal(sd1->dacl, sd2->dacl)) {
1747 torture_comment(tctx, "%s: dacl mismatch\n", __location__);
1748 NDR_PRINT_DEBUG(security_acl, sd1->dacl);
1749 NDR_PRINT_DEBUG(security_acl, sd2->dacl);
1750 return false;
1753 return true;
1756 static bool test_sd_set_level(struct torture_context *tctx,
1757 struct dcerpc_binding_handle *b,
1758 struct policy_handle *handle,
1759 uint32_t level,
1760 struct security_descriptor *sd)
1762 struct spoolss_SetPrinterInfoCtr info_ctr;
1763 struct spoolss_DevmodeContainer devmode_ctr;
1764 struct sec_desc_buf secdesc_ctr;
1765 union spoolss_SetPrinterInfo sinfo;
1767 ZERO_STRUCT(devmode_ctr);
1768 ZERO_STRUCT(secdesc_ctr);
1770 switch (level) {
1771 case 2: {
1772 union spoolss_PrinterInfo info;
1773 torture_assert(tctx, test_GetPrinter_level(tctx, b, handle, 2, &info), "");
1774 torture_assert(tctx, PrinterInfo_to_SetPrinterInfo(tctx, &info, 2, &sinfo), "");
1776 info_ctr.level = 2;
1777 info_ctr.info = sinfo;
1779 break;
1781 case 3: {
1782 struct spoolss_SetPrinterInfo3 info3;
1784 info3.sec_desc_ptr = 0;
1786 info_ctr.level = 3;
1787 info_ctr.info.info3 = &info3;
1789 break;
1791 default:
1792 return false;
1795 secdesc_ctr.sd = sd;
1797 torture_assert(tctx,
1798 test_SetPrinter(tctx, b, handle, &info_ctr, &devmode_ctr, &secdesc_ctr, 0), "");
1800 return true;
1803 static bool test_PrinterInfo_SDs(struct torture_context *tctx,
1804 struct dcerpc_binding_handle *b,
1805 struct policy_handle *handle)
1807 union spoolss_PrinterInfo info;
1808 struct security_descriptor *sd1, *sd2;
1809 int i;
1811 /* just compare level 2 and level 3 */
1813 torture_assert(tctx, test_GetPrinter_level(tctx, b, handle, 2, &info), "");
1815 sd1 = info.info2.secdesc;
1817 torture_assert(tctx, test_GetPrinter_level(tctx, b, handle, 3, &info), "");
1819 sd2 = info.info3.secdesc;
1821 torture_assert(tctx, test_security_descriptor_equal(tctx, sd1, sd2),
1822 "SD level 2 != SD level 3");
1825 /* query level 2, set level 2, query level 2 */
1827 torture_assert(tctx, test_GetPrinter_level(tctx, b, handle, 2, &info), "");
1829 sd1 = info.info2.secdesc;
1831 torture_assert(tctx, test_sd_set_level(tctx, b, handle, 2, sd1), "");
1833 torture_assert(tctx, test_GetPrinter_level(tctx, b, handle, 2, &info), "");
1835 sd2 = info.info2.secdesc;
1836 if (sd1->type & SEC_DESC_DACL_DEFAULTED) {
1837 torture_comment(tctx, "removing SEC_DESC_DACL_DEFAULTED\n");
1838 sd1->type &= ~SEC_DESC_DACL_DEFAULTED;
1841 torture_assert(tctx, test_security_descriptor_equal(tctx, sd1, sd2),
1842 "SD level 2 != SD level 2 after SD has been set via level 2");
1845 /* query level 2, set level 3, query level 2 */
1847 torture_assert(tctx, test_GetPrinter_level(tctx, b, handle, 2, &info), "");
1849 sd1 = info.info2.secdesc;
1851 torture_assert(tctx, test_sd_set_level(tctx, b, handle, 3, sd1), "");
1853 torture_assert(tctx, test_GetPrinter_level(tctx, b, handle, 2, &info), "");
1855 sd2 = info.info2.secdesc;
1857 torture_assert(tctx, test_security_descriptor_equal(tctx, sd1, sd2),
1858 "SD level 2 != SD level 2 after SD has been set via level 3");
1860 /* set modified sd level 3, query level 2 */
1862 for (i=0; i < 93; i++) {
1863 struct security_ace a;
1864 const char *sid_string = talloc_asprintf(tctx, "S-1-5-32-9999%i", i);
1865 a.type = SEC_ACE_TYPE_ACCESS_ALLOWED;
1866 a.flags = 0;
1867 a.size = 0; /* autogenerated */
1868 a.access_mask = 0;
1869 a.trustee = *dom_sid_parse_talloc(tctx, sid_string);
1870 torture_assert_ntstatus_ok(tctx, security_descriptor_dacl_add(sd1, &a), "");
1873 torture_assert(tctx, test_sd_set_level(tctx, b, handle, 3, sd1), "");
1875 torture_assert(tctx, test_GetPrinter_level(tctx, b, handle, 2, &info), "");
1876 sd2 = info.info2.secdesc;
1878 if (sd1->type & SEC_DESC_DACL_DEFAULTED) {
1879 torture_comment(tctx, "removing SEC_DESC_DACL_DEFAULTED\n");
1880 sd1->type &= ~SEC_DESC_DACL_DEFAULTED;
1883 torture_assert(tctx, test_security_descriptor_equal(tctx, sd1, sd2),
1884 "modified SD level 2 != SD level 2 after SD has been set via level 3");
1887 return true;
1891 * wrapper call that saves original sd, runs tests, and restores sd
1894 static bool test_PrinterInfo_SD(struct torture_context *tctx,
1895 struct dcerpc_binding_handle *b,
1896 struct policy_handle *handle)
1898 union spoolss_PrinterInfo info;
1899 struct security_descriptor *sd;
1900 bool ret = true;
1902 torture_comment(tctx, "Testing Printer Security Descriptors\n");
1904 /* save original sd */
1906 torture_assert(tctx, test_GetPrinter_level(tctx, b, handle, 2, &info),
1907 "failed to get initial security descriptor");
1909 sd = security_descriptor_copy(tctx, info.info2.secdesc);
1911 /* run tests */
1913 ret = test_PrinterInfo_SDs(tctx, b, handle);
1915 /* restore original sd */
1917 torture_assert(tctx, test_sd_set_level(tctx, b, handle, 3, sd),
1918 "failed to restore initial security descriptor");
1920 torture_comment(tctx, "Printer Security Descriptors test %s\n\n",
1921 ret ? "succeeded" : "failed");
1924 return ret;
1927 static bool test_devmode_set_level(struct torture_context *tctx,
1928 struct dcerpc_binding_handle *b,
1929 struct policy_handle *handle,
1930 uint32_t level,
1931 struct spoolss_DeviceMode *devmode)
1933 struct spoolss_SetPrinterInfoCtr info_ctr;
1934 struct spoolss_DevmodeContainer devmode_ctr;
1935 struct sec_desc_buf secdesc_ctr;
1936 union spoolss_SetPrinterInfo sinfo;
1938 ZERO_STRUCT(devmode_ctr);
1939 ZERO_STRUCT(secdesc_ctr);
1941 switch (level) {
1942 case 2: {
1943 union spoolss_PrinterInfo info;
1944 torture_assert(tctx, test_GetPrinter_level(tctx, b, handle, 2, &info), "");
1945 torture_assert(tctx, PrinterInfo_to_SetPrinterInfo(tctx, &info, 2, &sinfo), "");
1947 info_ctr.level = 2;
1948 info_ctr.info = sinfo;
1950 break;
1952 case 8: {
1953 struct spoolss_SetPrinterInfo8 info8;
1955 info8.devmode_ptr = 0;
1957 info_ctr.level = 8;
1958 info_ctr.info.info8 = &info8;
1960 break;
1962 default:
1963 return false;
1966 devmode_ctr.devmode = devmode;
1968 torture_assert(tctx,
1969 test_SetPrinter(tctx, b, handle, &info_ctr, &devmode_ctr, &secdesc_ctr, 0), "");
1971 return true;
1975 static bool test_devicemode_equal(struct torture_context *tctx,
1976 const struct spoolss_DeviceMode *d1,
1977 const struct spoolss_DeviceMode *d2)
1979 if (d1 == d2) {
1980 return true;
1983 if (!d1 || !d2) {
1984 torture_comment(tctx, "%s\n", __location__);
1985 return false;
1987 torture_assert_str_equal(tctx, d1->devicename, d2->devicename, "devicename mismatch");
1988 torture_assert_int_equal(tctx, d1->specversion, d2->specversion, "specversion mismatch");
1989 torture_assert_int_equal(tctx, d1->driverversion, d2->driverversion, "driverversion mismatch");
1990 torture_assert_int_equal(tctx, d1->size, d2->size, "size mismatch");
1991 torture_assert_int_equal(tctx, d1->__driverextra_length, d2->__driverextra_length, "__driverextra_length mismatch");
1992 torture_assert_int_equal(tctx, d1->fields, d2->fields, "fields mismatch");
1993 torture_assert_int_equal(tctx, d1->orientation, d2->orientation, "orientation mismatch");
1994 torture_assert_int_equal(tctx, d1->papersize, d2->papersize, "papersize mismatch");
1995 torture_assert_int_equal(tctx, d1->paperlength, d2->paperlength, "paperlength mismatch");
1996 torture_assert_int_equal(tctx, d1->paperwidth, d2->paperwidth, "paperwidth mismatch");
1997 torture_assert_int_equal(tctx, d1->scale, d2->scale, "scale mismatch");
1998 torture_assert_int_equal(tctx, d1->copies, d2->copies, "copies mismatch");
1999 torture_assert_int_equal(tctx, d1->defaultsource, d2->defaultsource, "defaultsource mismatch");
2000 torture_assert_int_equal(tctx, d1->printquality, d2->printquality, "printquality mismatch");
2001 torture_assert_int_equal(tctx, d1->color, d2->color, "color mismatch");
2002 torture_assert_int_equal(tctx, d1->duplex, d2->duplex, "duplex mismatch");
2003 torture_assert_int_equal(tctx, d1->yresolution, d2->yresolution, "yresolution mismatch");
2004 torture_assert_int_equal(tctx, d1->ttoption, d2->ttoption, "ttoption mismatch");
2005 torture_assert_int_equal(tctx, d1->collate, d2->collate, "collate mismatch");
2006 torture_assert_str_equal(tctx, d1->formname, d2->formname, "formname mismatch");
2007 torture_assert_int_equal(tctx, d1->logpixels, d2->logpixels, "logpixels mismatch");
2008 torture_assert_int_equal(tctx, d1->bitsperpel, d2->bitsperpel, "bitsperpel mismatch");
2009 torture_assert_int_equal(tctx, d1->pelswidth, d2->pelswidth, "pelswidth mismatch");
2010 torture_assert_int_equal(tctx, d1->pelsheight, d2->pelsheight, "pelsheight mismatch");
2011 torture_assert_int_equal(tctx, d1->displayflags, d2->displayflags, "displayflags mismatch");
2012 torture_assert_int_equal(tctx, d1->displayfrequency, d2->displayfrequency, "displayfrequency mismatch");
2013 torture_assert_int_equal(tctx, d1->icmmethod, d2->icmmethod, "icmmethod mismatch");
2014 torture_assert_int_equal(tctx, d1->icmintent, d2->icmintent, "icmintent mismatch");
2015 torture_assert_int_equal(tctx, d1->mediatype, d2->mediatype, "mediatype mismatch");
2016 torture_assert_int_equal(tctx, d1->dithertype, d2->dithertype, "dithertype mismatch");
2017 torture_assert_int_equal(tctx, d1->reserved1, d2->reserved1, "reserved1 mismatch");
2018 torture_assert_int_equal(tctx, d1->reserved2, d2->reserved2, "reserved2 mismatch");
2019 torture_assert_int_equal(tctx, d1->panningwidth, d2->panningwidth, "panningwidth mismatch");
2020 torture_assert_int_equal(tctx, d1->panningheight, d2->panningheight, "panningheight mismatch");
2021 torture_assert_data_blob_equal(tctx, d1->driverextra_data, d2->driverextra_data, "driverextra_data mismatch");
2023 return true;
2026 static bool test_devicemode_full(struct torture_context *tctx,
2027 struct dcerpc_binding_handle *b,
2028 struct policy_handle *handle)
2030 struct spoolss_SetPrinter s;
2031 struct spoolss_GetPrinter q;
2032 struct spoolss_GetPrinter q0;
2033 struct spoolss_SetPrinterInfoCtr info_ctr;
2034 struct spoolss_SetPrinterInfo8 info8;
2035 union spoolss_PrinterInfo info;
2036 struct spoolss_DevmodeContainer devmode_ctr;
2037 struct sec_desc_buf secdesc_ctr;
2038 uint32_t needed;
2039 bool ret = true;
2040 NTSTATUS status;
2042 #define TEST_DEVMODE_INT_EXP(lvl1, field1, lvl2, field2, value, exp_value) do { \
2043 torture_comment(tctx, "field test %d/%s vs %d/%s\n", lvl1, #field1, lvl2, #field2); \
2044 q.in.level = lvl1; \
2045 TESTGETCALL(GetPrinter, q) \
2046 info_ctr.level = lvl1; \
2047 if (lvl1 == 2) {\
2048 info_ctr.info.info ## lvl1 = (struct spoolss_SetPrinterInfo ## lvl1 *)(void *)&q.out.info->info ## lvl1; \
2049 } else if (lvl1 == 8) {\
2050 info_ctr.info.info ## lvl1 = &info8; \
2052 devmode_ctr.devmode = q.out.info->info ## lvl1.devmode; \
2053 devmode_ctr.devmode->field1 = value; \
2054 TESTSETCALL(SetPrinter, s) \
2055 TESTGETCALL(GetPrinter, q) \
2056 INT_EQUAL(q.out.info->info ## lvl1.devmode->field1, exp_value, field1); \
2057 q.in.level = lvl2; \
2058 TESTGETCALL(GetPrinter, q) \
2059 INT_EQUAL(q.out.info->info ## lvl2.devmode->field2, exp_value, field1); \
2060 } while (0)
2062 #define TEST_DEVMODE_INT(lvl1, field1, lvl2, field2, value) do { \
2063 TEST_DEVMODE_INT_EXP(lvl1, field1, lvl2, field2, value, value); \
2064 } while (0)
2066 ZERO_STRUCT(devmode_ctr);
2067 ZERO_STRUCT(secdesc_ctr);
2068 ZERO_STRUCT(info8);
2070 s.in.handle = handle;
2071 s.in.command = 0;
2072 s.in.info_ctr = &info_ctr;
2073 s.in.devmode_ctr = &devmode_ctr;
2074 s.in.secdesc_ctr = &secdesc_ctr;
2076 q.in.handle = handle;
2077 q.out.info = &info;
2078 q0 = q;
2080 #if 0
2081 const char *devicename;/* [charset(UTF16)] */
2082 enum spoolss_DeviceModeSpecVersion specversion;
2083 uint16_t driverversion;
2084 uint16_t size;
2085 uint16_t __driverextra_length;/* [value(r->driverextra_data.length)] */
2086 uint32_t fields;
2087 #endif
2089 TEST_DEVMODE_INT(8, orientation, 8, orientation, __LINE__);
2090 TEST_DEVMODE_INT(8, papersize, 8, papersize, __LINE__);
2091 TEST_DEVMODE_INT(8, paperlength, 8, paperlength, __LINE__);
2092 TEST_DEVMODE_INT(8, paperwidth, 8, paperwidth, __LINE__);
2093 TEST_DEVMODE_INT(8, scale, 8, scale, __LINE__);
2094 TEST_DEVMODE_INT(8, copies, 8, copies, __LINE__);
2095 TEST_DEVMODE_INT(8, defaultsource, 8, defaultsource, __LINE__);
2096 TEST_DEVMODE_INT(8, printquality, 8, printquality, __LINE__);
2097 TEST_DEVMODE_INT(8, color, 8, color, __LINE__);
2098 TEST_DEVMODE_INT(8, duplex, 8, duplex, __LINE__);
2099 TEST_DEVMODE_INT(8, yresolution, 8, yresolution, __LINE__);
2100 TEST_DEVMODE_INT(8, ttoption, 8, ttoption, __LINE__);
2101 TEST_DEVMODE_INT(8, collate, 8, collate, __LINE__);
2102 #if 0
2103 const char *formname;/* [charset(UTF16)] */
2104 #endif
2105 TEST_DEVMODE_INT(8, logpixels, 8, logpixels, __LINE__);
2106 TEST_DEVMODE_INT(8, bitsperpel, 8, bitsperpel, __LINE__);
2107 TEST_DEVMODE_INT(8, pelswidth, 8, pelswidth, __LINE__);
2108 TEST_DEVMODE_INT(8, pelsheight, 8, pelsheight, __LINE__);
2109 TEST_DEVMODE_INT(8, displayflags, 8, displayflags, __LINE__);
2110 TEST_DEVMODE_INT(8, displayfrequency, 8, displayfrequency, __LINE__);
2111 TEST_DEVMODE_INT(8, icmmethod, 8, icmmethod, __LINE__);
2112 TEST_DEVMODE_INT(8, icmintent, 8, icmintent, __LINE__);
2113 TEST_DEVMODE_INT(8, mediatype, 8, mediatype, __LINE__);
2114 TEST_DEVMODE_INT(8, dithertype, 8, dithertype, __LINE__);
2115 TEST_DEVMODE_INT(8, reserved1, 8, reserved1, __LINE__);
2116 TEST_DEVMODE_INT(8, reserved2, 8, reserved2, __LINE__);
2117 TEST_DEVMODE_INT(8, panningwidth, 8, panningwidth, __LINE__);
2118 TEST_DEVMODE_INT(8, panningheight, 8, panningheight, __LINE__);
2120 return ret;
2123 static bool call_OpenPrinterEx(struct torture_context *tctx,
2124 struct dcerpc_pipe *p,
2125 const char *name,
2126 struct spoolss_DeviceMode *devmode,
2127 struct policy_handle *handle);
2129 static bool test_ClosePrinter(struct torture_context *tctx,
2130 struct dcerpc_binding_handle *b,
2131 struct policy_handle *handle);
2133 static bool test_PrinterInfo_DevModes(struct torture_context *tctx,
2134 struct dcerpc_pipe *p,
2135 struct policy_handle *handle,
2136 const char *name)
2138 union spoolss_PrinterInfo info;
2139 struct spoolss_DeviceMode *devmode;
2140 struct spoolss_DeviceMode *devmode2;
2141 struct policy_handle handle_devmode;
2142 struct dcerpc_binding_handle *b = p->binding_handle;
2144 /* simply compare level8 and level2 devmode */
2146 torture_assert(tctx, test_GetPrinter_level(tctx, b, handle, 8, &info), "");
2148 devmode = info.info8.devmode;
2150 torture_assert(tctx, test_GetPrinter_level(tctx, b, handle, 2, &info), "");
2152 devmode2 = info.info2.devmode;
2154 torture_assert(tctx, test_devicemode_equal(tctx, devmode, devmode2),
2155 "DM level 8 != DM level 2");
2158 /* set devicemode level 8 and see if it persists */
2160 devmode->copies = 93;
2161 devmode->formname = talloc_strdup(tctx, "Legal");
2163 torture_assert(tctx, test_devmode_set_level(tctx, b, handle, 8, devmode), "");
2165 torture_assert(tctx, test_GetPrinter_level(tctx, b, handle, 8, &info), "");
2167 devmode2 = info.info8.devmode;
2169 torture_assert(tctx, test_devicemode_equal(tctx, devmode, devmode2),
2170 "modified DM level 8 != DM level 8 after DM has been set via level 8");
2172 torture_assert(tctx, test_GetPrinter_level(tctx, b, handle, 2, &info), "");
2174 devmode2 = info.info2.devmode;
2176 torture_assert(tctx, test_devicemode_equal(tctx, devmode, devmode2),
2177 "modified DM level 8 != DM level 2");
2180 /* set devicemode level 2 and see if it persists */
2182 devmode->copies = 39;
2183 devmode->formname = talloc_strdup(tctx, "Executive");
2185 torture_assert(tctx, test_devmode_set_level(tctx, b, handle, 2, devmode), "");
2187 torture_assert(tctx, test_GetPrinter_level(tctx, b, handle, 8, &info), "");
2189 devmode2 = info.info8.devmode;
2191 torture_assert(tctx, test_devicemode_equal(tctx, devmode, devmode2),
2192 "modified DM level 8 != DM level 8 after DM has been set via level 2");
2194 torture_assert(tctx, test_GetPrinter_level(tctx, b, handle, 2, &info), "");
2196 devmode2 = info.info2.devmode;
2198 torture_assert(tctx, test_devicemode_equal(tctx, devmode, devmode2),
2199 "modified DM level 8 != DM level 2");
2202 /* check every single bit in public part of devicemode */
2204 torture_assert(tctx, test_devicemode_full(tctx, b, handle),
2205 "failed to set every single devicemode component");
2208 /* change formname upon open and see if it persists in getprinter calls */
2210 devmode->formname = talloc_strdup(tctx, "A4");
2211 devmode->copies = 42;
2213 torture_assert(tctx, call_OpenPrinterEx(tctx, p, name, devmode, &handle_devmode),
2214 "failed to open printer handle");
2216 torture_assert(tctx, test_GetPrinter_level(tctx, b, &handle_devmode, 8, &info), "");
2218 devmode2 = info.info8.devmode;
2220 if (strequal(devmode->devicename, devmode2->devicename)) {
2221 torture_warning(tctx, "devicenames are the same\n");
2222 } else {
2223 torture_comment(tctx, "devicename passed in for open: %s\n", devmode->devicename);
2224 torture_comment(tctx, "devicename after level 8 get: %s\n", devmode2->devicename);
2227 if (strequal(devmode->formname, devmode2->formname)) {
2228 torture_warning(tctx, "formname are the same\n");
2229 } else {
2230 torture_comment(tctx, "formname passed in for open: %s\n", devmode->formname);
2231 torture_comment(tctx, "formname after level 8 get: %s\n", devmode2->formname);
2234 if (devmode->copies == devmode2->copies) {
2235 torture_warning(tctx, "copies are the same\n");
2236 } else {
2237 torture_comment(tctx, "copies passed in for open: %d\n", devmode->copies);
2238 torture_comment(tctx, "copies after level 8 get: %d\n", devmode2->copies);
2241 torture_assert(tctx, test_GetPrinter_level(tctx, b, &handle_devmode, 2, &info), "");
2243 devmode2 = info.info2.devmode;
2245 if (strequal(devmode->devicename, devmode2->devicename)) {
2246 torture_warning(tctx, "devicenames are the same\n");
2247 } else {
2248 torture_comment(tctx, "devicename passed in for open: %s\n", devmode->devicename);
2249 torture_comment(tctx, "devicename after level 2 get: %s\n", devmode2->devicename);
2252 if (strequal(devmode->formname, devmode2->formname)) {
2253 torture_warning(tctx, "formname is the same\n");
2254 } else {
2255 torture_comment(tctx, "formname passed in for open: %s\n", devmode->formname);
2256 torture_comment(tctx, "formname after level 2 get: %s\n", devmode2->formname);
2259 if (devmode->copies == devmode2->copies) {
2260 torture_warning(tctx, "copies are the same\n");
2261 } else {
2262 torture_comment(tctx, "copies passed in for open: %d\n", devmode->copies);
2263 torture_comment(tctx, "copies after level 2 get: %d\n", devmode2->copies);
2266 test_ClosePrinter(tctx, b, &handle_devmode);
2268 return true;
2272 * wrapper call that saves original devmode, runs tests, and restores devmode
2275 static bool test_PrinterInfo_DevMode(struct torture_context *tctx,
2276 struct dcerpc_pipe *p,
2277 struct policy_handle *handle,
2278 const char *name,
2279 struct spoolss_DeviceMode *addprinter_devmode)
2281 union spoolss_PrinterInfo info;
2282 struct spoolss_DeviceMode *devmode;
2283 bool ret = true;
2284 struct dcerpc_binding_handle *b = p->binding_handle;
2286 torture_comment(tctx, "Testing Printer Devicemodes\n");
2288 /* save original devmode */
2290 torture_assert(tctx, test_GetPrinter_level(tctx, b, handle, 8, &info),
2291 "failed to get initial global devicemode");
2293 devmode = info.info8.devmode;
2295 if (addprinter_devmode) {
2296 if (!test_devicemode_equal(tctx, devmode, addprinter_devmode)) {
2297 torture_warning(tctx, "current global DM is != DM provided in addprinter");
2301 /* run tests */
2303 ret = test_PrinterInfo_DevModes(tctx, p, handle, name);
2305 /* restore original devmode */
2307 torture_assert(tctx, test_devmode_set_level(tctx, b, handle, 8, devmode),
2308 "failed to restore initial global device mode");
2310 torture_comment(tctx, "Printer Devicemodes test %s\n\n",
2311 ret ? "succeeded" : "failed");
2314 return ret;
2317 static bool test_ClosePrinter(struct torture_context *tctx,
2318 struct dcerpc_binding_handle *b,
2319 struct policy_handle *handle)
2321 NTSTATUS status;
2322 struct spoolss_ClosePrinter r;
2324 r.in.handle = handle;
2325 r.out.handle = handle;
2327 torture_comment(tctx, "Testing ClosePrinter\n");
2329 status = dcerpc_spoolss_ClosePrinter_r(b, tctx, &r);
2330 torture_assert_ntstatus_ok(tctx, status, "ClosePrinter failed");
2331 torture_assert_werr_ok(tctx, r.out.result, "ClosePrinter failed");
2333 return true;
2336 static bool test_GetForm_args(struct torture_context *tctx,
2337 struct dcerpc_binding_handle *b,
2338 struct policy_handle *handle,
2339 const char *form_name,
2340 uint32_t level,
2341 union spoolss_FormInfo *info_p)
2343 NTSTATUS status;
2344 struct spoolss_GetForm r;
2345 uint32_t needed;
2347 r.in.handle = handle;
2348 r.in.form_name = form_name;
2349 r.in.level = level;
2350 r.in.buffer = NULL;
2351 r.in.offered = 0;
2352 r.out.needed = &needed;
2354 torture_comment(tctx, "Testing GetForm(%s) level %d\n", form_name, r.in.level);
2356 status = dcerpc_spoolss_GetForm_r(b, tctx, &r);
2357 torture_assert_ntstatus_ok(tctx, status, "GetForm failed");
2359 if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
2360 DATA_BLOB blob = data_blob_talloc_zero(tctx, needed);
2361 r.in.buffer = &blob;
2362 r.in.offered = needed;
2363 status = dcerpc_spoolss_GetForm_r(b, tctx, &r);
2364 torture_assert_ntstatus_ok(tctx, status, "GetForm failed");
2366 torture_assert_werr_ok(tctx, r.out.result, "GetForm failed");
2368 torture_assert(tctx, r.out.info, "No form info returned");
2371 torture_assert_werr_ok(tctx, r.out.result, "GetForm failed");
2373 CHECK_NEEDED_SIZE_LEVEL(spoolss_FormInfo, r.out.info, r.in.level, needed, 4);
2375 if (info_p) {
2376 *info_p = *r.out.info;
2379 return true;
2382 static bool test_GetForm(struct torture_context *tctx,
2383 struct dcerpc_binding_handle *b,
2384 struct policy_handle *handle,
2385 const char *form_name,
2386 uint32_t level)
2388 return test_GetForm_args(tctx, b, handle, form_name, level, NULL);
2391 static bool test_EnumForms(struct torture_context *tctx,
2392 struct dcerpc_binding_handle *b,
2393 struct policy_handle *handle,
2394 bool print_server,
2395 uint32_t level,
2396 uint32_t *count_p,
2397 union spoolss_FormInfo **info_p)
2399 struct spoolss_EnumForms r;
2400 uint32_t needed;
2401 uint32_t count;
2402 union spoolss_FormInfo *info;
2404 r.in.handle = handle;
2405 r.in.level = level;
2406 r.in.buffer = NULL;
2407 r.in.offered = 0;
2408 r.out.needed = &needed;
2409 r.out.count = &count;
2410 r.out.info = &info;
2412 torture_comment(tctx, "Testing EnumForms level %d\n", r.in.level);
2414 torture_assert_ntstatus_ok(tctx,
2415 dcerpc_spoolss_EnumForms_r(b, tctx, &r),
2416 "EnumForms failed");
2418 if ((r.in.level == 2) && (W_ERROR_EQUAL(r.out.result, WERR_UNKNOWN_LEVEL))) {
2419 torture_skip(tctx, "EnumForms level 2 not supported");
2422 if (print_server && W_ERROR_EQUAL(r.out.result, WERR_BADFID)) {
2423 torture_fail(tctx, "EnumForms on the PrintServer isn't supported by test server (NT4)");
2426 if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
2427 DATA_BLOB blob = data_blob_talloc_zero(tctx, needed);
2428 r.in.buffer = &blob;
2429 r.in.offered = needed;
2431 torture_assert_ntstatus_ok(tctx,
2432 dcerpc_spoolss_EnumForms_r(b, tctx, &r),
2433 "EnumForms failed");
2435 torture_assert(tctx, info, "No forms returned");
2438 torture_assert_werr_ok(tctx, r.out.result, "EnumForms failed");
2440 CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumForms, info, r.in.level, count, needed, 4);
2442 if (info_p) {
2443 *info_p = info;
2445 if (count_p) {
2446 *count_p = count;
2449 return true;
2452 static bool test_EnumForms_all(struct torture_context *tctx,
2453 struct dcerpc_binding_handle *b,
2454 struct policy_handle *handle,
2455 bool print_server)
2457 uint32_t levels[] = { 1, 2 };
2458 int i, j;
2460 for (i=0; i<ARRAY_SIZE(levels); i++) {
2462 uint32_t count = 0;
2463 union spoolss_FormInfo *info = NULL;
2465 torture_assert(tctx,
2466 test_EnumForms(tctx, b, handle, print_server, levels[i], &count, &info),
2467 "failed to enum forms");
2469 for (j = 0; j < count; j++) {
2470 if (!print_server) {
2471 torture_assert(tctx,
2472 test_GetForm(tctx, b, handle, info[j].info1.form_name, levels[i]),
2473 "failed to get form");
2478 return true;
2481 static bool test_EnumForms_find_one(struct torture_context *tctx,
2482 struct dcerpc_binding_handle *b,
2483 struct policy_handle *handle,
2484 bool print_server,
2485 const char *form_name)
2487 union spoolss_FormInfo *info;
2488 uint32_t count;
2489 bool found = false;
2490 int i;
2492 torture_assert(tctx,
2493 test_EnumForms(tctx, b, handle, print_server, 1, &count, &info),
2494 "failed to enumerate forms");
2496 for (i=0; i<count; i++) {
2497 if (strequal(form_name, info[i].info1.form_name)) {
2498 found = true;
2499 break;
2503 return found;
2506 static bool test_DeleteForm(struct torture_context *tctx,
2507 struct dcerpc_binding_handle *b,
2508 struct policy_handle *handle,
2509 const char *form_name,
2510 WERROR expected_result)
2512 struct spoolss_DeleteForm r;
2514 r.in.handle = handle;
2515 r.in.form_name = form_name;
2517 torture_comment(tctx, "Testing DeleteForm(%s)\n", form_name);
2519 torture_assert_ntstatus_ok(tctx,
2520 dcerpc_spoolss_DeleteForm_r(b, tctx, &r),
2521 "DeleteForm failed");
2522 torture_assert_werr_equal(tctx, r.out.result, expected_result,
2523 "DeleteForm gave unexpected result");
2524 if (W_ERROR_IS_OK(r.out.result)) {
2525 torture_assert_ntstatus_ok(tctx,
2526 dcerpc_spoolss_DeleteForm_r(b, tctx, &r),
2527 "2nd DeleteForm failed");
2528 torture_assert_werr_equal(tctx, r.out.result, WERR_INVALID_FORM_NAME,
2529 "2nd DeleteForm failed");
2532 return true;
2535 static bool test_AddForm(struct torture_context *tctx,
2536 struct dcerpc_binding_handle *b,
2537 struct policy_handle *handle,
2538 uint32_t level,
2539 union spoolss_AddFormInfo *info,
2540 WERROR expected_result)
2542 struct spoolss_AddForm r;
2544 if (level != 1) {
2545 torture_skip(tctx, "only level 1 supported");
2548 r.in.handle = handle;
2549 r.in.level = level;
2550 r.in.info = *info;
2552 torture_comment(tctx, "Testing AddForm(%s) level %d, type %d\n",
2553 r.in.info.info1->form_name, r.in.level,
2554 r.in.info.info1->flags);
2556 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_AddForm_r(b, tctx, &r),
2557 "AddForm failed");
2558 torture_assert_werr_equal(tctx, r.out.result, expected_result,
2559 "AddForm gave unexpected result");
2561 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_AddForm_r(b, tctx, &r),
2562 "2nd AddForm failed");
2563 if (W_ERROR_EQUAL(expected_result, WERR_INVALID_PARAM)) {
2564 torture_assert_werr_equal(tctx, r.out.result, WERR_INVALID_PARAM,
2565 "2nd AddForm gave unexpected result");
2566 } else {
2567 torture_assert_werr_equal(tctx, r.out.result, WERR_FILE_EXISTS,
2568 "2nd AddForm gave unexpected result");
2571 return true;
2574 static bool test_SetForm(struct torture_context *tctx,
2575 struct dcerpc_binding_handle *b,
2576 struct policy_handle *handle,
2577 const char *form_name,
2578 uint32_t level,
2579 union spoolss_AddFormInfo *info)
2581 struct spoolss_SetForm r;
2583 r.in.handle = handle;
2584 r.in.form_name = form_name;
2585 r.in.level = level;
2586 r.in.info = *info;
2588 torture_comment(tctx, "Testing SetForm(%s) level %d\n",
2589 form_name, r.in.level);
2591 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_SetForm_r(b, tctx, &r),
2592 "SetForm failed");
2594 torture_assert_werr_ok(tctx, r.out.result,
2595 "SetForm failed");
2597 return true;
2600 static bool test_GetForm_winreg(struct torture_context *tctx,
2601 struct dcerpc_binding_handle *b,
2602 struct policy_handle *handle,
2603 const char *key_name,
2604 const char *form_name,
2605 enum winreg_Type *w_type,
2606 uint32_t *w_size,
2607 uint32_t *w_length,
2608 uint8_t **w_data);
2610 static bool test_Forms_args(struct torture_context *tctx,
2611 struct dcerpc_binding_handle *b,
2612 struct policy_handle *handle,
2613 bool print_server,
2614 const char *printer_name,
2615 struct dcerpc_binding_handle *winreg_handle,
2616 struct policy_handle *hive_handle,
2617 const char *form_name,
2618 struct spoolss_AddFormInfo1 *info1,
2619 WERROR expected_add_result,
2620 WERROR expected_delete_result)
2622 union spoolss_FormInfo info;
2623 union spoolss_AddFormInfo add_info;
2625 enum winreg_Type w_type;
2626 uint32_t w_size;
2627 uint32_t w_length;
2628 uint8_t *w_data;
2630 add_info.info1 = info1;
2632 torture_assert(tctx,
2633 test_AddForm(tctx, b, handle, 1, &add_info, expected_add_result),
2634 "failed to add form");
2636 if (winreg_handle && hive_handle && W_ERROR_IS_OK(expected_add_result)) {
2638 torture_assert(tctx,
2639 test_GetForm_winreg(tctx, winreg_handle, hive_handle, TOP_LEVEL_CONTROL_FORMS_KEY, form_name, &w_type, &w_size, &w_length, &w_data),
2640 "failed to get form via winreg");
2642 torture_assert_int_equal(tctx, w_type, REG_BINARY, "unexpected type");
2643 torture_assert_int_equal(tctx, w_size, 0x20, "unexpected size");
2644 torture_assert_int_equal(tctx, w_length, 0x20, "unexpected length");
2645 torture_assert_mem_equal(tctx, &w_data[0], &add_info.info1->size.width, 4, "width mismatch");
2646 torture_assert_mem_equal(tctx, &w_data[4], &add_info.info1->size.height, 4, "height mismatch");
2647 torture_assert_mem_equal(tctx, &w_data[8], &add_info.info1->area.left, 4, "left mismatch");
2648 torture_assert_mem_equal(tctx, &w_data[12], &add_info.info1->area.top, 4, "top mismatch");
2649 torture_assert_mem_equal(tctx, &w_data[16], &add_info.info1->area.right, 4, "right mismatch");
2650 torture_assert_mem_equal(tctx, &w_data[20], &add_info.info1->area.bottom, 4, "bottom mismatch");
2651 /* skip index here */
2652 torture_assert_mem_equal(tctx, &w_data[28], &add_info.info1->flags, 4, "flags mismatch");
2655 if (!print_server && W_ERROR_IS_OK(expected_add_result)) {
2656 torture_assert(tctx,
2657 test_GetForm_args(tctx, b, handle, form_name, 1, &info),
2658 "failed to get added form");
2660 torture_assert_int_equal(tctx, info.info1.size.width, add_info.info1->size.width, "width mismatch");
2661 torture_assert_int_equal(tctx, info.info1.size.height, add_info.info1->size.height, "height mismatch");
2662 torture_assert_int_equal(tctx, info.info1.area.left, add_info.info1->area.left, "left mismatch");
2663 torture_assert_int_equal(tctx, info.info1.area.top, add_info.info1->area.top, "top mismatch");
2664 torture_assert_int_equal(tctx, info.info1.area.right, add_info.info1->area.right, "right mismatch");
2665 torture_assert_int_equal(tctx, info.info1.area.bottom, add_info.info1->area.bottom, "bottom mismatch");
2666 torture_assert_int_equal(tctx, info.info1.flags, add_info.info1->flags, "flags mismatch");
2668 if (winreg_handle && hive_handle) {
2669 torture_assert_mem_equal(tctx, &w_data[0], &info.info1.size.width, 4, "width mismatch");
2670 torture_assert_mem_equal(tctx, &w_data[4], &info.info1.size.height, 4, "height mismatch");
2671 torture_assert_mem_equal(tctx, &w_data[8], &info.info1.area.left, 4, "left mismatch");
2672 torture_assert_mem_equal(tctx, &w_data[12], &info.info1.area.top, 4, "top mismatch");
2673 torture_assert_mem_equal(tctx, &w_data[16], &info.info1.area.right, 4, "right mismatch");
2674 torture_assert_mem_equal(tctx, &w_data[20], &info.info1.area.bottom, 4, "bottom mismatch");
2675 /* skip index here */
2676 torture_assert_mem_equal(tctx, &w_data[28], &info.info1.flags, 4, "flags mismatch");
2679 add_info.info1->size.width = 1234;
2681 torture_assert(tctx,
2682 test_SetForm(tctx, b, handle, form_name, 1, &add_info),
2683 "failed to set form");
2684 torture_assert(tctx,
2685 test_GetForm_args(tctx, b, handle, form_name, 1, &info),
2686 "failed to get setted form");
2688 torture_assert_int_equal(tctx, info.info1.size.width, add_info.info1->size.width, "width mismatch");
2691 if (!W_ERROR_EQUAL(expected_add_result, WERR_INVALID_PARAM)) {
2692 torture_assert(tctx,
2693 test_EnumForms_find_one(tctx, b, handle, print_server, form_name),
2694 "Newly added form not found in enum call");
2697 torture_assert(tctx,
2698 test_DeleteForm(tctx, b, handle, form_name, expected_delete_result),
2699 "failed to delete form");
2701 return true;
2704 static bool test_Forms(struct torture_context *tctx,
2705 struct dcerpc_binding_handle *b,
2706 struct policy_handle *handle,
2707 bool print_server,
2708 const char *printer_name,
2709 struct dcerpc_binding_handle *winreg_handle,
2710 struct policy_handle *hive_handle)
2712 const struct spoolss_FormSize size = {
2713 .width = 50,
2714 .height = 25
2716 const struct spoolss_FormArea area = {
2717 .left = 5,
2718 .top = 10,
2719 .right = 45,
2720 .bottom = 15
2722 int i;
2724 struct {
2725 struct spoolss_AddFormInfo1 info1;
2726 WERROR expected_add_result;
2727 WERROR expected_delete_result;
2728 } forms[] = {
2730 .info1 = {
2731 .flags = SPOOLSS_FORM_USER,
2732 .form_name = "testform_user",
2733 .size = size,
2734 .area = area,
2736 .expected_add_result = WERR_OK,
2737 .expected_delete_result = WERR_OK
2740 weird, we can add a builtin form but we can never remove it
2741 again - gd
2744 .info1 = {
2745 .flags = SPOOLSS_FORM_BUILTIN,
2746 .form_name = "testform_builtin",
2747 .size = size,
2748 .area = area,
2750 .expected_add_result = WERR_OK,
2751 .expected_delete_result = WERR_INVALID_PARAM,
2755 .info1 = {
2756 .flags = SPOOLSS_FORM_PRINTER,
2757 .form_name = "testform_printer",
2758 .size = size,
2759 .area = area,
2761 .expected_add_result = WERR_OK,
2762 .expected_delete_result = WERR_OK
2765 .info1 = {
2766 .flags = SPOOLSS_FORM_USER,
2767 .form_name = "Letter",
2768 .size = size,
2769 .area = area,
2771 .expected_add_result = WERR_FILE_EXISTS,
2772 .expected_delete_result = WERR_INVALID_PARAM
2775 .info1 = {
2776 .flags = SPOOLSS_FORM_BUILTIN,
2777 .form_name = "Letter",
2778 .size = size,
2779 .area = area,
2781 .expected_add_result = WERR_FILE_EXISTS,
2782 .expected_delete_result = WERR_INVALID_PARAM
2785 .info1 = {
2786 .flags = SPOOLSS_FORM_PRINTER,
2787 .form_name = "Letter",
2788 .size = size,
2789 .area = area,
2791 .expected_add_result = WERR_FILE_EXISTS,
2792 .expected_delete_result = WERR_INVALID_PARAM
2795 .info1 = {
2796 .flags = 12345,
2797 .form_name = "invalid_flags",
2798 .size = size,
2799 .area = area,
2801 .expected_add_result = WERR_INVALID_PARAM,
2802 .expected_delete_result = WERR_INVALID_FORM_NAME
2807 for (i=0; i < ARRAY_SIZE(forms); i++) {
2808 torture_assert(tctx,
2809 test_Forms_args(tctx, b, handle, print_server, printer_name,
2810 winreg_handle, hive_handle,
2811 forms[i].info1.form_name,
2812 &forms[i].info1,
2813 forms[i].expected_add_result,
2814 forms[i].expected_delete_result),
2815 talloc_asprintf(tctx, "failed to test form '%s'", forms[i].info1.form_name));
2818 return true;
2821 static bool test_EnumPorts_old(struct torture_context *tctx,
2822 struct dcerpc_pipe *p)
2824 NTSTATUS status;
2825 struct spoolss_EnumPorts r;
2826 uint32_t needed;
2827 uint32_t count;
2828 union spoolss_PortInfo *info;
2829 struct dcerpc_binding_handle *b = p->binding_handle;
2831 r.in.servername = talloc_asprintf(tctx, "\\\\%s",
2832 dcerpc_server_name(p));
2833 r.in.level = 2;
2834 r.in.buffer = NULL;
2835 r.in.offered = 0;
2836 r.out.needed = &needed;
2837 r.out.count = &count;
2838 r.out.info = &info;
2840 torture_comment(tctx, "Testing EnumPorts\n");
2842 status = dcerpc_spoolss_EnumPorts_r(b, tctx, &r);
2844 torture_assert_ntstatus_ok(tctx, status, "EnumPorts failed");
2846 if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
2847 DATA_BLOB blob = data_blob_talloc_zero(tctx, needed);
2848 r.in.buffer = &blob;
2849 r.in.offered = needed;
2851 status = dcerpc_spoolss_EnumPorts_r(b, tctx, &r);
2852 torture_assert_ntstatus_ok(tctx, status, "EnumPorts failed");
2853 torture_assert_werr_ok(tctx, r.out.result, "EnumPorts failed");
2855 torture_assert(tctx, info, "No ports returned");
2858 torture_assert_werr_ok(tctx, r.out.result, "EnumPorts failed");
2860 CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumPorts, info, 2, count, needed, 4);
2862 return true;
2865 static bool test_AddPort(struct torture_context *tctx,
2866 struct dcerpc_pipe *p)
2868 NTSTATUS status;
2869 struct spoolss_AddPort r;
2870 struct dcerpc_binding_handle *b = p->binding_handle;
2872 r.in.server_name = talloc_asprintf(tctx, "\\\\%s",
2873 dcerpc_server_name(p));
2874 r.in.unknown = 0;
2875 r.in.monitor_name = "foo";
2877 torture_comment(tctx, "Testing AddPort\n");
2879 status = dcerpc_spoolss_AddPort_r(b, tctx, &r);
2881 torture_assert_ntstatus_ok(tctx, status, "AddPort failed");
2883 /* win2k3 returns WERR_NOT_SUPPORTED */
2885 #if 0
2887 if (!W_ERROR_IS_OK(r.out.result)) {
2888 printf("AddPort failed - %s\n", win_errstr(r.out.result));
2889 return false;
2892 #endif
2894 return true;
2897 static bool test_GetJob_args(struct torture_context *tctx,
2898 struct dcerpc_binding_handle *b,
2899 struct policy_handle *handle,
2900 uint32_t job_id,
2901 uint32_t level,
2902 union spoolss_JobInfo *info_p)
2904 NTSTATUS status;
2905 struct spoolss_GetJob r;
2906 union spoolss_JobInfo info;
2907 uint32_t needed;
2909 r.in.handle = handle;
2910 r.in.job_id = job_id;
2911 r.in.level = level;
2912 r.in.buffer = NULL;
2913 r.in.offered = 0;
2914 r.out.needed = &needed;
2915 r.out.info = &info;
2917 torture_comment(tctx, "Testing GetJob(%d), level %d\n", job_id, r.in.level);
2919 status = dcerpc_spoolss_GetJob_r(b, tctx, &r);
2920 torture_assert_ntstatus_ok(tctx, status, "GetJob failed");
2921 if (level == 0) {
2922 torture_assert_werr_equal(tctx, r.out.result, WERR_UNKNOWN_LEVEL, "Unexpected return code");
2925 if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
2926 DATA_BLOB blob = data_blob_talloc_zero(tctx, needed);
2927 r.in.buffer = &blob;
2928 r.in.offered = needed;
2930 status = dcerpc_spoolss_GetJob_r(b, tctx, &r);
2931 torture_assert_ntstatus_ok(tctx, status, "GetJob failed");
2934 torture_assert_werr_ok(tctx, r.out.result, "GetJob failed");
2935 torture_assert(tctx, r.out.info, "No job info returned");
2937 CHECK_NEEDED_SIZE_LEVEL(spoolss_JobInfo, r.out.info, r.in.level, needed, 4);
2939 if (info_p) {
2940 *info_p = *r.out.info;
2943 return true;
2946 static bool test_GetJob(struct torture_context *tctx,
2947 struct dcerpc_binding_handle *b,
2948 struct policy_handle *handle,
2949 uint32_t job_id)
2951 uint32_t levels[] = {0, 1, 2 /* 3, 4 */};
2952 uint32_t i;
2954 for (i=0; i < ARRAY_SIZE(levels); i++) {
2955 torture_assert(tctx,
2956 test_GetJob_args(tctx, b, handle, job_id, levels[i], NULL),
2957 "GetJob failed");
2960 return true;
2963 static bool test_SetJob(struct torture_context *tctx,
2964 struct dcerpc_binding_handle *b,
2965 struct policy_handle *handle,
2966 uint32_t job_id,
2967 struct spoolss_JobInfoContainer *ctr,
2968 enum spoolss_JobControl command)
2970 NTSTATUS status;
2971 struct spoolss_SetJob r;
2973 r.in.handle = handle;
2974 r.in.job_id = job_id;
2975 r.in.ctr = ctr;
2976 r.in.command = command;
2978 switch (command) {
2979 case SPOOLSS_JOB_CONTROL_PAUSE:
2980 torture_comment(tctx, "Testing SetJob(%d), SPOOLSS_JOB_CONTROL_PAUSE\n", job_id);
2981 break;
2982 case SPOOLSS_JOB_CONTROL_RESUME:
2983 torture_comment(tctx, "Testing SetJob(%d), SPOOLSS_JOB_CONTROL_RESUME\n", job_id);
2984 break;
2985 case SPOOLSS_JOB_CONTROL_CANCEL:
2986 torture_comment(tctx, "Testing SetJob(%d), SPOOLSS_JOB_CONTROL_CANCEL\n", job_id);
2987 break;
2988 case SPOOLSS_JOB_CONTROL_RESTART:
2989 torture_comment(tctx, "Testing SetJob(%d), SPOOLSS_JOB_CONTROL_RESTART\n", job_id);
2990 break;
2991 case SPOOLSS_JOB_CONTROL_DELETE:
2992 torture_comment(tctx, "Testing SetJob(%d), SPOOLSS_JOB_CONTROL_DELETE\n", job_id);
2993 break;
2994 case SPOOLSS_JOB_CONTROL_SEND_TO_PRINTER:
2995 torture_comment(tctx, "Testing SetJob(%d), SPOOLSS_JOB_CONTROL_SEND_TO_PRINTER\n", job_id);
2996 break;
2997 case SPOOLSS_JOB_CONTROL_LAST_PAGE_EJECTED:
2998 torture_comment(tctx, "Testing SetJob(%d), SPOOLSS_JOB_CONTROL_LAST_PAGE_EJECTED\n", job_id);
2999 break;
3000 case SPOOLSS_JOB_CONTROL_RETAIN:
3001 torture_comment(tctx, "Testing SetJob(%d), SPOOLSS_JOB_CONTROL_RETAIN\n", job_id);
3002 break;
3003 case SPOOLSS_JOB_CONTROL_RELEASE:
3004 torture_comment(tctx, "Testing SetJob(%d), SPOOLSS_JOB_CONTROL_RELEASE\n", job_id);
3005 break;
3006 default:
3007 torture_comment(tctx, "Testing SetJob(%d)\n", job_id);
3008 break;
3011 status = dcerpc_spoolss_SetJob_r(b, tctx, &r);
3012 torture_assert_ntstatus_ok(tctx, status, "SetJob failed");
3013 torture_assert_werr_ok(tctx, r.out.result, "SetJob failed");
3015 return true;
3018 static bool test_AddJob(struct torture_context *tctx,
3019 struct dcerpc_binding_handle *b,
3020 struct policy_handle *handle)
3022 NTSTATUS status;
3023 struct spoolss_AddJob r;
3024 uint32_t needed;
3026 r.in.level = 0;
3027 r.in.handle = handle;
3028 r.in.offered = 0;
3029 r.out.needed = &needed;
3030 r.in.buffer = r.out.buffer = NULL;
3032 torture_comment(tctx, "Testing AddJob\n");
3034 status = dcerpc_spoolss_AddJob_r(b, tctx, &r);
3035 torture_assert_werr_equal(tctx, r.out.result, WERR_UNKNOWN_LEVEL, "AddJob failed");
3037 r.in.level = 1;
3039 status = dcerpc_spoolss_AddJob_r(b, tctx, &r);
3040 torture_assert_werr_equal(tctx, r.out.result, WERR_INVALID_PARAM, "AddJob failed");
3042 return true;
3046 static bool test_EnumJobs_args(struct torture_context *tctx,
3047 struct dcerpc_binding_handle *b,
3048 struct policy_handle *handle,
3049 uint32_t level,
3050 uint32_t *count_p,
3051 union spoolss_JobInfo **info_p)
3053 NTSTATUS status;
3054 struct spoolss_EnumJobs r;
3055 uint32_t needed;
3056 uint32_t count;
3057 union spoolss_JobInfo *info;
3059 r.in.handle = handle;
3060 r.in.firstjob = 0;
3061 r.in.numjobs = 0xffffffff;
3062 r.in.level = level;
3063 r.in.buffer = NULL;
3064 r.in.offered = 0;
3065 r.out.needed = &needed;
3066 r.out.count = &count;
3067 r.out.info = &info;
3069 torture_comment(tctx, "Testing EnumJobs level %d\n", level);
3071 status = dcerpc_spoolss_EnumJobs_r(b, tctx, &r);
3073 torture_assert_ntstatus_ok(tctx, status, "EnumJobs failed");
3075 if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
3076 DATA_BLOB blob = data_blob_talloc_zero(tctx, needed);
3077 r.in.buffer = &blob;
3078 r.in.offered = needed;
3080 status = dcerpc_spoolss_EnumJobs_r(b, tctx, &r);
3082 torture_assert_ntstatus_ok(tctx, status, "EnumJobs failed");
3083 torture_assert_werr_ok(tctx, r.out.result, "EnumJobs failed");
3084 torture_assert(tctx, info, "No jobs returned");
3086 CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumJobs, *r.out.info, r.in.level, count, needed, 4);
3088 } else {
3089 torture_assert_werr_ok(tctx, r.out.result, "EnumJobs failed");
3092 if (count_p) {
3093 *count_p = count;
3095 if (info_p) {
3096 *info_p = info;
3099 return true;
3102 static bool test_DoPrintTest_add_one_job(struct torture_context *tctx,
3103 struct dcerpc_binding_handle *b,
3104 struct policy_handle *handle,
3105 uint32_t *job_id)
3107 NTSTATUS status;
3108 struct spoolss_StartDocPrinter s;
3109 struct spoolss_DocumentInfo1 info1;
3110 struct spoolss_StartPagePrinter sp;
3111 struct spoolss_WritePrinter w;
3112 struct spoolss_EndPagePrinter ep;
3113 struct spoolss_EndDocPrinter e;
3114 int i;
3115 uint32_t num_written;
3117 torture_comment(tctx, "Testing StartDocPrinter\n");
3119 s.in.handle = handle;
3120 s.in.level = 1;
3121 s.in.info.info1 = &info1;
3122 s.out.job_id = job_id;
3123 info1.document_name = "TorturePrintJob";
3124 info1.output_file = NULL;
3125 info1.datatype = "RAW";
3127 status = dcerpc_spoolss_StartDocPrinter_r(b, tctx, &s);
3128 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_StartDocPrinter failed");
3129 torture_assert_werr_ok(tctx, s.out.result, "StartDocPrinter failed");
3131 for (i=1; i < 4; i++) {
3132 torture_comment(tctx, "Testing StartPagePrinter: Page[%d], JobId[%d]\n", i, *job_id);
3134 sp.in.handle = handle;
3136 status = dcerpc_spoolss_StartPagePrinter_r(b, tctx, &sp);
3137 torture_assert_ntstatus_ok(tctx, status,
3138 "dcerpc_spoolss_StartPagePrinter failed");
3139 torture_assert_werr_ok(tctx, sp.out.result, "StartPagePrinter failed");
3141 torture_comment(tctx, "Testing WritePrinter: Page[%d], JobId[%d]\n", i, *job_id);
3143 w.in.handle = handle;
3144 w.in.data = data_blob_string_const(talloc_asprintf(tctx,"TortureTestPage: %d\nData\n",i));
3145 w.out.num_written = &num_written;
3147 status = dcerpc_spoolss_WritePrinter_r(b, tctx, &w);
3148 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_WritePrinter failed");
3149 torture_assert_werr_ok(tctx, w.out.result, "WritePrinter failed");
3151 torture_comment(tctx, "Testing EndPagePrinter: Page[%d], JobId[%d]\n", i, *job_id);
3153 ep.in.handle = handle;
3155 status = dcerpc_spoolss_EndPagePrinter_r(b, tctx, &ep);
3156 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EndPagePrinter failed");
3157 torture_assert_werr_ok(tctx, ep.out.result, "EndPagePrinter failed");
3160 torture_comment(tctx, "Testing EndDocPrinter: JobId[%d]\n", *job_id);
3162 e.in.handle = handle;
3164 status = dcerpc_spoolss_EndDocPrinter_r(b, tctx, &e);
3165 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EndDocPrinter failed");
3166 torture_assert_werr_ok(tctx, e.out.result, "EndDocPrinter failed");
3168 return true;
3171 static bool test_DoPrintTest_check_jobs(struct torture_context *tctx,
3172 struct dcerpc_binding_handle *b,
3173 struct policy_handle *handle,
3174 uint32_t num_jobs,
3175 uint32_t *job_ids)
3177 uint32_t count;
3178 union spoolss_JobInfo *info = NULL;
3179 int i;
3181 torture_assert(tctx,
3182 test_AddJob(tctx, b, handle),
3183 "AddJob failed");
3185 torture_assert(tctx,
3186 test_EnumJobs_args(tctx, b, handle, 1, &count, &info),
3187 "EnumJobs level 1 failed");
3189 torture_assert_int_equal(tctx, count, num_jobs, "unexpected number of jobs in queue");
3191 for (i=0; i < num_jobs; i++) {
3192 union spoolss_JobInfo ginfo;
3193 const char *document_name;
3194 const char *new_document_name = "any_other_docname";
3195 struct spoolss_JobInfoContainer ctr;
3196 struct spoolss_SetJobInfo1 info1;
3198 torture_assert_int_equal(tctx, info[i].info1.job_id, job_ids[i], "job id mismatch");
3200 torture_assert(tctx,
3201 test_GetJob_args(tctx, b, handle, info[i].info1.job_id, 1, &ginfo),
3202 "failed to call test_GetJob");
3204 torture_assert_int_equal(tctx, ginfo.info1.job_id, info[i].info1.job_id, "job id mismatch");
3206 document_name = ginfo.info1.document_name;
3208 info1.job_id = ginfo.info1.job_id;
3209 info1.printer_name = ginfo.info1.printer_name;
3210 info1.server_name = ginfo.info1.server_name;
3211 info1.user_name = ginfo.info1.user_name;
3212 info1.document_name = new_document_name;
3213 info1.data_type = ginfo.info1.data_type;
3214 info1.text_status = ginfo.info1.text_status;
3215 info1.status = ginfo.info1.status;
3216 info1.priority = ginfo.info1.priority;
3217 info1.position = ginfo.info1.position;
3218 info1.total_pages = ginfo.info1.total_pages;
3219 info1.pages_printed = ginfo.info1.pages_printed;
3220 info1.submitted = ginfo.info1.submitted;
3222 ctr.level = 1;
3223 ctr.info.info1 = &info1;
3225 torture_assert(tctx,
3226 test_SetJob(tctx, b, handle, info[i].info1.job_id, &ctr, 0),
3227 "failed to call test_SetJob level 1");
3229 torture_assert(tctx,
3230 test_GetJob_args(tctx, b, handle, info[i].info1.job_id, 1, &ginfo),
3231 "failed to call test_GetJob");
3233 if (strequal(ginfo.info1.document_name, document_name)) {
3234 torture_warning(tctx,
3235 talloc_asprintf(tctx, "document_name did *NOT* change from '%s' to '%s'\n",
3236 document_name, new_document_name));
3240 for (i=0; i < num_jobs; i++) {
3241 if (!test_SetJob(tctx, b, handle, info[i].info1.job_id, NULL, SPOOLSS_JOB_CONTROL_PAUSE)) {
3242 torture_warning(tctx, "failed to pause printjob\n");
3244 if (!test_SetJob(tctx, b, handle, info[i].info1.job_id, NULL, SPOOLSS_JOB_CONTROL_RESUME)) {
3245 torture_warning(tctx, "failed to resume printjob\n");
3249 return true;
3252 static bool test_DoPrintTest(struct torture_context *tctx,
3253 struct dcerpc_binding_handle *b,
3254 struct policy_handle *handle)
3256 bool ret = true;
3257 uint32_t num_jobs = 8;
3258 uint32_t *job_ids;
3259 int i;
3261 torture_comment(tctx, "Testing real print operations\n");
3263 job_ids = talloc_zero_array(tctx, uint32_t, num_jobs);
3265 for (i=0; i < num_jobs; i++) {
3266 ret &= test_DoPrintTest_add_one_job(tctx, b, handle, &job_ids[i]);
3269 for (i=0; i < num_jobs; i++) {
3270 ret &= test_SetJob(tctx, b, handle, job_ids[i], NULL, SPOOLSS_JOB_CONTROL_DELETE);
3273 if (ret == true) {
3274 torture_comment(tctx, "real print operations test succeeded\n\n");
3277 return ret;
3280 static bool test_DoPrintTest_extended(struct torture_context *tctx,
3281 struct dcerpc_binding_handle *b,
3282 struct policy_handle *handle)
3284 bool ret = true;
3285 uint32_t num_jobs = 8;
3286 uint32_t *job_ids;
3287 int i;
3288 torture_comment(tctx, "Testing real print operations (extended)\n");
3290 job_ids = talloc_zero_array(tctx, uint32_t, num_jobs);
3292 for (i=0; i < num_jobs; i++) {
3293 ret &= test_DoPrintTest_add_one_job(tctx, b, handle, &job_ids[i]);
3296 ret &= test_DoPrintTest_check_jobs(tctx, b, handle, num_jobs, job_ids);
3298 for (i=0; i < num_jobs; i++) {
3299 ret &= test_SetJob(tctx, b, handle, job_ids[i], NULL, SPOOLSS_JOB_CONTROL_DELETE);
3302 if (ret == true) {
3303 torture_comment(tctx, "real print operations (extended) test succeeded\n\n");
3306 return ret;
3309 static bool test_PausePrinter(struct torture_context *tctx,
3310 struct dcerpc_binding_handle *b,
3311 struct policy_handle *handle)
3313 NTSTATUS status;
3314 struct spoolss_SetPrinter r;
3315 struct spoolss_SetPrinterInfoCtr info_ctr;
3316 struct spoolss_DevmodeContainer devmode_ctr;
3317 struct sec_desc_buf secdesc_ctr;
3319 info_ctr.level = 0;
3320 info_ctr.info.info0 = NULL;
3322 ZERO_STRUCT(devmode_ctr);
3323 ZERO_STRUCT(secdesc_ctr);
3325 r.in.handle = handle;
3326 r.in.info_ctr = &info_ctr;
3327 r.in.devmode_ctr = &devmode_ctr;
3328 r.in.secdesc_ctr = &secdesc_ctr;
3329 r.in.command = SPOOLSS_PRINTER_CONTROL_PAUSE;
3331 torture_comment(tctx, "Testing SetPrinter: SPOOLSS_PRINTER_CONTROL_PAUSE\n");
3333 status = dcerpc_spoolss_SetPrinter_r(b, tctx, &r);
3335 torture_assert_ntstatus_ok(tctx, status, "SetPrinter failed");
3337 torture_assert_werr_ok(tctx, r.out.result, "SetPrinter failed");
3339 return true;
3342 static bool test_ResumePrinter(struct torture_context *tctx,
3343 struct dcerpc_binding_handle *b,
3344 struct policy_handle *handle)
3346 NTSTATUS status;
3347 struct spoolss_SetPrinter r;
3348 struct spoolss_SetPrinterInfoCtr info_ctr;
3349 struct spoolss_DevmodeContainer devmode_ctr;
3350 struct sec_desc_buf secdesc_ctr;
3352 info_ctr.level = 0;
3353 info_ctr.info.info0 = NULL;
3355 ZERO_STRUCT(devmode_ctr);
3356 ZERO_STRUCT(secdesc_ctr);
3358 r.in.handle = handle;
3359 r.in.info_ctr = &info_ctr;
3360 r.in.devmode_ctr = &devmode_ctr;
3361 r.in.secdesc_ctr = &secdesc_ctr;
3362 r.in.command = SPOOLSS_PRINTER_CONTROL_RESUME;
3364 torture_comment(tctx, "Testing SetPrinter: SPOOLSS_PRINTER_CONTROL_RESUME\n");
3366 status = dcerpc_spoolss_SetPrinter_r(b, tctx, &r);
3368 torture_assert_ntstatus_ok(tctx, status, "SetPrinter failed");
3370 torture_assert_werr_ok(tctx, r.out.result, "SetPrinter failed");
3372 return true;
3375 static bool test_GetPrinterData(struct torture_context *tctx,
3376 struct dcerpc_binding_handle *b,
3377 struct policy_handle *handle,
3378 const char *value_name,
3379 enum winreg_Type *type_p,
3380 uint8_t **data_p,
3381 uint32_t *needed_p)
3383 NTSTATUS status;
3384 struct spoolss_GetPrinterData r;
3385 uint32_t needed;
3386 enum winreg_Type type;
3387 union spoolss_PrinterData data;
3389 r.in.handle = handle;
3390 r.in.value_name = value_name;
3391 r.in.offered = 0;
3392 r.out.needed = &needed;
3393 r.out.type = &type;
3394 r.out.data = talloc_zero_array(tctx, uint8_t, r.in.offered);
3396 torture_comment(tctx, "Testing GetPrinterData(%s)\n", r.in.value_name);
3398 status = dcerpc_spoolss_GetPrinterData_r(b, tctx, &r);
3399 torture_assert_ntstatus_ok(tctx, status, "GetPrinterData failed");
3401 if (W_ERROR_EQUAL(r.out.result, WERR_MORE_DATA)) {
3402 r.in.offered = needed;
3403 r.out.data = talloc_zero_array(tctx, uint8_t, r.in.offered);
3404 status = dcerpc_spoolss_GetPrinterData_r(b, tctx, &r);
3405 torture_assert_ntstatus_ok(tctx, status, "GetPrinterData failed");
3408 torture_assert_werr_ok(tctx, r.out.result,
3409 talloc_asprintf(tctx, "GetPrinterData(%s) failed", r.in.value_name));
3411 CHECK_NEEDED_SIZE_LEVEL(spoolss_PrinterData, &data, type, needed, 1);
3413 if (type_p) {
3414 *type_p = type;
3417 if (data_p) {
3418 *data_p = r.out.data;
3421 if (needed_p) {
3422 *needed_p = needed;
3425 return true;
3428 static bool test_GetPrinterDataEx(struct torture_context *tctx,
3429 struct dcerpc_pipe *p,
3430 struct policy_handle *handle,
3431 const char *key_name,
3432 const char *value_name,
3433 enum winreg_Type *type_p,
3434 uint8_t **data_p,
3435 uint32_t *needed_p)
3437 NTSTATUS status;
3438 struct spoolss_GetPrinterDataEx r;
3439 enum winreg_Type type;
3440 uint32_t needed;
3441 union spoolss_PrinterData data;
3442 struct dcerpc_binding_handle *b = p->binding_handle;
3444 r.in.handle = handle;
3445 r.in.key_name = key_name;
3446 r.in.value_name = value_name;
3447 r.in.offered = 0;
3448 r.out.type = &type;
3449 r.out.needed = &needed;
3450 r.out.data = talloc_zero_array(tctx, uint8_t, r.in.offered);
3452 torture_comment(tctx, "Testing GetPrinterDataEx(%s - %s)\n",
3453 r.in.key_name, r.in.value_name);
3455 status = dcerpc_spoolss_GetPrinterDataEx_r(b, tctx, &r);
3456 if (!NT_STATUS_IS_OK(status)) {
3457 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
3458 torture_skip(tctx, "GetPrinterDataEx not supported by server\n");
3460 torture_assert_ntstatus_ok(tctx, status, "GetPrinterDataEx failed");
3463 if (W_ERROR_EQUAL(r.out.result, WERR_MORE_DATA)) {
3464 r.in.offered = needed;
3465 r.out.data = talloc_zero_array(tctx, uint8_t, r.in.offered);
3466 status = dcerpc_spoolss_GetPrinterDataEx_r(b, tctx, &r);
3467 torture_assert_ntstatus_ok(tctx, status, "GetPrinterDataEx failed");
3470 torture_assert_werr_ok(tctx, r.out.result,
3471 talloc_asprintf(tctx, "GetPrinterDataEx(%s - %s) failed", r.in.key_name, r.in.value_name));
3473 CHECK_NEEDED_SIZE_LEVEL(spoolss_PrinterData, &data, type, needed, 1);
3475 if (type_p) {
3476 *type_p = type;
3479 if (data_p) {
3480 *data_p = r.out.data;
3483 if (needed_p) {
3484 *needed_p = needed;
3487 return true;
3490 static bool test_get_environment(struct torture_context *tctx,
3491 struct dcerpc_binding_handle *b,
3492 struct policy_handle *handle,
3493 const char **architecture)
3495 DATA_BLOB blob;
3496 enum winreg_Type type;
3497 uint8_t *data;
3498 uint32_t needed;
3500 torture_assert(tctx,
3501 test_GetPrinterData(tctx, b, handle, "Architecture", &type, &data, &needed),
3502 "failed to get Architecture");
3504 torture_assert_int_equal(tctx, type, REG_SZ, "unexpected type");
3506 blob = data_blob_const(data, needed);
3507 *architecture = reg_val_data_string(tctx, REG_SZ, blob);
3509 return true;
3512 static bool test_GetPrinterData_list(struct torture_context *tctx,
3513 struct dcerpc_pipe *p,
3514 struct policy_handle *handle,
3515 const char **architecture)
3517 struct dcerpc_binding_handle *b = p->binding_handle;
3518 const char *list[] = {
3519 "W3SvcInstalled",
3520 "BeepEnabled",
3521 "EventLog",
3522 /* "NetPopup", not on w2k8 */
3523 /* "NetPopupToComputer", not on w2k8 */
3524 "MajorVersion",
3525 "MinorVersion",
3526 "DefaultSpoolDirectory",
3527 "Architecture",
3528 "DsPresent",
3529 "OSVersion",
3530 /* "OSVersionEx", not on s3 */
3531 "DNSMachineName"
3533 int i;
3535 for (i=0; i < ARRAY_SIZE(list); i++) {
3536 enum winreg_Type type, type_ex;
3537 uint8_t *data, *data_ex;
3538 uint32_t needed, needed_ex;
3540 torture_assert(tctx, test_GetPrinterData(tctx, b, handle, list[i], &type, &data, &needed),
3541 talloc_asprintf(tctx, "GetPrinterData failed on %s\n", list[i]));
3542 torture_assert(tctx, test_GetPrinterDataEx(tctx, p, handle, "random_string", list[i], &type_ex, &data_ex, &needed_ex),
3543 talloc_asprintf(tctx, "GetPrinterDataEx failed on %s\n", list[i]));
3544 torture_assert_int_equal(tctx, type, type_ex, "type mismatch");
3545 torture_assert_int_equal(tctx, needed, needed_ex, "needed mismatch");
3546 torture_assert_mem_equal(tctx, data, data_ex, needed, "data mismatch");
3548 if (strequal(list[i], "Architecture")) {
3549 if (architecture) {
3550 DATA_BLOB blob = data_blob_const(data, needed);
3551 *architecture = reg_val_data_string(tctx, REG_SZ, blob);
3556 return true;
3559 static bool test_EnumPrinterData(struct torture_context *tctx,
3560 struct dcerpc_pipe *p,
3561 struct policy_handle *handle,
3562 uint32_t enum_index,
3563 uint32_t value_offered,
3564 uint32_t data_offered,
3565 enum winreg_Type *type_p,
3566 uint32_t *value_needed_p,
3567 uint32_t *data_needed_p,
3568 const char **value_name_p,
3569 uint8_t **data_p,
3570 WERROR *result_p)
3572 struct spoolss_EnumPrinterData r;
3573 uint32_t data_needed;
3574 uint32_t value_needed;
3575 enum winreg_Type type;
3576 struct dcerpc_binding_handle *b = p->binding_handle;
3578 r.in.handle = handle;
3579 r.in.enum_index = enum_index;
3580 r.in.value_offered = value_offered;
3581 r.in.data_offered = data_offered;
3582 r.out.data_needed = &data_needed;
3583 r.out.value_needed = &value_needed;
3584 r.out.type = &type;
3585 r.out.data = talloc_zero_array(tctx, uint8_t, r.in.data_offered);
3586 r.out.value_name = talloc_zero_array(tctx, const char, r.in.value_offered);
3588 torture_comment(tctx, "Testing EnumPrinterData(%d)\n", enum_index);
3590 torture_assert_ntstatus_ok(tctx,
3591 dcerpc_spoolss_EnumPrinterData_r(b, tctx, &r),
3592 "EnumPrinterData failed");
3594 if (type_p) {
3595 *type_p = type;
3597 if (value_needed_p) {
3598 *value_needed_p = value_needed;
3600 if (data_needed_p) {
3601 *data_needed_p = data_needed;
3603 if (value_name_p) {
3604 *value_name_p = r.out.value_name;
3606 if (data_p) {
3607 *data_p = r.out.data;
3609 if (result_p) {
3610 *result_p = r.out.result;
3613 return true;
3617 static bool test_EnumPrinterData_all(struct torture_context *tctx,
3618 struct dcerpc_pipe *p,
3619 struct policy_handle *handle)
3621 uint32_t enum_index = 0;
3622 enum winreg_Type type;
3623 uint32_t value_needed;
3624 uint32_t data_needed;
3625 uint8_t *data;
3626 const char *value_name;
3627 WERROR result;
3629 torture_comment(tctx, "Testing EnumPrinterData\n");
3631 do {
3632 torture_assert(tctx,
3633 test_EnumPrinterData(tctx, p, handle, enum_index, 0, 0,
3634 &type, &value_needed, &data_needed,
3635 &value_name, &data, &result),
3636 "EnumPrinterData failed");
3638 if (W_ERROR_EQUAL(result, WERR_NO_MORE_ITEMS)) {
3639 break;
3642 torture_assert(tctx,
3643 test_EnumPrinterData(tctx, p, handle, enum_index, value_needed, data_needed,
3644 &type, &value_needed, &data_needed,
3645 &value_name, &data, &result),
3646 "EnumPrinterData failed");
3648 if (W_ERROR_EQUAL(result, WERR_NO_MORE_ITEMS)) {
3649 break;
3652 enum_index++;
3654 } while (W_ERROR_IS_OK(result));
3656 torture_comment(tctx, "EnumPrinterData test succeeded\n");
3658 return true;
3661 static bool test_EnumPrinterDataEx(struct torture_context *tctx,
3662 struct dcerpc_binding_handle *b,
3663 struct policy_handle *handle,
3664 const char *key_name,
3665 uint32_t *count_p,
3666 struct spoolss_PrinterEnumValues **info_p)
3668 struct spoolss_EnumPrinterDataEx r;
3669 struct spoolss_PrinterEnumValues *info;
3670 uint32_t needed;
3671 uint32_t count;
3673 r.in.handle = handle;
3674 r.in.key_name = key_name;
3675 r.in.offered = 0;
3676 r.out.needed = &needed;
3677 r.out.count = &count;
3678 r.out.info = &info;
3680 torture_comment(tctx, "Testing EnumPrinterDataEx(%s)\n", key_name);
3682 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_EnumPrinterDataEx_r(b, tctx, &r),
3683 "EnumPrinterDataEx failed");
3684 if (W_ERROR_EQUAL(r.out.result, WERR_MORE_DATA)) {
3685 r.in.offered = needed;
3686 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_EnumPrinterDataEx_r(b, tctx, &r),
3687 "EnumPrinterDataEx failed");
3690 torture_assert_werr_ok(tctx, r.out.result, "EnumPrinterDataEx failed");
3692 CHECK_NEEDED_SIZE_ENUM(spoolss_EnumPrinterDataEx, info, count, needed, 1);
3694 if (count_p) {
3695 *count_p = count;
3697 if (info_p) {
3698 *info_p = info;
3701 return true;
3704 static bool test_SetPrinterData(struct torture_context *tctx,
3705 struct dcerpc_binding_handle *b,
3706 struct policy_handle *handle,
3707 const char *value_name,
3708 enum winreg_Type type,
3709 uint8_t *data,
3710 uint32_t offered);
3711 static bool test_DeletePrinterData(struct torture_context *tctx,
3712 struct dcerpc_binding_handle *b,
3713 struct policy_handle *handle,
3714 const char *value_name);
3716 static bool test_EnumPrinterData_consistency(struct torture_context *tctx,
3717 struct dcerpc_pipe *p,
3718 struct policy_handle *handle)
3720 uint32_t count;
3721 struct spoolss_PrinterEnumValues *info;
3722 int i;
3723 uint32_t value_needed, data_needed;
3724 uint32_t value_offered, data_offered;
3725 WERROR result;
3726 struct dcerpc_binding_handle *b = p->binding_handle;
3728 enum winreg_Type type;
3729 DATA_BLOB blob;
3731 torture_comment(tctx, "Testing EnumPrinterData vs EnumPrinterDataEx consistency\n");
3733 torture_assert(tctx, push_reg_sz(tctx, &blob, "torture_data1"), "");
3734 type = REG_SZ;
3736 torture_assert(tctx,
3737 test_SetPrinterData(tctx, b, handle, "torture_value1", type, blob.data, blob.length),
3738 "SetPrinterData failed");
3740 blob = data_blob_string_const("torture_data2");
3742 torture_assert(tctx,
3743 test_SetPrinterData(tctx, b, handle, "torture_value2", REG_BINARY, blob.data, blob.length),
3744 "SetPrinterData failed");
3746 blob = data_blob_talloc(tctx, NULL, 4);
3747 SIVAL(blob.data, 0, 0x11223344);
3749 torture_assert(tctx,
3750 test_SetPrinterData(tctx, b, handle, "torture_value3", type, blob.data, blob.length),
3751 "SetPrinterData failed");
3753 torture_assert(tctx,
3754 test_EnumPrinterDataEx(tctx, b, handle, "PrinterDriverData", &count, &info),
3755 "failed to call EnumPrinterDataEx");
3757 /* get the max sizes for value and data */
3759 torture_assert(tctx,
3760 test_EnumPrinterData(tctx, p, handle, 0, 0, 0,
3761 NULL, &value_needed, &data_needed,
3762 NULL, NULL, &result),
3763 "EnumPrinterData failed");
3764 torture_assert_werr_ok(tctx, result, "unexpected result");
3766 /* check if the reply from the EnumPrinterData really matches max values */
3768 for (i=0; i < count; i++) {
3769 if (info[i].value_name_len > value_needed) {
3770 torture_fail(tctx,
3771 talloc_asprintf(tctx,
3772 "EnumPrinterDataEx gave a reply with value length %d which is larger then expected max value length %d from EnumPrinterData",
3773 info[i].value_name_len, value_needed));
3775 if (info[i].data_length > data_needed) {
3776 torture_fail(tctx,
3777 talloc_asprintf(tctx,
3778 "EnumPrinterDataEx gave a reply with data length %d which is larger then expected max data length %d from EnumPrinterData",
3779 info[i].data_length, data_needed));
3783 /* assuming that both EnumPrinterData and EnumPrinterDataEx do either
3784 * sort or not sort the replies by value name, we should be able to do
3785 * the following entry comparison */
3787 data_offered = data_needed;
3788 value_offered = value_needed;
3790 for (i=0; i < count; i++) {
3792 const char *value_name;
3793 uint8_t *data;
3795 torture_assert(tctx,
3796 test_EnumPrinterData(tctx, p, handle, i, value_offered, data_offered,
3797 &type, &value_needed, &data_needed,
3798 &value_name, &data, &result),
3799 "EnumPrinterData failed");
3801 if (i -1 == count) {
3802 torture_assert_werr_equal(tctx, result, WERR_NO_MORE_ITEMS,
3803 "unexpected result");
3804 break;
3805 } else {
3806 torture_assert_werr_ok(tctx, result, "unexpected result");
3809 torture_assert_int_equal(tctx, type, info[i].type, "type mismatch");
3810 torture_assert_int_equal(tctx, value_needed, info[i].value_name_len, "value name length mismatch");
3811 torture_assert_str_equal(tctx, value_name, info[i].value_name, "value name mismatch");
3812 torture_assert_int_equal(tctx, data_needed, info[i].data_length, "data length mismatch");
3813 torture_assert_mem_equal(tctx, data, info[i].data->data, info[i].data_length, "data mismatch");
3816 torture_assert(tctx,
3817 test_DeletePrinterData(tctx, b, handle, "torture_value1"),
3818 "DeletePrinterData failed");
3819 torture_assert(tctx,
3820 test_DeletePrinterData(tctx, b, handle, "torture_value2"),
3821 "DeletePrinterData failed");
3822 torture_assert(tctx,
3823 test_DeletePrinterData(tctx, b, handle, "torture_value3"),
3824 "DeletePrinterData failed");
3826 torture_comment(tctx, "EnumPrinterData vs EnumPrinterDataEx consistency test succeeded\n\n");
3828 return true;
3831 static bool test_DeletePrinterData(struct torture_context *tctx,
3832 struct dcerpc_binding_handle *b,
3833 struct policy_handle *handle,
3834 const char *value_name)
3836 NTSTATUS status;
3837 struct spoolss_DeletePrinterData r;
3839 r.in.handle = handle;
3840 r.in.value_name = value_name;
3842 torture_comment(tctx, "Testing DeletePrinterData(%s)\n",
3843 r.in.value_name);
3845 status = dcerpc_spoolss_DeletePrinterData_r(b, tctx, &r);
3847 torture_assert_ntstatus_ok(tctx, status, "DeletePrinterData failed");
3848 torture_assert_werr_ok(tctx, r.out.result, "DeletePrinterData failed");
3850 return true;
3853 static bool test_DeletePrinterDataEx(struct torture_context *tctx,
3854 struct dcerpc_binding_handle *b,
3855 struct policy_handle *handle,
3856 const char *key_name,
3857 const char *value_name)
3859 struct spoolss_DeletePrinterDataEx r;
3861 r.in.handle = handle;
3862 r.in.key_name = key_name;
3863 r.in.value_name = value_name;
3865 torture_comment(tctx, "Testing DeletePrinterDataEx(%s - %s)\n",
3866 r.in.key_name, r.in.value_name);
3868 torture_assert_ntstatus_ok(tctx,
3869 dcerpc_spoolss_DeletePrinterDataEx_r(b, tctx, &r),
3870 "DeletePrinterDataEx failed");
3871 torture_assert_werr_ok(tctx, r.out.result,
3872 "DeletePrinterDataEx failed");
3874 return true;
3877 static bool test_DeletePrinterKey(struct torture_context *tctx,
3878 struct dcerpc_binding_handle *b,
3879 struct policy_handle *handle,
3880 const char *key_name)
3882 struct spoolss_DeletePrinterKey r;
3884 r.in.handle = handle;
3885 r.in.key_name = key_name;
3887 torture_comment(tctx, "Testing DeletePrinterKey(%s)\n", r.in.key_name);
3889 if (strequal(key_name, "") && !torture_setting_bool(tctx, "dangerous", false)) {
3890 torture_skip(tctx, "not wiping out printer registry - enable dangerous tests to use\n");
3891 return true;
3894 torture_assert_ntstatus_ok(tctx,
3895 dcerpc_spoolss_DeletePrinterKey_r(b, tctx, &r),
3896 "DeletePrinterKey failed");
3897 torture_assert_werr_ok(tctx, r.out.result,
3898 "DeletePrinterKey failed");
3900 return true;
3903 static bool test_winreg_OpenHKLM(struct torture_context *tctx,
3904 struct dcerpc_binding_handle *b,
3905 struct policy_handle *handle)
3907 struct winreg_OpenHKLM r;
3909 r.in.system_name = NULL;
3910 r.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
3911 r.out.handle = handle;
3913 torture_comment(tctx, "Testing winreg_OpenHKLM\n");
3915 torture_assert_ntstatus_ok(tctx, dcerpc_winreg_OpenHKLM_r(b, tctx, &r), "OpenHKLM failed");
3916 torture_assert_werr_ok(tctx, r.out.result, "OpenHKLM failed");
3918 return true;
3921 static void init_winreg_String(struct winreg_String *name, const char *s)
3923 name->name = s;
3924 if (s) {
3925 name->name_len = 2 * (strlen_m(s) + 1);
3926 name->name_size = name->name_len;
3927 } else {
3928 name->name_len = 0;
3929 name->name_size = 0;
3933 static bool test_winreg_OpenKey_opts(struct torture_context *tctx,
3934 struct dcerpc_binding_handle *b,
3935 struct policy_handle *hive_handle,
3936 const char *keyname,
3937 uint32_t options,
3938 struct policy_handle *key_handle)
3940 struct winreg_OpenKey r;
3942 r.in.parent_handle = hive_handle;
3943 init_winreg_String(&r.in.keyname, keyname);
3944 r.in.options = options;
3945 r.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
3946 r.out.handle = key_handle;
3948 torture_comment(tctx, "Testing winreg_OpenKey(%s)\n", keyname);
3950 torture_assert_ntstatus_ok(tctx, dcerpc_winreg_OpenKey_r(b, tctx, &r), "OpenKey failed");
3951 torture_assert_werr_ok(tctx, r.out.result, "OpenKey failed");
3953 return true;
3956 static bool test_winreg_OpenKey(struct torture_context *tctx,
3957 struct dcerpc_binding_handle *b,
3958 struct policy_handle *hive_handle,
3959 const char *keyname,
3960 struct policy_handle *key_handle)
3962 return test_winreg_OpenKey_opts(tctx, b, hive_handle, keyname,
3963 REG_OPTION_NON_VOLATILE, key_handle);
3966 static bool test_winreg_CloseKey(struct torture_context *tctx,
3967 struct dcerpc_binding_handle *b,
3968 struct policy_handle *handle)
3970 struct winreg_CloseKey r;
3972 r.in.handle = handle;
3973 r.out.handle = handle;
3975 torture_comment(tctx, "Testing winreg_CloseKey\n");
3977 torture_assert_ntstatus_ok(tctx, dcerpc_winreg_CloseKey_r(b, tctx, &r), "CloseKey failed");
3978 torture_assert_werr_ok(tctx, r.out.result, "CloseKey failed");
3980 return true;
3983 bool test_winreg_QueryValue(struct torture_context *tctx,
3984 struct dcerpc_binding_handle *b,
3985 struct policy_handle *handle,
3986 const char *value_name,
3987 enum winreg_Type *type_p,
3988 uint32_t *data_size_p,
3989 uint32_t *data_length_p,
3990 uint8_t **data_p)
3992 struct winreg_QueryValue r;
3993 enum winreg_Type type = REG_NONE;
3994 uint32_t data_size = 0;
3995 uint32_t data_length = 0;
3996 struct winreg_String valuename;
3997 uint8_t *data = NULL;
3999 init_winreg_String(&valuename, value_name);
4001 data = talloc_zero_array(tctx, uint8_t, 0);
4003 r.in.handle = handle;
4004 r.in.value_name = &valuename;
4005 r.in.type = &type;
4006 r.in.data_size = &data_size;
4007 r.in.data_length = &data_length;
4008 r.in.data = data;
4009 r.out.type = &type;
4010 r.out.data = data;
4011 r.out.data_size = &data_size;
4012 r.out.data_length = &data_length;
4014 torture_comment(tctx, "Testing winreg_QueryValue(%s)\n", value_name);
4016 torture_assert_ntstatus_ok(tctx, dcerpc_winreg_QueryValue_r(b, tctx, &r), "QueryValue failed");
4017 if (W_ERROR_EQUAL(r.out.result, WERR_MORE_DATA)) {
4018 *r.in.data_size = *r.out.data_size;
4019 data = talloc_zero_array(tctx, uint8_t, *r.in.data_size);
4020 r.in.data = data;
4021 r.out.data = data;
4022 torture_assert_ntstatus_ok(tctx, dcerpc_winreg_QueryValue_r(b, tctx, &r), "QueryValue failed");
4024 torture_assert_werr_ok(tctx, r.out.result, "QueryValue failed");
4026 if (type_p) {
4027 *type_p = *r.out.type;
4029 if (data_size_p) {
4030 *data_size_p = *r.out.data_size;
4032 if (data_length_p) {
4033 *data_length_p = *r.out.data_length;
4035 if (data_p) {
4036 *data_p = r.out.data;
4039 return true;
4042 static bool test_winreg_query_printerdata(struct torture_context *tctx,
4043 struct dcerpc_binding_handle *b,
4044 struct policy_handle *handle,
4045 const char *printer_name,
4046 const char *key_name,
4047 const char *value_name,
4048 enum winreg_Type *w_type,
4049 uint32_t *w_size,
4050 uint32_t *w_length,
4051 uint8_t **w_data)
4053 const char *printer_key;
4054 struct policy_handle key_handle;
4056 printer_key = talloc_asprintf(tctx, "%s\\%s\\%s",
4057 TOP_LEVEL_PRINT_PRINTERS_KEY, printer_name, key_name);
4059 torture_assert(tctx,
4060 test_winreg_OpenKey(tctx, b, handle, printer_key, &key_handle), "");
4062 torture_assert(tctx,
4063 test_winreg_QueryValue(tctx, b, &key_handle, value_name, w_type, w_size, w_length, w_data), "");
4065 torture_assert(tctx,
4066 test_winreg_CloseKey(tctx, b, &key_handle), "");
4068 return true;
4071 static bool test_GetForm_winreg(struct torture_context *tctx,
4072 struct dcerpc_binding_handle *b,
4073 struct policy_handle *handle,
4074 const char *key_name,
4075 const char *form_name,
4076 enum winreg_Type *w_type,
4077 uint32_t *w_size,
4078 uint32_t *w_length,
4079 uint8_t **w_data)
4081 struct policy_handle key_handle;
4083 torture_assert(tctx,
4084 test_winreg_OpenKey(tctx, b, handle, key_name, &key_handle), "");
4086 torture_assert(tctx,
4087 test_winreg_QueryValue(tctx, b, &key_handle, form_name, w_type, w_size, w_length, w_data), "");
4089 torture_assert(tctx,
4090 test_winreg_CloseKey(tctx, b, &key_handle), "");
4092 return true;
4095 static bool test_winreg_symbolic_link(struct torture_context *tctx,
4096 struct dcerpc_binding_handle *b,
4097 struct policy_handle *handle,
4098 const char *symlink_keyname,
4099 const char *symlink_destination)
4101 /* check if the first key is a symlink to the second key */
4103 enum winreg_Type w_type;
4104 uint32_t w_size;
4105 uint32_t w_length;
4106 uint8_t *w_data;
4107 struct policy_handle key_handle;
4108 DATA_BLOB blob;
4109 const char *str;
4111 if (torture_setting_bool(tctx, "samba3", false)) {
4112 torture_skip(tctx, "skip winreg symlink test against samba");
4115 torture_assert(tctx,
4116 test_winreg_OpenKey_opts(tctx, b, handle, symlink_keyname, REG_OPTION_OPEN_LINK, &key_handle),
4117 "failed to open key link");
4119 torture_assert(tctx,
4120 test_winreg_QueryValue(tctx, b, &key_handle,
4121 "SymbolicLinkValue",
4122 &w_type, &w_size, &w_length, &w_data),
4123 "failed to query for 'SymbolicLinkValue' attribute");
4125 torture_assert_int_equal(tctx, w_type, REG_LINK, "unexpected type");
4127 blob = data_blob(w_data, w_size);
4128 str = reg_val_data_string(tctx, REG_SZ, blob);
4130 torture_assert_str_equal(tctx, str, symlink_destination, "unexpected symlink target string");
4132 torture_assert(tctx,
4133 test_winreg_CloseKey(tctx, b, &key_handle),
4134 "failed to close key link");
4136 return true;
4139 static const char *strip_unc(const char *unc)
4141 char *name;
4143 if (!unc) {
4144 return NULL;
4147 if (unc[0] == '\\' && unc[1] == '\\') {
4148 unc +=2;
4151 name = strchr(unc, '\\');
4152 if (name) {
4153 return name+1;
4156 return unc;
4159 static bool test_GetPrinterInfo_winreg(struct torture_context *tctx,
4160 struct dcerpc_binding_handle *b,
4161 struct policy_handle *handle,
4162 const char *printer_name,
4163 struct dcerpc_binding_handle *winreg_handle,
4164 struct policy_handle *hive_handle)
4166 union spoolss_PrinterInfo info;
4167 const char *keys[] = {
4168 TOP_LEVEL_CONTROL_PRINTERS_KEY,
4169 TOP_LEVEL_PRINT_PRINTERS_KEY
4171 int i;
4172 const char *printername, *sharename;
4174 torture_comment(tctx, "Testing Printer Info and winreg consistency\n");
4176 torture_assert(tctx,
4177 test_GetPrinter_level(tctx, b, handle, 2, &info),
4178 "failed to get printer info level 2");
4180 printername = strip_unc(info.info2.printername);
4181 sharename = strip_unc(info.info2.sharename);
4183 #define test_sz(wname, iname) \
4184 do {\
4185 DATA_BLOB blob;\
4186 const char *str;\
4187 enum winreg_Type w_type;\
4188 uint32_t w_size;\
4189 uint32_t w_length;\
4190 uint8_t *w_data;\
4191 torture_assert(tctx,\
4192 test_winreg_QueryValue(tctx, winreg_handle, &key_handle, wname,\
4193 &w_type, &w_size, &w_length, &w_data),\
4194 "failed to query winreg");\
4195 torture_assert_int_equal(tctx, w_type, REG_SZ, "unexpected type");\
4196 blob = data_blob(w_data, w_size);\
4197 str = reg_val_data_string(tctx, REG_SZ, blob);\
4198 if (w_size == 2 && iname == NULL) {\
4199 /*torture_comment(tctx, "%s: \"\", %s: (null)\n", #wname, #iname);\ */\
4200 } else {\
4201 torture_assert_str_equal(tctx, str, iname,\
4202 talloc_asprintf(tctx, "%s - %s mismatch", #wname, #iname));\
4204 } while(0);
4206 #define test_dword(wname, iname) \
4207 do {\
4208 uint32_t value;\
4209 enum winreg_Type w_type;\
4210 uint32_t w_size;\
4211 uint32_t w_length;\
4212 uint8_t *w_data;\
4213 torture_assert(tctx,\
4214 test_winreg_QueryValue(tctx, winreg_handle, &key_handle, wname,\
4215 &w_type, &w_size, &w_length, &w_data),\
4216 "failed to query winreg");\
4217 torture_assert_int_equal(tctx, w_type, REG_DWORD, "unexpected type");\
4218 torture_assert_int_equal(tctx, w_size, 4, "unexpected size");\
4219 torture_assert_int_equal(tctx, w_length, 4, "unexpected length");\
4220 value = IVAL(w_data, 0);\
4221 torture_assert_int_equal(tctx, value, iname,\
4222 talloc_asprintf(tctx, "%s - %s mismatch", #wname, #iname));\
4223 } while(0);
4225 #define test_dm(wname, iname) \
4226 do {\
4227 DATA_BLOB blob;\
4228 struct spoolss_DeviceMode dm;\
4229 enum ndr_err_code ndr_err;\
4230 enum winreg_Type w_type;\
4231 uint32_t w_size;\
4232 uint32_t w_length;\
4233 uint8_t *w_data;\
4234 torture_assert(tctx,\
4235 test_winreg_QueryValue(tctx, winreg_handle, &key_handle, wname,\
4236 &w_type, &w_size, &w_length, &w_data),\
4237 "failed to query winreg");\
4238 torture_assert_int_equal(tctx, w_type, REG_BINARY, "unexpected type");\
4239 blob = data_blob(w_data, w_size);\
4240 ndr_err = ndr_pull_struct_blob(&blob, tctx, &dm,\
4241 (ndr_pull_flags_fn_t)ndr_pull_spoolss_DeviceMode);\
4242 torture_assert_ndr_success(tctx, ndr_err, "failed to unmarshall dm");\
4243 torture_assert(tctx, test_devicemode_equal(tctx, &dm, iname),\
4244 "dm unequal");\
4245 } while(0);
4247 #define test_sd(wname, iname) \
4248 do {\
4249 DATA_BLOB blob;\
4250 struct security_descriptor sd;\
4251 enum ndr_err_code ndr_err;\
4252 enum winreg_Type w_type;\
4253 uint32_t w_size;\
4254 uint32_t w_length;\
4255 uint8_t *w_data;\
4256 torture_assert(tctx,\
4257 test_winreg_QueryValue(tctx, winreg_handle, &key_handle, wname,\
4258 &w_type, &w_size, &w_length, &w_data),\
4259 "failed to query winreg");\
4260 torture_assert_int_equal(tctx, w_type, REG_BINARY, "unexpected type");\
4261 blob = data_blob(w_data, w_size);\
4262 ndr_err = ndr_pull_struct_blob(&blob, tctx, &sd,\
4263 (ndr_pull_flags_fn_t)ndr_pull_security_descriptor);\
4264 torture_assert_ndr_success(tctx, ndr_err, "failed to unmarshall sd");\
4265 torture_assert(tctx, test_security_descriptor_equal(tctx, &sd, iname),\
4266 "sd unequal");\
4267 } while(0);
4269 #define test_multi_sz(wname, iname) \
4270 do {\
4271 DATA_BLOB blob;\
4272 const char **array;\
4273 enum winreg_Type w_type;\
4274 uint32_t w_size;\
4275 uint32_t w_length;\
4276 uint8_t *w_data;\
4277 int i;\
4278 torture_assert(tctx,\
4279 test_winreg_QueryValue(tctx, winreg_handle, &key_handle, wname,\
4280 &w_type, &w_size, &w_length, &w_data),\
4281 "failed to query winreg");\
4282 torture_assert_int_equal(tctx, w_type, REG_MULTI_SZ, "unexpected type");\
4283 blob = data_blob(w_data, w_size);\
4284 torture_assert(tctx, \
4285 pull_reg_multi_sz(tctx, &blob, &array),\
4286 "failed to pull multi sz");\
4287 for (i=0; array[i] != NULL; i++) {\
4288 torture_assert_str_equal(tctx, array[i], iname[i],\
4289 talloc_asprintf(tctx, "%s - %s mismatch", #wname, iname[i]));\
4291 } while(0);
4294 if (!test_winreg_symbolic_link(tctx, winreg_handle, hive_handle,
4295 TOP_LEVEL_CONTROL_PRINTERS_KEY,
4296 "\\Registry\\Machine\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Print\\Printers"))
4298 torture_warning(tctx, "failed to check for winreg symlink");
4302 for (i=0; i < ARRAY_SIZE(keys); i++) {
4304 const char *printer_key;
4305 struct policy_handle key_handle;
4307 printer_key = talloc_asprintf(tctx, "%s\\%s",
4308 keys[i], printer_name);
4310 torture_assert(tctx,
4311 test_winreg_OpenKey(tctx, winreg_handle, hive_handle, printer_key, &key_handle), "");
4313 test_sz("Name", printername);
4314 test_sz("Share Name", sharename);
4315 test_sz("Port", info.info2.portname);
4316 test_sz("Printer Driver", info.info2.drivername);
4317 test_sz("Description", info.info2.comment);
4318 test_sz("Location", info.info2.location);
4319 test_sz("Separator File", info.info2.sepfile);
4320 test_sz("Print Processor", info.info2.printprocessor);
4321 test_sz("Datatype", info.info2.datatype);
4322 test_sz("Parameters", info.info2.parameters);
4323 /* winreg: 0, spoolss not */
4324 /* test_dword("Attributes", info.info2.attributes); */
4325 test_dword("Priority", info.info2.priority);
4326 test_dword("Default Priority", info.info2.defaultpriority);
4327 /* winreg: 60, spoolss: 0 */
4328 /* test_dword("StartTime", info.info2.starttime); */
4329 /* test_dword("UntilTime", info.info2.untiltime); */
4330 /* winreg != spoolss */
4331 /* test_dword("Status", info.info2.status); */
4332 test_dm("Default DevMode", info.info2.devmode);
4333 test_sd("Security", info.info2.secdesc);
4335 torture_assert(tctx,
4336 test_winreg_CloseKey(tctx, winreg_handle, &key_handle), "");
4339 #undef test_dm
4340 #undef test_sd
4342 torture_comment(tctx, "Printer Info and winreg consistency test succeeded\n\n");
4344 return true;
4347 static bool test_GetPrinterDriver2_level(struct torture_context *tctx,
4348 struct dcerpc_binding_handle *b,
4349 struct policy_handle *handle,
4350 const char *driver_name,
4351 const char *architecture,
4352 uint32_t level,
4353 uint32_t client_major_version,
4354 uint32_t client_minor_version,
4355 union spoolss_DriverInfo *info_p,
4356 WERROR *result);
4358 static const char *strip_path(const char *path)
4360 char *p;
4362 if (path == NULL) {
4363 return NULL;
4366 p = strrchr(path, '\\');
4367 if (p) {
4368 return p+1;
4371 return path;
4374 static const char **strip_paths(const char **path_array)
4376 int i;
4378 if (path_array == NULL) {
4379 return NULL;
4382 for (i=0; path_array[i] != NULL; i++) {
4383 path_array[i] = strip_path(path_array[i]);
4386 return path_array;
4389 static const char *driver_winreg_date(TALLOC_CTX *mem_ctx, NTTIME nt)
4391 time_t t;
4392 struct tm *tm;
4393 t = nt_time_to_unix(nt);
4394 tm = localtime(&t);
4396 return talloc_asprintf(mem_ctx, "%02d/%02d/%04d",
4397 tm->tm_mon + 1, tm->tm_mday, tm->tm_year + 1900);
4400 static const char *driver_winreg_version(TALLOC_CTX *mem_ctx, uint64_t v)
4402 return talloc_asprintf(mem_ctx, "%u.%u.%u.%u",
4403 (unsigned)((v >> 48) & 0xFFFF),
4404 (unsigned)((v >> 32) & 0xFFFF),
4405 (unsigned)((v >> 16) & 0xFFFF),
4406 (unsigned)(v & 0xFFFF));
4409 static bool test_GetDriverInfo_winreg(struct torture_context *tctx,
4410 struct dcerpc_binding_handle *b,
4411 struct policy_handle *handle,
4412 const char *printer_name,
4413 const char *driver_name,
4414 const char *environment,
4415 struct dcerpc_binding_handle *winreg_handle,
4416 struct policy_handle *hive_handle)
4418 WERROR result;
4419 union spoolss_DriverInfo info;
4420 const char *driver_key;
4421 struct policy_handle key_handle;
4423 const char *driver_path;
4424 const char *data_file;
4425 const char *config_file;
4426 const char *help_file;
4427 const char **dependent_files;
4429 const char *driver_date;
4430 const char *inbox_driver_date;
4432 const char *driver_version;
4433 const char *inbox_driver_version;
4435 torture_comment(tctx, "Testing Driver Info and winreg consistency\n");
4437 driver_key = talloc_asprintf(tctx, "%s\\%s\\Drivers\\Version-%d\\%s",
4438 TOP_LEVEL_CONTROL_ENVIRONMENTS_KEY,
4439 environment,
4441 driver_name);
4443 torture_assert(tctx,
4444 test_winreg_OpenKey(tctx, winreg_handle, hive_handle, driver_key, &key_handle),
4445 "failed to open driver key");
4447 if (torture_setting_bool(tctx, "samba3", false)) {
4448 goto try_level3;
4451 torture_assert(tctx,
4452 test_GetPrinterDriver2_level(tctx, b, handle, driver_name, environment, 8, 3, 0, &info, &result),
4453 "failed to get driver info level 8");
4455 if (W_ERROR_EQUAL(result, WERR_INVALID_LEVEL)) {
4456 goto try_level6;
4459 driver_path = strip_path(info.info8.driver_path);
4460 data_file = strip_path(info.info8.data_file);
4461 config_file = strip_path(info.info8.config_file);
4462 help_file = strip_path(info.info8.help_file);
4463 dependent_files = strip_paths(info.info8.dependent_files);
4465 driver_date = driver_winreg_date(tctx, info.info8.driver_date);
4466 inbox_driver_date = driver_winreg_date(tctx, info.info8.min_inbox_driver_ver_date);
4468 driver_version = driver_winreg_version(tctx, info.info8.driver_version);
4469 inbox_driver_version = driver_winreg_version(tctx, info.info8.min_inbox_driver_ver_version);
4471 test_sz("Configuration File", config_file);
4472 test_sz("Data File", data_file);
4473 test_sz("Datatype", info.info8.default_datatype);
4474 test_sz("Driver", driver_path);
4475 test_sz("DriverDate", driver_date);
4476 test_sz("DriverVersion", driver_version);
4477 test_sz("HardwareID", info.info8.hardware_id);
4478 test_sz("Help File", help_file);
4479 test_sz("InfPath", info.info8.inf_path);
4480 test_sz("Manufacturer", info.info8.manufacturer_name);
4481 test_sz("MinInboxDriverVerDate", inbox_driver_date);
4482 test_sz("MinInboxDriverVerVersion", inbox_driver_version);
4483 test_sz("Monitor", info.info8.monitor_name);
4484 test_sz("OEM URL", info.info8.manufacturer_url);
4485 test_sz("Print Processor", info.info8.print_processor);
4486 test_sz("Provider", info.info8.provider);
4487 test_sz("VendorSetup", info.info8.vendor_setup);
4488 test_multi_sz("ColorProfiles", info.info8.color_profiles);
4489 test_multi_sz("Dependent Files", dependent_files);
4490 test_multi_sz("CoreDependencies", info.info8.core_driver_dependencies);
4491 test_multi_sz("Previous Names", info.info8.previous_names);
4492 /* test_dword("Attributes", ?); */
4493 test_dword("PrinterDriverAttributes", info.info8.printer_driver_attributes);
4494 test_dword("Version", info.info8.version);
4495 /* test_dword("TempDir", ?); */
4497 try_level6:
4499 torture_assert(tctx,
4500 test_GetPrinterDriver2_level(tctx, b, handle, driver_name, environment, 6, 3, 0, &info, &result),
4501 "failed to get driver info level 6");
4503 driver_path = strip_path(info.info6.driver_path);
4504 data_file = strip_path(info.info6.data_file);
4505 config_file = strip_path(info.info6.config_file);
4506 help_file = strip_path(info.info6.help_file);
4507 dependent_files = strip_paths(info.info6.dependent_files);
4509 driver_date = driver_winreg_date(tctx, info.info6.driver_date);
4511 driver_version = driver_winreg_version(tctx, info.info6.driver_version);
4513 test_sz("Configuration File", config_file);
4514 test_sz("Data File", data_file);
4515 test_sz("Datatype", info.info6.default_datatype);
4516 test_sz("Driver", driver_path);
4517 test_sz("DriverDate", driver_date);
4518 test_sz("DriverVersion", driver_version);
4519 test_sz("HardwareID", info.info6.hardware_id);
4520 test_sz("Help File", help_file);
4521 test_sz("Manufacturer", info.info6.manufacturer_name);
4522 test_sz("Monitor", info.info6.monitor_name);
4523 test_sz("OEM URL", info.info6.manufacturer_url);
4524 test_sz("Provider", info.info6.provider);
4525 test_multi_sz("Dependent Files", dependent_files);
4526 test_multi_sz("Previous Names", info.info6.previous_names);
4527 /* test_dword("Attributes", ?); */
4528 test_dword("Version", info.info6.version);
4529 /* test_dword("TempDir", ?); */
4531 try_level3:
4533 torture_assert(tctx,
4534 test_GetPrinterDriver2_level(tctx, b, handle, driver_name, environment, 3, 3, 0, &info, &result),
4535 "failed to get driver info level 3");
4537 driver_path = strip_path(info.info3.driver_path);
4538 data_file = strip_path(info.info3.data_file);
4539 config_file = strip_path(info.info3.config_file);
4540 help_file = strip_path(info.info3.help_file);
4541 dependent_files = strip_paths(info.info3.dependent_files);
4543 test_sz("Configuration File", config_file);
4544 test_sz("Data File", data_file);
4545 test_sz("Datatype", info.info3.default_datatype);
4546 test_sz("Driver", driver_path);
4547 test_sz("Help File", help_file);
4548 test_sz("Monitor", info.info3.monitor_name);
4549 test_multi_sz("Dependent Files", dependent_files);
4550 /* test_dword("Attributes", ?); */
4551 test_dword("Version", info.info3.version);
4552 /* test_dword("TempDir", ?); */
4555 torture_assert(tctx,
4556 test_winreg_CloseKey(tctx, winreg_handle, &key_handle), "");
4558 torture_comment(tctx, "Driver Info and winreg consistency test succeeded\n\n");
4560 return true;
4563 #undef test_sz
4564 #undef test_dword
4566 static bool test_SetPrinterData(struct torture_context *tctx,
4567 struct dcerpc_binding_handle *b,
4568 struct policy_handle *handle,
4569 const char *value_name,
4570 enum winreg_Type type,
4571 uint8_t *data,
4572 uint32_t offered)
4574 struct spoolss_SetPrinterData r;
4576 r.in.handle = handle;
4577 r.in.value_name = value_name;
4578 r.in.type = type;
4579 r.in.data = data;
4580 r.in.offered = offered;
4582 torture_comment(tctx, "Testing SetPrinterData(%s)\n",
4583 r.in.value_name);
4585 torture_assert_ntstatus_ok(tctx,
4586 dcerpc_spoolss_SetPrinterData_r(b, tctx, &r),
4587 "SetPrinterData failed");
4588 torture_assert_werr_ok(tctx, r.out.result,
4589 "SetPrinterData failed");
4591 return true;
4594 static bool test_SetPrinterData_matrix(struct torture_context *tctx,
4595 struct dcerpc_binding_handle *b,
4596 struct policy_handle *handle,
4597 const char *printer_name,
4598 struct dcerpc_binding_handle *winreg_handle,
4599 struct policy_handle *hive_handle)
4601 const char *values[] = {
4602 "spootyfoot",
4603 "spooty\\foot",
4604 #if 0
4605 /* FIXME: not working with s3 atm. */
4606 "spooty,foot",
4607 "spooty,fo,ot",
4608 #endif
4609 "spooty foot",
4610 #if 0
4611 /* FIXME: not working with s3 atm. */
4612 "spooty\\fo,ot",
4613 "spooty,fo\\ot"
4614 #endif
4616 int i;
4618 for (i=0; i < ARRAY_SIZE(values); i++) {
4620 enum winreg_Type type;
4621 DATA_BLOB blob;
4622 uint8_t *data;
4623 uint32_t needed;
4625 torture_assert(tctx, push_reg_sz(tctx, &blob, "dog"), "");
4626 type = REG_SZ;
4628 torture_assert(tctx,
4629 test_SetPrinterData(tctx, b, handle, values[i], REG_SZ, blob.data, blob.length),
4630 "SetPrinterData failed");
4632 torture_assert(tctx,
4633 test_GetPrinterData(tctx, b, handle, values[i], &type, &data, &needed),
4634 "GetPrinterData failed");
4636 torture_assert_int_equal(tctx, type, REG_SZ, "type mismatch");
4637 torture_assert_int_equal(tctx, needed, blob.length, "size mismatch");
4638 torture_assert_mem_equal(tctx, data, blob.data, blob.length, "buffer mismatch");
4640 if (winreg_handle && hive_handle) {
4642 enum winreg_Type w_type;
4643 uint32_t w_size;
4644 uint32_t w_length;
4645 uint8_t *w_data;
4647 torture_assert(tctx,
4648 test_winreg_query_printerdata(tctx, winreg_handle, hive_handle,
4649 printer_name, "PrinterDriverData", values[i],
4650 &w_type, &w_size, &w_length, &w_data), "");
4652 torture_assert_int_equal(tctx, w_type, REG_SZ, "winreg type mismatch");
4653 torture_assert_int_equal(tctx, w_size, blob.length, "winreg size mismatch");
4654 torture_assert_int_equal(tctx, w_length, blob.length, "winreg length mismatch");
4655 torture_assert_mem_equal(tctx, w_data, blob.data, blob.length, "winreg buffer mismatch");
4658 torture_assert(tctx,
4659 test_DeletePrinterData(tctx, b, handle, values[i]),
4660 "DeletePrinterData failed");
4663 return true;
4667 static bool test_EnumPrinterKey(struct torture_context *tctx,
4668 struct dcerpc_binding_handle *b,
4669 struct policy_handle *handle,
4670 const char *key_name,
4671 const char ***array);
4673 static bool test_SetPrinterDataEx(struct torture_context *tctx,
4674 struct dcerpc_binding_handle *b,
4675 struct policy_handle *handle,
4676 const char *key_name,
4677 const char *value_name,
4678 enum winreg_Type type,
4679 uint8_t *data,
4680 uint32_t offered)
4682 NTSTATUS status;
4683 struct spoolss_SetPrinterDataEx r;
4685 r.in.handle = handle;
4686 r.in.key_name = key_name;
4687 r.in.value_name = value_name;
4688 r.in.type = type;
4689 r.in.data = data;
4690 r.in.offered = offered;
4692 torture_comment(tctx, "Testing SetPrinterDataEx(%s - %s) type: %s, offered: 0x%08x\n",
4693 r.in.key_name, r.in.value_name, str_regtype(r.in.type), r.in.offered);
4695 status = dcerpc_spoolss_SetPrinterDataEx_r(b, tctx, &r);
4697 torture_assert_ntstatus_ok(tctx, status, "SetPrinterDataEx failed");
4698 torture_assert_werr_ok(tctx, r.out.result, "SetPrinterDataEx failed");
4700 return true;
4703 static bool test_SetPrinterDataEx_matrix(struct torture_context *tctx,
4704 struct dcerpc_pipe *p,
4705 struct policy_handle *handle,
4706 const char *printername,
4707 struct dcerpc_binding_handle *winreg_handle,
4708 struct policy_handle *hive_handle)
4710 struct dcerpc_binding_handle *b = p->binding_handle;
4711 const char *value_name = "dog";
4712 const char *keys[] = {
4713 "torturedataex",
4714 "torture data ex",
4715 #if 0
4716 /* FIXME: not working with s3 atm. */
4717 "torturedataex_with_subkey\\subkey",
4718 "torturedataex_with_subkey\\subkey:0",
4719 "torturedataex_with_subkey\\subkey:1",
4720 "torturedataex_with_subkey\\subkey\\subsubkey",
4721 "torturedataex_with_subkey\\subkey\\subsubkey:0",
4722 "torturedataex_with_subkey\\subkey\\subsubkey:1",
4723 #endif
4724 "torture,data",
4725 #if 0
4726 /* FIXME: not working with s3 atm. */
4728 "torture,data,ex",
4729 "torture,data\\ex",
4730 "torture\\data,ex"
4731 #endif
4733 enum winreg_Type types[] = {
4734 REG_SZ,
4735 REG_MULTI_SZ,
4736 REG_DWORD,
4737 REG_BINARY
4739 const char *str = "abcdefghijklmnopqrstuvwxzy";
4740 int i, t, s;
4743 for (i=0; i < ARRAY_SIZE(keys); i++) {
4744 for (t=0; t < ARRAY_SIZE(types); t++) {
4745 for (s=0; s < strlen(str); s++) {
4747 char *c;
4748 const char *key;
4749 enum winreg_Type type;
4750 const char *string = talloc_strndup(tctx, str, s);
4751 const char *array[2];
4752 DATA_BLOB blob = data_blob_string_const(string);
4753 const char **subkeys;
4754 DATA_BLOB data;
4755 uint8_t *data_out;
4756 uint32_t needed, offered = 0;
4757 uint32_t ecount;
4758 struct spoolss_PrinterEnumValues *einfo;
4760 array[0] = talloc_strdup(tctx, string);
4761 array[1] = NULL;
4763 if (types[t] == REG_DWORD) {
4764 s = 0xffff;
4767 if (torture_setting_bool(tctx, "samba3", false)) {
4768 if ((types[t] == REG_MULTI_SZ) && s == 0) {
4769 torture_warning(tctx, "samba3 does not handle 4 byte emtpy REG_MULTI_SZ buffers");
4770 continue;
4774 switch (types[t]) {
4775 case REG_BINARY:
4776 data = blob;
4777 offered = blob.length;
4778 break;
4779 case REG_DWORD:
4780 data = data_blob_talloc(tctx, NULL, 4);
4781 SIVAL(data.data, 0, 0x12345678);
4782 offered = 4;
4783 break;
4784 case REG_SZ:
4785 torture_assert(tctx, push_reg_sz(tctx, &data, string), "");
4786 type = REG_SZ;
4787 offered = data.length;
4788 /*strlen_m_term(data.string)*2;*/
4789 break;
4790 case REG_MULTI_SZ:
4791 torture_assert(tctx, push_reg_multi_sz(tctx, &data, array), "");
4792 type = REG_MULTI_SZ;
4793 offered = data.length;
4794 break;
4795 default:
4796 torture_fail(tctx, talloc_asprintf(tctx, "type %d untested\n", types[t]));
4799 torture_assert(tctx,
4800 test_SetPrinterDataEx(tctx, b, handle, keys[i], value_name, types[t], data.data, offered),
4801 "failed to call SetPrinterDataEx");
4803 torture_assert(tctx,
4804 test_GetPrinterDataEx(tctx, p, handle, keys[i], value_name, &type, &data_out, &needed),
4805 "failed to call GetPrinterDataEx");
4807 torture_assert(tctx,
4808 test_EnumPrinterDataEx(tctx, b, handle, keys[i], &ecount, &einfo),
4809 "failed to call EnumPrinterDataEx");
4811 torture_assert_int_equal(tctx, types[t], type, "type mismatch");
4812 torture_assert_int_equal(tctx, needed, offered, "size mismatch");
4813 torture_assert_mem_equal(tctx, data_out, data.data, offered, "buffer mismatch");
4815 torture_assert_int_equal(tctx, ecount, 1, "unexpected enum count");
4816 torture_assert_str_equal(tctx, einfo[0].value_name, value_name, "value_name mismatch");
4817 torture_assert_int_equal(tctx, einfo[0].value_name_len, strlen_m_term(value_name)*2, "unexpected value_name_len");
4818 torture_assert_int_equal(tctx, einfo[0].type, types[t], "type mismatch");
4819 torture_assert_int_equal(tctx, einfo[0].data_length, offered, "size mismatch");
4820 if (einfo[0].data_length > 0) {
4821 torture_assert_mem_equal(tctx, einfo[0].data->data, data.data, offered, "buffer mismatch");
4824 if (winreg_handle && hive_handle) {
4825 enum winreg_Type w_type;
4826 uint32_t w_size;
4827 uint32_t w_length;
4828 uint8_t *w_data;
4830 torture_assert(tctx,
4831 test_winreg_query_printerdata(tctx, winreg_handle, hive_handle,
4832 printername, keys[i], value_name,
4833 &w_type, &w_size, &w_length, &w_data), "");
4835 torture_assert_int_equal(tctx, w_type, types[t], "winreg type mismatch");
4836 torture_assert_int_equal(tctx, w_size, offered, "winreg size mismatch");
4837 torture_assert_int_equal(tctx, w_length, offered, "winreg length mismatch");
4838 torture_assert_mem_equal(tctx, w_data, data.data, offered, "winreg buffer mismatch");
4841 key = talloc_strdup(tctx, keys[i]);
4843 if (!test_DeletePrinterDataEx(tctx, b, handle, keys[i], value_name)) {
4844 return false;
4847 c = strchr(key, '\\');
4848 if (c) {
4849 int k;
4851 /* we have subkeys */
4853 *c = 0;
4855 if (!test_EnumPrinterKey(tctx, b, handle, key, &subkeys)) {
4856 return false;
4859 for (k=0; subkeys && subkeys[k]; k++) {
4861 const char *current_key = talloc_asprintf(tctx, "%s\\%s", key, subkeys[k]);
4863 if (!test_DeletePrinterKey(tctx, b, handle, current_key)) {
4864 return false;
4868 if (!test_DeletePrinterKey(tctx, b, handle, key)) {
4869 return false;
4872 } else {
4873 if (!test_DeletePrinterKey(tctx, b, handle, key)) {
4874 return false;
4881 return true;
4884 static bool test_PrinterData_winreg(struct torture_context *tctx,
4885 struct dcerpc_pipe *p,
4886 struct policy_handle *handle,
4887 const char *printer_name)
4889 struct dcerpc_binding_handle *b = p->binding_handle;
4890 struct dcerpc_pipe *p2;
4891 bool ret = true;
4892 struct policy_handle hive_handle;
4893 struct dcerpc_binding_handle *b2;
4895 torture_assert_ntstatus_ok(tctx,
4896 torture_rpc_connection(tctx, &p2, &ndr_table_winreg),
4897 "could not open winreg pipe");
4898 b2 = p2->binding_handle;
4900 torture_assert(tctx, test_winreg_OpenHKLM(tctx, b2, &hive_handle), "");
4902 ret &= test_SetPrinterData_matrix(tctx, b, handle, printer_name, b2, &hive_handle);
4903 ret &= test_SetPrinterDataEx_matrix(tctx, p, handle, printer_name, b2, &hive_handle);
4905 test_winreg_CloseKey(tctx, b2, &hive_handle);
4907 talloc_free(p2);
4909 return ret;
4912 static bool test_Forms_winreg(struct torture_context *tctx,
4913 struct dcerpc_binding_handle *b,
4914 struct policy_handle *handle,
4915 bool print_server,
4916 const char *printer_name)
4918 struct dcerpc_pipe *p2;
4919 bool ret = true;
4920 struct policy_handle hive_handle;
4921 struct dcerpc_binding_handle *b2;
4923 torture_assert_ntstatus_ok(tctx,
4924 torture_rpc_connection(tctx, &p2, &ndr_table_winreg),
4925 "could not open winreg pipe");
4926 b2 = p2->binding_handle;
4928 torture_assert(tctx, test_winreg_OpenHKLM(tctx, b2, &hive_handle), "");
4930 ret = test_Forms(tctx, b, handle, print_server, printer_name, b2, &hive_handle);
4932 test_winreg_CloseKey(tctx, b2, &hive_handle);
4934 talloc_free(p2);
4936 return ret;
4939 static bool test_PrinterInfo_winreg(struct torture_context *tctx,
4940 struct dcerpc_pipe *p,
4941 struct policy_handle *handle,
4942 const char *printer_name)
4944 struct dcerpc_binding_handle *b = p->binding_handle;
4945 struct dcerpc_pipe *p2;
4946 bool ret = true;
4947 struct policy_handle hive_handle;
4948 struct dcerpc_binding_handle *b2;
4950 torture_assert_ntstatus_ok(tctx,
4951 torture_rpc_connection(tctx, &p2, &ndr_table_winreg),
4952 "could not open winreg pipe");
4953 b2 = p2->binding_handle;
4955 torture_assert(tctx, test_winreg_OpenHKLM(tctx, b2, &hive_handle), "");
4957 ret = test_GetPrinterInfo_winreg(tctx, b, handle, printer_name, b2, &hive_handle);
4959 test_winreg_CloseKey(tctx, b2, &hive_handle);
4961 talloc_free(p2);
4963 return ret;
4966 static bool test_DriverInfo_winreg(struct torture_context *tctx,
4967 struct dcerpc_pipe *p,
4968 struct policy_handle *handle,
4969 const char *printer_name,
4970 const char *driver_name,
4971 const char *environment)
4973 struct dcerpc_binding_handle *b = p->binding_handle;
4974 struct dcerpc_pipe *p2;
4975 bool ret = true;
4976 struct policy_handle hive_handle;
4977 struct dcerpc_binding_handle *b2;
4979 torture_assert_ntstatus_ok(tctx,
4980 torture_rpc_connection(tctx, &p2, &ndr_table_winreg),
4981 "could not open winreg pipe");
4982 b2 = p2->binding_handle;
4984 torture_assert(tctx, test_winreg_OpenHKLM(tctx, b2, &hive_handle), "");
4986 ret = test_GetDriverInfo_winreg(tctx, b, handle, printer_name, driver_name, environment, b2, &hive_handle);
4988 test_winreg_CloseKey(tctx, b2, &hive_handle);
4990 talloc_free(p2);
4992 return ret;
4995 static bool test_PrinterData_DsSpooler(struct torture_context *tctx,
4996 struct dcerpc_pipe *p,
4997 struct policy_handle *handle,
4998 const char *printer_name)
5000 struct spoolss_SetPrinterInfoCtr info_ctr;
5001 struct spoolss_DevmodeContainer devmode_ctr;
5002 struct sec_desc_buf secdesc_ctr;
5003 union spoolss_SetPrinterInfo sinfo;
5004 union spoolss_PrinterInfo info;
5005 struct dcerpc_binding_handle *b = p->binding_handle;
5006 const char *pname;
5008 ZERO_STRUCT(info_ctr);
5009 ZERO_STRUCT(devmode_ctr);
5010 ZERO_STRUCT(secdesc_ctr);
5012 torture_comment(tctx, "Testing DsSpooler <-> SetPrinter relations\n");
5014 torture_assert(tctx,
5015 test_GetPrinter_level(tctx, b, handle, 2, &info),
5016 "failed to query Printer level 2");
5018 torture_assert(tctx,
5019 PrinterInfo_to_SetPrinterInfo(tctx, &info, 2, &sinfo),
5020 "failed to convert");
5022 info_ctr.level = 2;
5023 info_ctr.info = sinfo;
5025 #define TEST_SZ(wname, iname) \
5026 do {\
5027 enum winreg_Type type;\
5028 uint8_t *data;\
5029 uint32_t needed;\
5030 DATA_BLOB blob;\
5031 const char *str;\
5032 torture_assert(tctx,\
5033 test_GetPrinterDataEx(tctx, p, handle, "DsSpooler", wname, &type, &data, &needed),\
5034 "failed to query");\
5035 torture_assert_int_equal(tctx, type, REG_SZ, "unexpected type");\
5036 blob = data_blob_const(data, needed);\
5037 torture_assert(tctx,\
5038 pull_reg_sz(tctx, &blob, &str),\
5039 "failed to pull REG_SZ");\
5040 torture_assert_str_equal(tctx, str, iname, "unexpected result");\
5041 } while(0);
5044 #define TEST_SET_SZ(wname, iname, val) \
5045 do {\
5046 enum winreg_Type type;\
5047 uint8_t *data;\
5048 uint32_t needed;\
5049 DATA_BLOB blob;\
5050 const char *str;\
5051 sinfo.info2->iname = val;\
5052 torture_assert(tctx,\
5053 test_SetPrinter(tctx, b, handle, &info_ctr, &devmode_ctr, &secdesc_ctr, 0),\
5054 "failed to call SetPrinter");\
5055 torture_assert(tctx,\
5056 test_GetPrinterDataEx(tctx, p, handle, "DsSpooler", wname, &type, &data, &needed),\
5057 "failed to query");\
5058 torture_assert_int_equal(tctx, type, REG_SZ, "unexpected type");\
5059 blob = data_blob_const(data, needed);\
5060 torture_assert(tctx,\
5061 pull_reg_sz(tctx, &blob, &str),\
5062 "failed to pull REG_SZ");\
5063 torture_assert_str_equal(tctx, str, val, "unexpected result");\
5064 } while(0);
5066 #define TEST_SET_DWORD(wname, iname, val) \
5067 do {\
5068 enum winreg_Type type;\
5069 uint8_t *data;\
5070 uint32_t needed;\
5071 uint32_t value;\
5072 sinfo.info2->iname = val;\
5073 torture_assert(tctx,\
5074 test_SetPrinter(tctx, b, handle, &info_ctr, &devmode_ctr, &secdesc_ctr, 0),\
5075 "failed to call SetPrinter");\
5076 torture_assert(tctx,\
5077 test_GetPrinterDataEx(tctx, p, handle, "DsSpooler", wname, &type, &data, &needed),\
5078 "failed to query");\
5079 torture_assert_int_equal(tctx, type, REG_DWORD, "unexpected type");\
5080 torture_assert_int_equal(tctx, needed, 4, "unexpected length");\
5081 value = IVAL(data, 0); \
5082 torture_assert_int_equal(tctx, value, val, "unexpected result");\
5083 } while(0);
5085 TEST_SET_SZ("description", comment, "newval");
5086 TEST_SET_SZ("location", location, "newval");
5087 /* TEST_SET_DWORD("priority", priority, 25); */
5089 torture_assert(tctx,
5090 test_GetPrinter_level(tctx, b, handle, 2, &info),
5091 "failed to query Printer level 2");
5093 TEST_SZ("description", info.info2.comment);
5094 /* TEST_SZ("driverName", info.info2.drivername); */
5095 TEST_SZ("location", info.info2.location);
5097 pname = strrchr(info.info2.printername, '\\');
5098 if (pname == NULL) {
5099 pname = info.info2.printername;
5100 } else {
5101 pname++;
5103 /* TEST_SZ("printerName", pname); */
5104 /* TEST_SZ("printSeparatorFile", info.info2.sepfile); */
5105 /* TEST_SZ("printShareName", info.info2.sharename); */
5107 /* FIXME gd: complete the list */
5109 #undef TEST_SZ
5110 #undef TEST_SET_SZ
5111 #undef TEST_DWORD
5113 torture_comment(tctx, "DsSpooler <-> SetPrinter relations test succeeded\n\n");
5115 return true;
5118 static bool test_GetChangeID_PrinterData(struct torture_context *tctx,
5119 struct dcerpc_binding_handle *b,
5120 struct policy_handle *handle,
5121 uint32_t *change_id)
5123 enum winreg_Type type;
5124 uint8_t *data;
5125 uint32_t needed;
5127 torture_assert(tctx,
5128 test_GetPrinterData(tctx, b, handle, "ChangeID", &type, &data, &needed),
5129 "failed to call GetPrinterData");
5131 torture_assert(tctx, type == REG_DWORD, "unexpected type");
5132 torture_assert_int_equal(tctx, needed, 4, "unexpected size");
5134 *change_id = IVAL(data, 0);
5136 return true;
5139 static bool test_GetChangeID_PrinterDataEx(struct torture_context *tctx,
5140 struct dcerpc_pipe *p,
5141 struct policy_handle *handle,
5142 uint32_t *change_id)
5144 enum winreg_Type type;
5145 uint8_t *data;
5146 uint32_t needed;
5148 torture_assert(tctx,
5149 test_GetPrinterDataEx(tctx, p, handle, "PrinterDriverData", "ChangeID", &type, &data, &needed),
5150 "failed to call GetPrinterData");
5152 torture_assert(tctx, type == REG_DWORD, "unexpected type");
5153 torture_assert_int_equal(tctx, needed, 4, "unexpected size");
5155 *change_id = IVAL(data, 0);
5157 return true;
5160 static bool test_GetChangeID_PrinterInfo(struct torture_context *tctx,
5161 struct dcerpc_binding_handle *b,
5162 struct policy_handle *handle,
5163 uint32_t *change_id)
5165 union spoolss_PrinterInfo info;
5167 torture_assert(tctx, test_GetPrinter_level(tctx, b, handle, 0, &info),
5168 "failed to query Printer level 0");
5170 *change_id = info.info0.change_id;
5172 return true;
5175 static bool test_ChangeID(struct torture_context *tctx,
5176 struct dcerpc_pipe *p,
5177 struct policy_handle *handle)
5179 uint32_t change_id, change_id_ex, change_id_info;
5180 uint32_t change_id2, change_id_ex2, change_id_info2;
5181 union spoolss_PrinterInfo info;
5182 const char *comment;
5183 struct dcerpc_binding_handle *b = p->binding_handle;
5185 torture_comment(tctx, "Testing ChangeID: id change test #1\n");
5187 torture_assert(tctx, test_GetChangeID_PrinterData(tctx, b, handle, &change_id),
5188 "failed to query for ChangeID");
5189 torture_assert(tctx, test_GetChangeID_PrinterDataEx(tctx, p, handle, &change_id_ex),
5190 "failed to query for ChangeID");
5191 torture_assert(tctx, test_GetChangeID_PrinterInfo(tctx, b, handle, &change_id_info),
5192 "failed to query for ChangeID");
5194 torture_assert_int_equal(tctx, change_id, change_id_ex,
5195 "change_ids should all be equal");
5196 torture_assert_int_equal(tctx, change_id_ex, change_id_info,
5197 "change_ids should all be equal");
5200 torture_comment(tctx, "Testing ChangeID: id change test #2\n");
5202 torture_assert(tctx, test_GetChangeID_PrinterData(tctx, b, handle, &change_id),
5203 "failed to query for ChangeID");
5204 torture_assert(tctx, test_GetPrinter_level(tctx, b, handle, 2, &info),
5205 "failed to query Printer level 2");
5206 torture_assert(tctx, test_GetChangeID_PrinterDataEx(tctx, p, handle, &change_id_ex),
5207 "failed to query for ChangeID");
5208 torture_assert(tctx, test_GetChangeID_PrinterInfo(tctx, b, handle, &change_id_info),
5209 "failed to query for ChangeID");
5210 torture_assert_int_equal(tctx, change_id, change_id_ex,
5211 "change_id should not have changed");
5212 torture_assert_int_equal(tctx, change_id_ex, change_id_info,
5213 "change_id should not have changed");
5216 torture_comment(tctx, "Testing ChangeID: id change test #3\n");
5218 torture_assert(tctx, test_GetChangeID_PrinterData(tctx, b, handle, &change_id),
5219 "failed to query for ChangeID");
5220 torture_assert(tctx, test_GetChangeID_PrinterDataEx(tctx, p, handle, &change_id_ex),
5221 "failed to query for ChangeID");
5222 torture_assert(tctx, test_GetChangeID_PrinterInfo(tctx, b, handle, &change_id_info),
5223 "failed to query for ChangeID");
5224 torture_assert(tctx, test_GetPrinter_level(tctx, b, handle, 2, &info),
5225 "failed to query Printer level 2");
5226 comment = talloc_strdup(tctx, info.info2.comment);
5229 struct spoolss_SetPrinterInfoCtr info_ctr;
5230 struct spoolss_DevmodeContainer devmode_ctr;
5231 struct sec_desc_buf secdesc_ctr;
5232 union spoolss_SetPrinterInfo sinfo;
5234 ZERO_STRUCT(info_ctr);
5235 ZERO_STRUCT(devmode_ctr);
5236 ZERO_STRUCT(secdesc_ctr);
5239 torture_assert(tctx, PrinterInfo_to_SetPrinterInfo(tctx, &info, 2, &sinfo), "");
5240 sinfo.info2->comment = "torture_comment";
5242 info_ctr.level = 2;
5243 info_ctr.info = sinfo;
5245 torture_assert(tctx, test_SetPrinter(tctx, b, handle, &info_ctr, &devmode_ctr, &secdesc_ctr, 0),
5246 "failed to call SetPrinter");
5248 sinfo.info2->comment = comment;
5250 torture_assert(tctx, test_SetPrinter(tctx, b, handle, &info_ctr, &devmode_ctr, &secdesc_ctr, 0),
5251 "failed to call SetPrinter");
5255 torture_assert(tctx, test_GetChangeID_PrinterData(tctx, b, handle, &change_id2),
5256 "failed to query for ChangeID");
5257 torture_assert(tctx, test_GetChangeID_PrinterDataEx(tctx, p, handle, &change_id_ex2),
5258 "failed to query for ChangeID");
5259 torture_assert(tctx, test_GetChangeID_PrinterInfo(tctx, b, handle, &change_id_info2),
5260 "failed to query for ChangeID");
5262 torture_assert_int_equal(tctx, change_id2, change_id_ex2,
5263 "change_ids should all be equal");
5264 torture_assert_int_equal(tctx, change_id_ex2, change_id_info2,
5265 "change_ids should all be equal");
5267 torture_assert(tctx, (change_id < change_id2),
5268 talloc_asprintf(tctx, "change_id %d needs to be larger than change_id %d",
5269 change_id2, change_id));
5270 torture_assert(tctx, (change_id_ex < change_id_ex2),
5271 talloc_asprintf(tctx, "change_id %d needs to be larger than change_id %d",
5272 change_id_ex2, change_id_ex));
5273 torture_assert(tctx, (change_id_info < change_id_info2),
5274 talloc_asprintf(tctx, "change_id %d needs to be larger than change_id %d",
5275 change_id_info2, change_id_info));
5277 torture_comment(tctx, "ChangeID tests succeeded\n\n");
5279 return true;
5282 static bool test_SecondaryClosePrinter(struct torture_context *tctx,
5283 struct dcerpc_pipe *p,
5284 struct policy_handle *handle)
5286 NTSTATUS status;
5287 struct dcerpc_binding *b;
5288 struct dcerpc_pipe *p2;
5289 struct spoolss_ClosePrinter cp;
5291 /* only makes sense on SMB */
5292 if (p->conn->transport.transport != NCACN_NP) {
5293 return true;
5296 torture_comment(tctx, "Testing close on secondary pipe\n");
5298 status = dcerpc_parse_binding(tctx, p->conn->binding_string, &b);
5299 torture_assert_ntstatus_ok(tctx, status, "Failed to parse dcerpc binding");
5301 status = dcerpc_secondary_connection(p, &p2, b);
5302 torture_assert_ntstatus_ok(tctx, status, "Failed to create secondary connection");
5304 status = dcerpc_bind_auth_none(p2, &ndr_table_spoolss);
5305 torture_assert_ntstatus_ok(tctx, status, "Failed to create bind on secondary connection");
5307 cp.in.handle = handle;
5308 cp.out.handle = handle;
5310 status = dcerpc_spoolss_ClosePrinter_r(p2->binding_handle, tctx, &cp);
5311 torture_assert_ntstatus_equal(tctx, status, NT_STATUS_RPC_SS_CONTEXT_MISMATCH,
5312 "ERROR: Allowed close on secondary connection");
5314 talloc_free(p2);
5316 return true;
5319 static bool test_OpenPrinter_badname(struct torture_context *tctx,
5320 struct dcerpc_binding_handle *b, const char *name)
5322 NTSTATUS status;
5323 struct spoolss_OpenPrinter op;
5324 struct spoolss_OpenPrinterEx opEx;
5325 struct policy_handle handle;
5326 bool ret = true;
5328 op.in.printername = name;
5329 op.in.datatype = NULL;
5330 op.in.devmode_ctr.devmode= NULL;
5331 op.in.access_mask = 0;
5332 op.out.handle = &handle;
5334 torture_comment(tctx, "Testing OpenPrinter(%s) with bad name\n", op.in.printername);
5336 status = dcerpc_spoolss_OpenPrinter_r(b, tctx, &op);
5337 torture_assert_ntstatus_ok(tctx, status, "OpenPrinter failed");
5338 torture_assert_werr_equal(tctx, op.out.result, WERR_INVALID_PRINTER_NAME,
5339 "unexpected result");
5341 if (W_ERROR_IS_OK(op.out.result)) {
5342 ret &=test_ClosePrinter(tctx, b, &handle);
5345 opEx.in.printername = name;
5346 opEx.in.datatype = NULL;
5347 opEx.in.devmode_ctr.devmode = NULL;
5348 opEx.in.access_mask = 0;
5349 opEx.in.level = 1;
5350 opEx.in.userlevel.level1 = NULL;
5351 opEx.out.handle = &handle;
5353 torture_comment(tctx, "Testing OpenPrinterEx(%s) with bad name\n", opEx.in.printername);
5355 status = dcerpc_spoolss_OpenPrinterEx_r(b, tctx, &opEx);
5356 torture_assert_ntstatus_ok(tctx, status, "OpenPrinterEx failed");
5357 torture_assert_werr_equal(tctx, opEx.out.result, WERR_INVALID_PARAM,
5358 "unexpected result");
5360 if (W_ERROR_IS_OK(opEx.out.result)) {
5361 ret &=test_ClosePrinter(tctx, b, &handle);
5364 return ret;
5367 static bool test_OpenPrinter_badname_list(struct torture_context *tctx,
5368 struct dcerpc_binding_handle *b,
5369 const char *server_name)
5371 const char *badnames[] = {
5372 "__INVALID_PRINTER__",
5373 "\\\\__INVALID_HOST__",
5375 "\\\\\\",
5376 "\\\\\\__INVALID_PRINTER__"
5378 const char *badname;
5379 int i;
5381 for (i=0; i < ARRAY_SIZE(badnames); i++) {
5382 torture_assert(tctx,
5383 test_OpenPrinter_badname(tctx, b, badnames[i]),
5384 "");
5387 badname = talloc_asprintf(tctx, "\\\\%s\\", server_name);
5388 torture_assert(tctx,
5389 test_OpenPrinter_badname(tctx, b, badname),
5390 "");
5392 badname = talloc_asprintf(tctx, "\\\\%s\\__INVALID_PRINTER__", server_name);
5393 torture_assert(tctx,
5394 test_OpenPrinter_badname(tctx, b, badname),
5395 "");
5397 return true;
5400 static bool test_OpenPrinter(struct torture_context *tctx,
5401 struct dcerpc_pipe *p,
5402 const char *name,
5403 const char *environment)
5405 NTSTATUS status;
5406 struct spoolss_OpenPrinter r;
5407 struct policy_handle handle;
5408 bool ret = true;
5409 struct dcerpc_binding_handle *b = p->binding_handle;
5411 r.in.printername = talloc_asprintf(tctx, "\\\\%s\\%s", dcerpc_server_name(p), name);
5412 r.in.datatype = NULL;
5413 r.in.devmode_ctr.devmode= NULL;
5414 r.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
5415 r.out.handle = &handle;
5417 torture_comment(tctx, "Testing OpenPrinter(%s)\n", r.in.printername);
5419 status = dcerpc_spoolss_OpenPrinter_r(b, tctx, &r);
5421 torture_assert_ntstatus_ok(tctx, status, "OpenPrinter failed");
5423 torture_assert_werr_ok(tctx, r.out.result, "OpenPrinter failed");
5425 if (!test_GetPrinter(tctx, b, &handle, environment)) {
5426 ret = false;
5429 if (!torture_setting_bool(tctx, "samba3", false)) {
5430 if (!test_SecondaryClosePrinter(tctx, p, &handle)) {
5431 ret = false;
5435 if (!test_ClosePrinter(tctx, b, &handle)) {
5436 ret = false;
5439 return ret;
5442 static bool call_OpenPrinterEx(struct torture_context *tctx,
5443 struct dcerpc_pipe *p,
5444 const char *name,
5445 struct spoolss_DeviceMode *devmode,
5446 struct policy_handle *handle)
5448 struct spoolss_OpenPrinterEx r;
5449 struct spoolss_UserLevel1 userlevel1;
5450 NTSTATUS status;
5451 struct dcerpc_binding_handle *b = p->binding_handle;
5453 if (name && name[0]) {
5454 r.in.printername = talloc_asprintf(tctx, "\\\\%s\\%s",
5455 dcerpc_server_name(p), name);
5456 } else {
5457 r.in.printername = talloc_asprintf(tctx, "\\\\%s",
5458 dcerpc_server_name(p));
5461 r.in.datatype = NULL;
5462 r.in.devmode_ctr.devmode= devmode;
5463 r.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
5464 r.in.level = 1;
5465 r.in.userlevel.level1 = &userlevel1;
5466 r.out.handle = handle;
5468 userlevel1.size = 1234;
5469 userlevel1.client = "hello";
5470 userlevel1.user = "spottyfoot!";
5471 userlevel1.build = 1;
5472 userlevel1.major = 2;
5473 userlevel1.minor = 3;
5474 userlevel1.processor = 4;
5476 torture_comment(tctx, "Testing OpenPrinterEx(%s)\n", r.in.printername);
5478 status = dcerpc_spoolss_OpenPrinterEx_r(b, tctx, &r);
5480 torture_assert_ntstatus_ok(tctx, status, "OpenPrinterEx failed");
5482 torture_assert_werr_ok(tctx, r.out.result, "OpenPrinterEx failed");
5484 return true;
5487 static bool test_printer_rename(struct torture_context *tctx,
5488 struct dcerpc_pipe *p,
5489 struct policy_handle *handle,
5490 const char *name)
5492 bool ret = true;
5493 union spoolss_PrinterInfo info;
5494 union spoolss_SetPrinterInfo sinfo;
5495 struct spoolss_SetPrinterInfoCtr info_ctr;
5496 struct spoolss_DevmodeContainer devmode_ctr;
5497 struct sec_desc_buf secdesc_ctr;
5498 const char *printer_name;
5499 const char *printer_name_orig;
5500 const char *printer_name_new = "SAMBA smbtorture Test Printer (Copy 2)";
5501 struct policy_handle new_handle;
5502 const char *q;
5503 struct dcerpc_binding_handle *b = p->binding_handle;
5505 ZERO_STRUCT(devmode_ctr);
5506 ZERO_STRUCT(secdesc_ctr);
5508 torture_comment(tctx, "Testing Printer rename operations\n");
5510 torture_assert(tctx,
5511 test_GetPrinter_level(tctx, b, handle, 2, &info),
5512 "failed to call GetPrinter level 2");
5514 printer_name_orig = talloc_strdup(tctx, info.info2.printername);
5516 q = strrchr(info.info2.printername, '\\');
5517 if (q) {
5518 torture_warning(tctx,
5519 "server returns printername %s incl. servername although we did not set servername", info.info2.printername);
5522 torture_assert(tctx,
5523 PrinterInfo_to_SetPrinterInfo(tctx, &info, 2, &sinfo), "");
5525 sinfo.info2->printername = printer_name_new;
5527 info_ctr.level = 2;
5528 info_ctr.info = sinfo;
5530 torture_assert(tctx,
5531 test_SetPrinter(tctx, b, handle, &info_ctr, &devmode_ctr, &secdesc_ctr, 0),
5532 "failed to call SetPrinter level 2");
5534 torture_assert(tctx,
5535 test_GetPrinter_level(tctx, b, handle, 2, &info),
5536 "failed to call GetPrinter level 2");
5538 printer_name = talloc_strdup(tctx, info.info2.printername);
5540 q = strrchr(info.info2.printername, '\\');
5541 if (q) {
5542 torture_warning(tctx,
5543 "server returns printername %s incl. servername although we did not set servername", info.info2.printername);
5544 q++;
5545 printer_name = q;
5548 torture_assert_str_equal(tctx, printer_name, printer_name_new,
5549 "new printer name was not set");
5551 /* samba currently cannot fully rename printers */
5552 if (!torture_setting_bool(tctx, "samba3", false)) {
5553 torture_assert(tctx,
5554 test_OpenPrinter_badname(tctx, b, printer_name_orig),
5555 "still can open printer with oldname after rename");
5556 } else {
5557 torture_warning(tctx, "*not* checking for open with oldname after rename for samba3");
5560 torture_assert(tctx,
5561 call_OpenPrinterEx(tctx, p, printer_name_new, NULL, &new_handle),
5562 "failed to open printer with new name");
5564 torture_assert(tctx,
5565 test_GetPrinter_level(tctx, b, &new_handle, 2, &info),
5566 "failed to call GetPrinter level 2");
5568 /* FIXME: we openend with servername! */
5569 printer_name = talloc_asprintf(tctx, "\\\\%s\\%s",
5570 dcerpc_server_name(p), printer_name_new);
5572 torture_assert_str_equal(tctx, info.info2.printername, printer_name,
5573 "new printer name was not set");
5575 torture_assert(tctx,
5576 test_ClosePrinter(tctx, b, &new_handle),
5577 "failed to close printer");
5579 torture_comment(tctx, "Printer rename operations test succeeded\n\n");
5581 return ret;
5585 static bool test_OpenPrinterEx(struct torture_context *tctx,
5586 struct dcerpc_pipe *p,
5587 const char *name,
5588 const char *environment)
5590 struct policy_handle handle;
5591 bool ret = true;
5592 struct dcerpc_binding_handle *b = p->binding_handle;
5594 if (!call_OpenPrinterEx(tctx, p, name, NULL, &handle)) {
5595 return false;
5598 if (!test_PrinterInfo_SD(tctx, b, &handle)) {
5599 ret = false;
5602 if (!test_GetPrinter(tctx, b, &handle, environment)) {
5603 ret = false;
5606 if (!test_EnumForms_all(tctx, b, &handle, false)) {
5607 ret = false;
5610 if (!test_Forms(tctx, b, &handle, false, name, NULL, NULL)) {
5611 ret = false;
5614 if (!test_Forms_winreg(tctx, b, &handle, false, name)) {
5615 ret = false;
5618 if (!test_EnumPrinterData_all(tctx, p, &handle)) {
5619 ret = false;
5622 if (!test_EnumPrinterDataEx(tctx, b, &handle, "PrinterDriverData", NULL, NULL)) {
5623 ret = false;
5626 if (!test_EnumPrinterData_consistency(tctx, p, &handle)) {
5627 ret = false;
5630 if (!test_printer_keys(tctx, b, &handle)) {
5631 ret = false;
5634 if (!test_PausePrinter(tctx, b, &handle)) {
5635 ret = false;
5638 if (!test_DoPrintTest(tctx, b, &handle)) {
5639 ret = false;
5642 if (!test_ResumePrinter(tctx, b, &handle)) {
5643 ret = false;
5646 if (!test_SetPrinterData_matrix(tctx, b, &handle, name, NULL, NULL)) {
5647 ret = false;
5650 if (!test_SetPrinterDataEx_matrix(tctx, p, &handle, name, NULL, NULL)) {
5651 ret = false;
5654 if (!torture_setting_bool(tctx, "samba3", false)) {
5655 if (!test_SecondaryClosePrinter(tctx, p, &handle)) {
5656 ret = false;
5660 if (!test_ClosePrinter(tctx, b, &handle)) {
5661 ret = false;
5664 return ret;
5667 static bool test_EnumPrinters_old(struct torture_context *tctx,
5668 struct dcerpc_pipe *p,
5669 const char *environment)
5671 struct spoolss_EnumPrinters r;
5672 NTSTATUS status;
5673 uint16_t levels[] = {1, 2, 4, 5};
5674 int i;
5675 bool ret = true;
5676 struct dcerpc_binding_handle *b = p->binding_handle;
5678 for (i=0;i<ARRAY_SIZE(levels);i++) {
5679 union spoolss_PrinterInfo *info;
5680 int j;
5681 uint32_t needed;
5682 uint32_t count;
5684 r.in.flags = PRINTER_ENUM_LOCAL;
5685 r.in.server = "";
5686 r.in.level = levels[i];
5687 r.in.buffer = NULL;
5688 r.in.offered = 0;
5689 r.out.needed = &needed;
5690 r.out.count = &count;
5691 r.out.info = &info;
5693 torture_comment(tctx, "Testing EnumPrinters level %u\n", r.in.level);
5695 status = dcerpc_spoolss_EnumPrinters_r(b, tctx, &r);
5696 torture_assert_ntstatus_ok(tctx, status, "EnumPrinters failed");
5698 if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
5699 DATA_BLOB blob = data_blob_talloc_zero(tctx, needed);
5700 r.in.buffer = &blob;
5701 r.in.offered = needed;
5702 status = dcerpc_spoolss_EnumPrinters_r(b, tctx, &r);
5705 torture_assert_ntstatus_ok(tctx, status, "EnumPrinters failed");
5707 torture_assert_werr_ok(tctx, r.out.result, "EnumPrinters failed");
5709 CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumPrinters, info, r.in.level, count, needed, 4);
5711 if (!info) {
5712 torture_comment(tctx, "No printers returned\n");
5713 return true;
5716 for (j=0;j<count;j++) {
5717 if (r.in.level == 1) {
5718 char *unc = talloc_strdup(tctx, info[j].info1.name);
5719 char *slash, *name;
5720 name = unc;
5721 if (unc[0] == '\\' && unc[1] == '\\') {
5722 unc +=2;
5724 slash = strchr(unc, '\\');
5725 if (slash) {
5726 slash++;
5727 name = slash;
5729 if (!test_OpenPrinter(tctx, p, name, environment)) {
5730 ret = false;
5732 if (!test_OpenPrinterEx(tctx, p, name, environment)) {
5733 ret = false;
5739 return ret;
5742 static bool test_GetPrinterDriver(struct torture_context *tctx,
5743 struct dcerpc_binding_handle *b,
5744 struct policy_handle *handle,
5745 const char *driver_name)
5747 struct spoolss_GetPrinterDriver r;
5748 uint32_t needed;
5750 r.in.handle = handle;
5751 r.in.architecture = "W32X86";
5752 r.in.level = 1;
5753 r.in.buffer = NULL;
5754 r.in.offered = 0;
5755 r.out.needed = &needed;
5757 torture_comment(tctx, "Testing GetPrinterDriver level %d\n", r.in.level);
5759 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_GetPrinterDriver_r(b, tctx, &r),
5760 "failed to call GetPrinterDriver");
5761 if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
5762 DATA_BLOB blob = data_blob_talloc_zero(tctx, needed);
5763 r.in.buffer = &blob;
5764 r.in.offered = needed;
5765 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_GetPrinterDriver_r(b, tctx, &r),
5766 "failed to call GetPrinterDriver");
5769 torture_assert_werr_ok(tctx, r.out.result,
5770 "failed to call GetPrinterDriver");
5772 CHECK_NEEDED_SIZE_LEVEL(spoolss_DriverInfo, r.out.info, r.in.level, needed, 4);
5774 return true;
5777 static bool test_GetPrinterDriver2_level(struct torture_context *tctx,
5778 struct dcerpc_binding_handle *b,
5779 struct policy_handle *handle,
5780 const char *driver_name,
5781 const char *architecture,
5782 uint32_t level,
5783 uint32_t client_major_version,
5784 uint32_t client_minor_version,
5785 union spoolss_DriverInfo *info_p,
5786 WERROR *result_p)
5789 struct spoolss_GetPrinterDriver2 r;
5790 uint32_t needed;
5791 uint32_t server_major_version;
5792 uint32_t server_minor_version;
5794 r.in.handle = handle;
5795 r.in.architecture = architecture;
5796 r.in.client_major_version = client_major_version;
5797 r.in.client_minor_version = client_minor_version;
5798 r.in.buffer = NULL;
5799 r.in.offered = 0;
5800 r.in.level = level;
5801 r.out.needed = &needed;
5802 r.out.server_major_version = &server_major_version;
5803 r.out.server_minor_version = &server_minor_version;
5805 torture_comment(tctx, "Testing GetPrinterDriver2(%s) level %d\n",
5806 driver_name, r.in.level);
5808 torture_assert_ntstatus_ok(tctx,
5809 dcerpc_spoolss_GetPrinterDriver2_r(b, tctx, &r),
5810 "failed to call GetPrinterDriver2");
5811 if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
5812 DATA_BLOB blob = data_blob_talloc_zero(tctx, needed);
5813 r.in.buffer = &blob;
5814 r.in.offered = needed;
5815 torture_assert_ntstatus_ok(tctx,
5816 dcerpc_spoolss_GetPrinterDriver2_r(b, tctx, &r),
5817 "failed to call GetPrinterDriver2");
5820 if (result_p) {
5821 *result_p = r.out.result;
5824 if (W_ERROR_EQUAL(r.out.result, WERR_INVALID_LEVEL)) {
5825 switch (r.in.level) {
5826 case 101:
5827 case 8:
5828 torture_comment(tctx,
5829 "level %d not implemented, not considering as an error\n",
5830 r.in.level);
5831 return true;
5832 default:
5833 break;
5837 torture_assert_werr_ok(tctx, r.out.result,
5838 "failed to call GetPrinterDriver2");
5840 CHECK_NEEDED_SIZE_LEVEL(spoolss_DriverInfo, r.out.info, r.in.level, needed, 4);
5842 if (info_p) {
5843 *info_p = *r.out.info;
5846 return true;
5849 static bool test_GetPrinterDriver2(struct torture_context *tctx,
5850 struct dcerpc_binding_handle *b,
5851 struct policy_handle *handle,
5852 const char *driver_name,
5853 const char *architecture)
5855 uint16_t levels[] = {1, 2, 3, 4, 5, 6, 8, 101 };
5856 int i;
5859 for (i=0;i<ARRAY_SIZE(levels);i++) {
5861 torture_assert(tctx,
5862 test_GetPrinterDriver2_level(tctx, b, handle, driver_name, architecture, levels[i], 3, 0, NULL, NULL),
5863 "");
5866 return true;
5869 static bool test_EnumPrinterDrivers_old(struct torture_context *tctx,
5870 struct dcerpc_pipe *p,
5871 const char *environment)
5873 uint16_t levels[] = {1, 2, 3, 4, 5, 6};
5874 int i;
5875 struct dcerpc_binding_handle *b = p->binding_handle;
5876 const char *server_name = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
5878 for (i=0;i<ARRAY_SIZE(levels);i++) {
5880 uint32_t count;
5881 union spoolss_DriverInfo *info;
5883 torture_assert(tctx,
5884 test_EnumPrinterDrivers_args(tctx, b, server_name, environment, levels[i], &count, &info),
5885 "failed to enumerate drivers");
5887 if (!info) {
5888 torture_comment(tctx, "No printer drivers returned\n");
5889 break;
5893 return true;
5896 static bool test_DeletePrinter(struct torture_context *tctx,
5897 struct dcerpc_binding_handle *b,
5898 struct policy_handle *handle)
5900 struct spoolss_DeletePrinter r;
5902 torture_comment(tctx, "Testing DeletePrinter\n");
5904 r.in.handle = handle;
5906 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_DeletePrinter_r(b, tctx, &r),
5907 "failed to delete printer");
5908 torture_assert_werr_ok(tctx, r.out.result,
5909 "failed to delete printer");
5911 return true;
5914 static bool test_EnumPrinters_findname(struct torture_context *tctx,
5915 struct dcerpc_binding_handle *b,
5916 uint32_t flags,
5917 uint32_t level,
5918 const char *name,
5919 bool *found)
5921 struct spoolss_EnumPrinters e;
5922 uint32_t count;
5923 union spoolss_PrinterInfo *info;
5924 uint32_t needed;
5925 int i;
5927 *found = false;
5929 e.in.flags = flags;
5930 e.in.server = NULL;
5931 e.in.level = level;
5932 e.in.buffer = NULL;
5933 e.in.offered = 0;
5934 e.out.count = &count;
5935 e.out.info = &info;
5936 e.out.needed = &needed;
5938 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_EnumPrinters_r(b, tctx, &e),
5939 "failed to enum printers");
5941 if (W_ERROR_EQUAL(e.out.result, WERR_INSUFFICIENT_BUFFER)) {
5942 DATA_BLOB blob = data_blob_talloc_zero(tctx, needed);
5943 e.in.buffer = &blob;
5944 e.in.offered = needed;
5946 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_EnumPrinters_r(b, tctx, &e),
5947 "failed to enum printers");
5950 torture_assert_werr_ok(tctx, e.out.result,
5951 "failed to enum printers");
5953 for (i=0; i < count; i++) {
5955 const char *current = NULL;
5956 const char *q;
5958 switch (level) {
5959 case 1:
5960 current = info[i].info1.name;
5961 break;
5964 if (strequal(current, name)) {
5965 *found = true;
5966 break;
5969 q = strrchr(current, '\\');
5970 if (q) {
5971 if (!e.in.server) {
5972 torture_warning(tctx,
5973 "server returns printername %s incl. servername although we did not set servername", current);
5975 q++;
5976 if (strequal(q, name)) {
5977 *found = true;
5978 break;
5983 return true;
5986 static bool test_AddPrinter_wellknown(struct torture_context *tctx,
5987 struct dcerpc_pipe *p,
5988 const char *printername,
5989 bool ex)
5991 WERROR result;
5992 struct spoolss_AddPrinter r;
5993 struct spoolss_AddPrinterEx rex;
5994 struct spoolss_SetPrinterInfoCtr info_ctr;
5995 struct spoolss_SetPrinterInfo1 info1;
5996 struct spoolss_DevmodeContainer devmode_ctr;
5997 struct sec_desc_buf secdesc_ctr;
5998 struct spoolss_UserLevelCtr userlevel_ctr;
5999 struct policy_handle handle;
6000 bool found = false;
6001 struct dcerpc_binding_handle *b = p->binding_handle;
6003 ZERO_STRUCT(devmode_ctr);
6004 ZERO_STRUCT(secdesc_ctr);
6005 ZERO_STRUCT(userlevel_ctr);
6006 ZERO_STRUCT(info1);
6008 torture_comment(tctx, "Testing AddPrinter%s(%s) level 1\n",
6009 ex ? "Ex":"", printername);
6011 /* try to add printer to wellknown printer list (level 1) */
6013 userlevel_ctr.level = 1;
6015 info_ctr.info.info1 = &info1;
6016 info_ctr.level = 1;
6018 rex.in.server = NULL;
6019 rex.in.info_ctr = &info_ctr;
6020 rex.in.devmode_ctr = &devmode_ctr;
6021 rex.in.secdesc_ctr = &secdesc_ctr;
6022 rex.in.userlevel_ctr = &userlevel_ctr;
6023 rex.out.handle = &handle;
6025 r.in.server = NULL;
6026 r.in.info_ctr = &info_ctr;
6027 r.in.devmode_ctr = &devmode_ctr;
6028 r.in.secdesc_ctr = &secdesc_ctr;
6029 r.out.handle = &handle;
6031 torture_assert_ntstatus_ok(tctx, ex ? dcerpc_spoolss_AddPrinterEx_r(b, tctx, &rex) :
6032 dcerpc_spoolss_AddPrinter_r(b, tctx, &r),
6033 "failed to add printer");
6034 result = ex ? rex.out.result : r.out.result;
6035 torture_assert_werr_equal(tctx, result, WERR_INVALID_PRINTER_NAME,
6036 "unexpected result code");
6038 info1.name = printername;
6039 info1.flags = PRINTER_ATTRIBUTE_SHARED;
6041 torture_assert_ntstatus_ok(tctx, ex ? dcerpc_spoolss_AddPrinterEx_r(b, tctx, &rex) :
6042 dcerpc_spoolss_AddPrinter_r(b, tctx, &r),
6043 "failed to add printer");
6044 result = ex ? rex.out.result : r.out.result;
6045 torture_assert_werr_equal(tctx, result, WERR_PRINTER_ALREADY_EXISTS,
6046 "unexpected result code");
6048 /* bizarre protocol, WERR_PRINTER_ALREADY_EXISTS means success here,
6049 better do a real check to see the printer is really there */
6051 torture_assert(tctx, test_EnumPrinters_findname(tctx, b,
6052 PRINTER_ENUM_NETWORK, 1,
6053 printername,
6054 &found),
6055 "failed to enum printers");
6057 torture_assert(tctx, found, "failed to find newly added printer");
6059 info1.flags = 0;
6061 torture_assert_ntstatus_ok(tctx, ex ? dcerpc_spoolss_AddPrinterEx_r(b, tctx, &rex) :
6062 dcerpc_spoolss_AddPrinter_r(b, tctx, &r),
6063 "failed to add printer");
6064 result = ex ? rex.out.result : r.out.result;
6065 torture_assert_werr_equal(tctx, result, WERR_PRINTER_ALREADY_EXISTS,
6066 "unexpected result code");
6068 /* bizarre protocol, WERR_PRINTER_ALREADY_EXISTS means success here,
6069 better do a real check to see the printer has really been removed
6070 from the well known printer list */
6072 found = false;
6074 torture_assert(tctx, test_EnumPrinters_findname(tctx, b,
6075 PRINTER_ENUM_NETWORK, 1,
6076 printername,
6077 &found),
6078 "failed to enum printers");
6079 #if 0
6080 torture_assert(tctx, !found, "printer still in well known printer list");
6081 #endif
6082 return true;
6085 static bool test_AddPrinter_normal(struct torture_context *tctx,
6086 struct dcerpc_pipe *p,
6087 struct policy_handle *handle_p,
6088 const char *printername,
6089 const char *drivername,
6090 const char *portname,
6091 struct spoolss_DeviceMode *devmode,
6092 bool ex)
6094 WERROR result;
6095 struct spoolss_AddPrinter r;
6096 struct spoolss_AddPrinterEx rex;
6097 struct spoolss_SetPrinterInfoCtr info_ctr;
6098 struct spoolss_SetPrinterInfo2 info2;
6099 struct spoolss_DevmodeContainer devmode_ctr;
6100 struct sec_desc_buf secdesc_ctr;
6101 struct spoolss_UserLevelCtr userlevel_ctr;
6102 struct policy_handle handle;
6103 bool found = false;
6104 bool existing_printer_deleted = false;
6105 struct dcerpc_binding_handle *b = p->binding_handle;
6107 ZERO_STRUCT(devmode_ctr);
6108 ZERO_STRUCT(secdesc_ctr);
6109 ZERO_STRUCT(userlevel_ctr);
6111 torture_comment(tctx, "Testing AddPrinter%s(%s) level 2\n",
6112 ex ? "Ex":"", printername);
6114 devmode_ctr.devmode = devmode;
6116 userlevel_ctr.level = 1;
6118 rex.in.server = NULL;
6119 rex.in.info_ctr = &info_ctr;
6120 rex.in.devmode_ctr = &devmode_ctr;
6121 rex.in.secdesc_ctr = &secdesc_ctr;
6122 rex.in.userlevel_ctr = &userlevel_ctr;
6123 rex.out.handle = &handle;
6125 r.in.server = NULL;
6126 r.in.info_ctr = &info_ctr;
6127 r.in.devmode_ctr = &devmode_ctr;
6128 r.in.secdesc_ctr = &secdesc_ctr;
6129 r.out.handle = &handle;
6131 again:
6133 /* try to add printer to printer list (level 2) */
6135 ZERO_STRUCT(info2);
6137 info_ctr.info.info2 = &info2;
6138 info_ctr.level = 2;
6140 torture_assert_ntstatus_ok(tctx, ex ? dcerpc_spoolss_AddPrinterEx_r(b, tctx, &rex) :
6141 dcerpc_spoolss_AddPrinter_r(b, tctx, &r),
6142 "failed to add printer");
6143 result = ex ? rex.out.result : r.out.result;
6144 torture_assert_werr_equal(tctx, result, WERR_INVALID_PRINTER_NAME,
6145 "unexpected result code");
6147 info2.printername = printername;
6149 torture_assert_ntstatus_ok(tctx, ex ? dcerpc_spoolss_AddPrinterEx_r(b, tctx, &rex) :
6150 dcerpc_spoolss_AddPrinter_r(b, tctx, &r),
6151 "failed to add printer");
6152 result = ex ? rex.out.result : r.out.result;
6154 if (W_ERROR_EQUAL(result, WERR_PRINTER_ALREADY_EXISTS)) {
6155 struct policy_handle printer_handle;
6157 if (existing_printer_deleted) {
6158 torture_fail(tctx, "already deleted printer still existing?");
6161 torture_assert(tctx, call_OpenPrinterEx(tctx, p, printername, NULL, &printer_handle),
6162 "failed to open printer handle");
6164 torture_assert(tctx, test_DeletePrinter(tctx, b, &printer_handle),
6165 "failed to delete printer");
6167 torture_assert(tctx, test_ClosePrinter(tctx, b, &printer_handle),
6168 "failed to close server handle");
6170 existing_printer_deleted = true;
6172 goto again;
6175 torture_assert_werr_equal(tctx, result, WERR_UNKNOWN_PORT,
6176 "unexpected result code");
6178 info2.portname = portname;
6180 torture_assert_ntstatus_ok(tctx, ex ? dcerpc_spoolss_AddPrinterEx_r(b, tctx, &rex) :
6181 dcerpc_spoolss_AddPrinter_r(b, tctx, &r),
6182 "failed to add printer");
6183 result = ex ? rex.out.result : r.out.result;
6184 torture_assert_werr_equal(tctx, result, WERR_UNKNOWN_PRINTER_DRIVER,
6185 "unexpected result code");
6187 info2.drivername = drivername;
6189 torture_assert_ntstatus_ok(tctx, ex ? dcerpc_spoolss_AddPrinterEx_r(b, tctx, &rex) :
6190 dcerpc_spoolss_AddPrinter_r(b, tctx, &r),
6191 "failed to add printer");
6192 result = ex ? rex.out.result : r.out.result;
6194 /* w2k8r2 allows to add printer w/o defining printprocessor */
6196 if (!W_ERROR_IS_OK(result)) {
6197 torture_assert_werr_equal(tctx, result, WERR_UNKNOWN_PRINTPROCESSOR,
6198 "unexpected result code");
6200 info2.printprocessor = "winprint";
6202 torture_assert_ntstatus_ok(tctx, ex ? dcerpc_spoolss_AddPrinterEx_r(b, tctx, &rex) :
6203 dcerpc_spoolss_AddPrinter_r(b, tctx, &r),
6204 "failed to add printer");
6205 result = ex ? rex.out.result : r.out.result;
6206 torture_assert_werr_ok(tctx, result,
6207 "failed to add printer");
6210 *handle_p = handle;
6212 /* we are paranoid, really check if the printer is there now */
6214 torture_assert(tctx, test_EnumPrinters_findname(tctx, b,
6215 PRINTER_ENUM_LOCAL, 1,
6216 printername,
6217 &found),
6218 "failed to enum printers");
6219 torture_assert(tctx, found, "failed to find newly added printer");
6221 torture_assert_ntstatus_ok(tctx, ex ? dcerpc_spoolss_AddPrinterEx_r(b, tctx, &rex) :
6222 dcerpc_spoolss_AddPrinter_r(b, tctx, &r),
6223 "failed to add printer");
6224 result = ex ? rex.out.result : r.out.result;
6225 torture_assert_werr_equal(tctx, result, WERR_PRINTER_ALREADY_EXISTS,
6226 "unexpected result code");
6228 return true;
6231 static bool test_printer_info(struct torture_context *tctx,
6232 struct dcerpc_binding_handle *b,
6233 struct policy_handle *handle)
6235 bool ret = true;
6237 if (torture_setting_bool(tctx, "samba3", false)) {
6238 torture_skip(tctx, "skipping printer info cross tests against samba 3");
6241 if (!test_PrinterInfo(tctx, b, handle)) {
6242 ret = false;
6245 if (!test_SetPrinter_errors(tctx, b, handle)) {
6246 ret = false;
6249 return ret;
6252 static bool test_EnumPrinterKey(struct torture_context *tctx,
6253 struct dcerpc_binding_handle *b,
6254 struct policy_handle *handle,
6255 const char *key_name,
6256 const char ***array)
6258 struct spoolss_EnumPrinterKey r;
6259 uint32_t needed = 0;
6260 union spoolss_KeyNames key_buffer;
6261 int32_t offered[] = { 0, 1, 2, 3, 4, 5, -1, -2, -3, -4, -5, 256, 512, 1024, 2048 };
6262 uint32_t _ndr_size;
6263 int i;
6265 r.in.handle = handle;
6266 r.in.key_name = key_name;
6267 r.out.key_buffer = &key_buffer;
6268 r.out.needed = &needed;
6269 r.out._ndr_size = &_ndr_size;
6271 for (i=0; i < ARRAY_SIZE(offered); i++) {
6273 if (offered[i] < 0 && needed) {
6274 if (needed <= 4) {
6275 continue;
6277 r.in.offered = needed + offered[i];
6278 } else {
6279 r.in.offered = offered[i];
6282 ZERO_STRUCT(key_buffer);
6284 torture_comment(tctx, "Testing EnumPrinterKey(%s) with %d offered\n", r.in.key_name, r.in.offered);
6286 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_EnumPrinterKey_r(b, tctx, &r),
6287 "failed to call EnumPrinterKey");
6288 if (W_ERROR_EQUAL(r.out.result, WERR_MORE_DATA)) {
6290 torture_assert(tctx, (_ndr_size == r.in.offered/2),
6291 talloc_asprintf(tctx, "EnumPrinterKey size mismatch, _ndr_size %d (expected %d)",
6292 _ndr_size, r.in.offered/2));
6294 r.in.offered = needed;
6295 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_EnumPrinterKey_r(b, tctx, &r),
6296 "failed to call EnumPrinterKey");
6299 if (offered[i] > 0) {
6300 torture_assert_werr_ok(tctx, r.out.result,
6301 "failed to call EnumPrinterKey");
6304 torture_assert(tctx, (_ndr_size == r.in.offered/2),
6305 talloc_asprintf(tctx, "EnumPrinterKey size mismatch, _ndr_size %d (expected %d)",
6306 _ndr_size, r.in.offered/2));
6308 torture_assert(tctx, (*r.out.needed <= r.in.offered),
6309 talloc_asprintf(tctx, "EnumPrinterKey size mismatch: needed %d is not <= offered %d", *r.out.needed, r.in.offered));
6311 torture_assert(tctx, (*r.out.needed <= _ndr_size * 2),
6312 talloc_asprintf(tctx, "EnumPrinterKey size mismatch: needed %d is not <= _ndr_size %d * 2", *r.out.needed, _ndr_size));
6314 if (key_buffer.string_array) {
6315 uint32_t calc_needed = 0;
6316 int s;
6317 for (s=0; key_buffer.string_array[s]; s++) {
6318 calc_needed += strlen_m_term(key_buffer.string_array[s])*2;
6320 if (!key_buffer.string_array[0]) {
6321 calc_needed += 2;
6323 calc_needed += 2;
6325 torture_assert_int_equal(tctx, *r.out.needed, calc_needed,
6326 "EnumPrinterKey unexpected size");
6330 if (array) {
6331 *array = key_buffer.string_array;
6334 return true;
6337 bool test_printer_keys(struct torture_context *tctx,
6338 struct dcerpc_binding_handle *b,
6339 struct policy_handle *handle)
6341 const char **key_array = NULL;
6342 int i;
6344 torture_comment(tctx, "Testing Printer Keys\n");
6346 torture_assert(tctx, test_EnumPrinterKey(tctx, b, handle, "", &key_array),
6347 "failed to call test_EnumPrinterKey");
6349 for (i=0; key_array && key_array[i]; i++) {
6350 torture_assert(tctx, test_EnumPrinterKey(tctx, b, handle, key_array[i], NULL),
6351 "failed to call test_EnumPrinterKey");
6353 for (i=0; key_array && key_array[i]; i++) {
6354 torture_assert(tctx, test_EnumPrinterDataEx(tctx, b, handle, key_array[i], NULL, NULL),
6355 "failed to call test_EnumPrinterDataEx");
6358 torture_comment(tctx, "Printer Keys test succeeded\n\n");
6360 return true;
6363 static bool test_one_printer(struct torture_context *tctx,
6364 struct dcerpc_pipe *p,
6365 struct policy_handle *handle,
6366 const char *name,
6367 const char *drivername,
6368 const char *environment,
6369 bool have_driver,
6370 struct spoolss_DeviceMode *devmode)
6372 bool ret = true;
6373 struct dcerpc_binding_handle *b = p->binding_handle;
6375 if (!test_PausePrinter(tctx, b, handle)) {
6376 ret = false;
6379 if (!test_DoPrintTest(tctx, b, handle)) {
6380 ret = false;
6383 if (!test_DoPrintTest_extended(tctx, b, handle)) {
6384 torture_comment(tctx, "extended printing test failed!\n");
6387 if (!test_ResumePrinter(tctx, b, handle)) {
6388 ret = false;
6391 if (!test_printer_info(tctx, b, handle)) {
6392 ret = false;
6395 if (!test_PrinterInfo_SD(tctx, b, handle)) {
6396 ret = false;
6399 if (!test_PrinterInfo_DevMode(tctx, p, handle, name, devmode)) {
6400 ret = false;
6403 if (!test_PrinterInfo_winreg(tctx, p, handle, name)) {
6404 ret = false;
6407 if (!test_ChangeID(tctx, p, handle)) {
6408 ret = false;
6411 if (!test_printer_keys(tctx, b, handle)) {
6412 ret = false;
6415 if (!test_EnumPrinterData_consistency(tctx, p, handle)) {
6416 ret = false;
6419 if (!test_SetPrinterDataEx_matrix(tctx, p, handle, name, NULL, NULL)) {
6420 ret = false;
6423 if (!test_PrinterData_winreg(tctx, p, handle, name)) {
6424 ret = false;
6427 if (!test_PrinterData_DsSpooler(tctx, p, handle, name)) {
6428 ret = false;
6431 if (have_driver) {
6432 if (!test_DriverInfo_winreg(tctx, p, handle, name, drivername, environment)) {
6433 ret = false;
6437 if (!test_printer_rename(tctx, p, handle, name)) {
6438 ret = false;
6441 return ret;
6444 static bool test_csetprinter(struct torture_context *tctx,
6445 struct dcerpc_pipe *p,
6446 struct policy_handle *handle,
6447 const char *printername,
6448 const char *drivername,
6449 const char *portname)
6451 union spoolss_PrinterInfo info;
6452 struct policy_handle new_handle, new_handle2;
6453 struct dcerpc_binding_handle *b = p->binding_handle;
6455 torture_comment(tctx, "Testing c_setprinter\n");
6457 torture_assert(tctx,
6458 test_GetPrinter_level(tctx, b, handle, 0, &info),
6459 "failed to get level 0 printer info");
6460 torture_comment(tctx, "csetprinter on initial printer handle: %d\n",
6461 info.info0.c_setprinter);
6463 /* check if c_setprinter on 1st handle increases after a printer has
6464 * been added */
6466 torture_assert(tctx,
6467 test_AddPrinter_normal(tctx, p, &new_handle, printername, drivername, portname, NULL, false),
6468 "failed to add new printer");
6469 torture_assert(tctx,
6470 test_GetPrinter_level(tctx, b, handle, 0, &info),
6471 "failed to get level 0 printer info");
6472 torture_comment(tctx, "csetprinter on initial printer handle (after add): %d\n",
6473 info.info0.c_setprinter);
6475 /* check if c_setprinter on new handle increases after a printer has
6476 * been added */
6478 torture_assert(tctx,
6479 test_GetPrinter_level(tctx, b, &new_handle, 0, &info),
6480 "failed to get level 0 printer info");
6481 torture_comment(tctx, "csetprinter on created handle: %d\n",
6482 info.info0.c_setprinter);
6484 /* open the new printer and check if c_setprinter increases */
6486 torture_assert(tctx,
6487 call_OpenPrinterEx(tctx, p, printername, NULL, &new_handle2),
6488 "failed to open created printer");
6489 torture_assert(tctx,
6490 test_GetPrinter_level(tctx, b, &new_handle2, 0, &info),
6491 "failed to get level 0 printer info");
6492 torture_comment(tctx, "csetprinter on new handle (after openprinter): %d\n",
6493 info.info0.c_setprinter);
6495 /* cleanup */
6497 torture_assert(tctx,
6498 test_ClosePrinter(tctx, b, &new_handle2),
6499 "failed to close printer");
6500 torture_assert(tctx,
6501 test_DeletePrinter(tctx, b, &new_handle),
6502 "failed to delete new printer");
6504 return true;
6507 static bool test_add_printer_args_with_driver(struct torture_context *tctx,
6508 struct dcerpc_pipe *p,
6509 struct torture_printer_context *t)
6511 bool ret = true;
6512 struct policy_handle handle;
6513 bool found = false;
6514 struct dcerpc_binding_handle *b = p->binding_handle;
6515 const char *printer_name = t->info2.printername;
6516 const char *driver_name = t->added_driver ? t->driver.info8.driver_name : t->info2.drivername;
6517 const char *port_name = t->info2.portname;
6518 const char *printer_name2 = talloc_asprintf(tctx, "%s2", printer_name);
6520 if (t->wellknown) {
6521 torture_assert(tctx,
6522 test_AddPrinter_wellknown(tctx, p, printer_name, t->ex),
6523 "failed to add wellknown printer");
6524 } else {
6525 torture_assert(tctx,
6526 test_AddPrinter_normal(tctx, p, &handle, printer_name, driver_name, port_name, t->devmode, t->ex),
6527 "failed to add printer");
6530 if (!test_csetprinter(tctx, p, &handle, printer_name2, driver_name, port_name)) {
6531 ret = false;
6534 if (!test_one_printer(tctx, p, &handle, printer_name, driver_name, t->driver.remote.environment, t->have_driver, t->devmode)) {
6535 ret = false;
6538 if (!test_DeletePrinter(tctx, b, &handle)) {
6539 ret = false;
6542 if (!test_EnumPrinters_findname(tctx, b, PRINTER_ENUM_LOCAL, 1,
6543 printer_name, &found)) {
6544 ret = false;
6547 torture_assert(tctx, !found, "deleted printer still there");
6549 return ret;
6552 static bool compose_local_driver_directory(struct torture_context *tctx,
6553 const char *environment,
6554 const char *local_dir,
6555 const char **path)
6557 char *p;
6559 p = strrchr(local_dir, '/');
6560 if (!p) {
6561 return NULL;
6563 p++;
6565 if (strequal(environment, "Windows x64")) {
6566 if (!strequal(p, "x64")) {
6567 *path = talloc_asprintf(tctx, "%s/x64", local_dir);
6569 } else if (strequal(environment, "Windows NT x86")) {
6570 if (!strequal(p, "i386")) {
6571 *path = talloc_asprintf(tctx, "%s/i386", local_dir);
6573 } else {
6574 torture_assert(tctx, "unknown environment: '%s'\n", environment);
6577 return true;
6580 static bool test_add_printer_args(struct torture_context *tctx,
6581 struct dcerpc_pipe *p,
6582 struct torture_printer_context *t)
6584 bool ret = true;
6585 struct dcerpc_binding_handle *b = p->binding_handle;
6586 const char *server_name_slash = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
6588 if (t->wellknown && torture_setting_bool(tctx, "samba3", false)) {
6589 torture_skip(tctx, "skipping AddPrinter level 1 against samba");
6592 torture_assert(tctx,
6593 fillup_printserver_info(tctx, p, &t->driver),
6594 "failed to fillup printserver info");
6596 t->driver.info8.architecture = talloc_strdup(t, t->driver.remote.environment);
6598 torture_assert(tctx,
6599 compose_local_driver_directory(tctx, t->driver.remote.environment,
6600 t->driver.local.driver_directory,
6601 &t->driver.local.driver_directory),
6602 "failed to compose local driver directory");
6604 if (test_EnumPrinterDrivers_findone(tctx, b, server_name_slash, t->driver.remote.environment, 3, t->info2.drivername)) {
6605 t->have_driver = true;
6606 goto try_run;
6609 torture_comment(tctx, "driver '%s' (architecture: %s, version: 3) does not exist on the server\n",
6610 t->info2.drivername, t->driver.remote.environment);
6611 torture_comment(tctx, "trying to upload own driver\n");
6613 if (!directory_exist(t->driver.local.driver_directory)) {
6614 torture_warning(tctx, "no local driver is available!");
6615 t->have_driver = false;
6616 goto try_run;
6619 torture_assert(tctx,
6620 upload_printer_driver(tctx, dcerpc_server_name(p), &t->driver),
6621 "failed to upload printer driver");
6623 torture_assert(tctx,
6624 test_AddPrinterDriver_args_level_3(tctx, b, server_name_slash, &t->driver.info8, 0, false),
6625 "failed to add driver");
6627 t->added_driver = true;
6628 t->have_driver = true;
6630 try_run:
6631 ret = test_add_printer_args_with_driver(tctx, p, t);
6633 if (t->added_driver) {
6634 torture_assert(tctx,
6635 remove_printer_driver(tctx, dcerpc_server_name(p), &t->driver),
6636 "failed to remove printer driver");
6639 return ret;
6642 static bool test_add_printer(struct torture_context *tctx,
6643 struct dcerpc_pipe *p,
6644 void *private_data)
6646 struct torture_printer_context *t =
6647 (struct torture_printer_context *)talloc_get_type_abort(private_data, struct torture_printer_context);
6649 t->ex = false;
6650 t->wellknown = false;
6651 t->info2.printername = TORTURE_PRINTER;
6653 return test_add_printer_args(tctx, p, t);
6656 static bool test_add_printer_wellknown(struct torture_context *tctx,
6657 struct dcerpc_pipe *p,
6658 void *private_data)
6660 struct torture_printer_context *t =
6661 (struct torture_printer_context *)talloc_get_type_abort(private_data, struct torture_printer_context);
6663 t->ex = false;
6664 t->wellknown = true;
6665 t->info2.printername = TORTURE_WELLKNOWN_PRINTER;
6666 t->devmode = NULL;
6668 return test_add_printer_args(tctx, p, t);
6671 static bool test_add_printer_ex(struct torture_context *tctx,
6672 struct dcerpc_pipe *p,
6673 void *private_data)
6675 struct torture_printer_context *t =
6676 (struct torture_printer_context *)talloc_get_type_abort(private_data, struct torture_printer_context);
6678 t->ex = true;
6679 t->wellknown = false;
6680 t->info2.printername = TORTURE_PRINTER_EX;
6681 t->devmode = NULL;
6683 return test_add_printer_args(tctx, p, t);
6686 static bool test_add_printer_ex_wellknown(struct torture_context *tctx,
6687 struct dcerpc_pipe *p,
6688 void *private_data)
6690 struct torture_printer_context *t =
6691 (struct torture_printer_context *)talloc_get_type_abort(private_data, struct torture_printer_context);
6693 t->ex = true;
6694 t->wellknown = true;
6695 t->info2.printername = TORTURE_WELLKNOWN_PRINTER_EX;
6696 t->devmode = NULL;
6698 return test_add_printer_args(tctx, p, t);
6701 static struct spoolss_DeviceMode *torture_devicemode(TALLOC_CTX *mem_ctx,
6702 const char *devicename)
6704 struct spoolss_DeviceMode *r;
6706 r = talloc_zero(mem_ctx, struct spoolss_DeviceMode);
6707 if (r == NULL) {
6708 return NULL;
6711 r->devicename = talloc_strdup(r, devicename);
6712 r->specversion = DMSPEC_NT4_AND_ABOVE;
6713 r->driverversion = 0x0600;
6714 r->size = 0x00dc;
6715 r->__driverextra_length = 0;
6716 r->fields = DEVMODE_FORMNAME |
6717 DEVMODE_TTOPTION |
6718 DEVMODE_PRINTQUALITY |
6719 DEVMODE_DEFAULTSOURCE |
6720 DEVMODE_COPIES |
6721 DEVMODE_SCALE |
6722 DEVMODE_PAPERSIZE |
6723 DEVMODE_ORIENTATION;
6724 r->orientation = DMORIENT_PORTRAIT;
6725 r->papersize = DMPAPER_LETTER;
6726 r->paperlength = 0;
6727 r->paperwidth = 0;
6728 r->scale = 100;
6729 r->copies = 55;
6730 r->defaultsource = DMBIN_FORMSOURCE;
6731 r->printquality = DMRES_HIGH;
6732 r->color = DMRES_MONOCHROME;
6733 r->duplex = DMDUP_SIMPLEX;
6734 r->yresolution = 0;
6735 r->ttoption = DMTT_SUBDEV;
6736 r->collate = DMCOLLATE_FALSE;
6737 r->formname = talloc_strdup(r, "Letter");
6739 return r;
6742 static bool test_add_printer_with_devmode(struct torture_context *tctx,
6743 struct dcerpc_pipe *p,
6744 void *private_data)
6746 struct torture_printer_context *t =
6747 (struct torture_printer_context *)talloc_get_type_abort(private_data, struct torture_printer_context);
6749 t->ex = true;
6750 t->wellknown = false;
6751 t->info2.printername = TORTURE_PRINTER_EX;
6752 t->devmode = torture_devicemode(t, TORTURE_PRINTER_EX);
6754 return test_add_printer_args(tctx, p, t);
6757 static bool test_architecture_buffer(struct torture_context *tctx,
6758 struct dcerpc_pipe *p)
6760 struct spoolss_OpenPrinterEx r;
6761 struct spoolss_UserLevel1 u1;
6762 struct policy_handle handle;
6763 uint32_t architectures[] = {
6764 PROCESSOR_ARCHITECTURE_INTEL,
6765 PROCESSOR_ARCHITECTURE_IA64,
6766 PROCESSOR_ARCHITECTURE_AMD64
6768 uint32_t needed[3];
6769 int i;
6770 struct dcerpc_binding_handle *b = p->binding_handle;
6772 for (i=0; i < ARRAY_SIZE(architectures); i++) {
6774 torture_comment(tctx, "Testing OpenPrinterEx with architecture %d\n", architectures[i]);
6776 u1.size = 0;
6777 u1.client = NULL;
6778 u1.user = NULL;
6779 u1.build = 0;
6780 u1.major = 3;
6781 u1.minor = 0;
6782 u1.processor = architectures[i];
6784 r.in.printername = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
6785 r.in.datatype = NULL;
6786 r.in.devmode_ctr.devmode= NULL;
6787 r.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
6788 r.in.level = 1;
6789 r.in.userlevel.level1 = &u1;
6790 r.out.handle = &handle;
6792 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_OpenPrinterEx_r(b, tctx, &r), "");
6793 torture_assert_werr_ok(tctx, r.out.result, "");
6796 struct spoolss_EnumPrinters e;
6797 uint32_t count;
6798 union spoolss_PrinterInfo *info;
6800 e.in.flags = PRINTER_ENUM_LOCAL;
6801 e.in.server = NULL;
6802 e.in.level = 2;
6803 e.in.buffer = NULL;
6804 e.in.offered = 0;
6805 e.out.count = &count;
6806 e.out.info = &info;
6807 e.out.needed = &needed[i];
6809 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_EnumPrinters_r(b, tctx, &e), "");
6810 #if 0
6811 torture_comment(tctx, "needed was %d\n", needed[i]);
6812 #endif
6815 torture_assert(tctx, test_ClosePrinter(tctx, b, &handle), "");
6818 for (i=1; i < ARRAY_SIZE(architectures); i++) {
6819 if (needed[i-1] != needed[i]) {
6820 torture_fail(tctx,
6821 talloc_asprintf(tctx, "needed size %d for architecture %d != needed size %d for architecture %d\n",
6822 needed[i-1], architectures[i-1], needed[i], architectures[i]));
6826 return true;
6829 bool torture_rpc_spoolss(struct torture_context *torture)
6831 NTSTATUS status;
6832 struct dcerpc_pipe *p;
6833 struct dcerpc_binding_handle *b;
6834 bool ret = true;
6835 struct test_spoolss_context *ctx;
6836 const char *environment = SPOOLSS_ARCHITECTURE_NT_X86;
6838 status = torture_rpc_connection(torture, &p, &ndr_table_spoolss);
6839 if (!NT_STATUS_IS_OK(status)) {
6840 return false;
6842 b = p->binding_handle;
6844 ctx = talloc_zero(torture, struct test_spoolss_context);
6846 ret &= test_OpenPrinter_server(torture, p, &ctx->server_handle);
6847 ret &= test_GetPrinterData_list(torture, p, &ctx->server_handle, &environment);
6848 ret &= test_EnumForms_all(torture, b, &ctx->server_handle, true);
6849 ret &= test_Forms(torture, b, &ctx->server_handle, true, NULL, NULL, NULL);
6850 ret &= test_Forms_winreg(torture, b, &ctx->server_handle, true, NULL);
6851 ret &= test_EnumPorts(torture, b, ctx);
6852 ret &= test_GetPrinterDriverDirectory(torture, p, environment);
6853 ret &= test_GetPrintProcessorDirectory(torture, p, environment);
6854 ret &= test_EnumPrinterDrivers(torture, p, ctx, environment);
6855 ret &= test_EnumPrinterDrivers(torture, p, ctx, SPOOLSS_ARCHITECTURE_ALL);
6856 ret &= test_EnumMonitors(torture, b, ctx);
6857 ret &= test_EnumPrintProcessors(torture, b, ctx, environment);
6858 ret &= test_EnumPrintProcDataTypes(torture, b);
6859 ret &= test_EnumPrinters(torture, b, ctx);
6860 ret &= test_OpenPrinter_badname_list(torture, b, dcerpc_server_name(p));
6862 ret &= test_AddPort(torture, p);
6863 ret &= test_EnumPorts_old(torture, p);
6864 ret &= test_EnumPrinters_old(torture, p, environment);
6865 ret &= test_EnumPrinterDrivers_old(torture, p, environment);
6866 ret &= test_architecture_buffer(torture, p);
6868 return ret;
6871 struct torture_suite *torture_rpc_spoolss_printer(TALLOC_CTX *mem_ctx)
6873 struct torture_suite *suite = torture_suite_create(mem_ctx, "SPOOLSS-PRINTER");
6875 struct torture_rpc_tcase *tcase = torture_suite_add_rpc_iface_tcase(suite,
6876 "printer", &ndr_table_spoolss);
6878 struct torture_printer_context *t;
6880 t = talloc_zero(mem_ctx, struct torture_printer_context);
6882 t->driver.info8.version = SPOOLSS_DRIVER_VERSION_200X;
6883 t->driver.info8.driver_name = TORTURE_DRIVER;
6884 t->driver.info8.driver_path = "pscript5.dll";
6885 t->driver.info8.data_file = "cups6.ppd";
6886 t->driver.info8.config_file = "ps5ui.dll";
6887 t->driver.info8.help_file = "pscript.hlp";
6888 t->driver.info8.default_datatype = "RAW";
6889 t->driver.info8.dependent_files = talloc_zero(t, struct spoolss_StringArray);
6890 t->driver.info8.dependent_files->string = talloc_zero_array(t, const char *, 8 + 1);
6891 t->driver.info8.dependent_files->string[0] = "pscript5.dll";
6892 t->driver.info8.dependent_files->string[1] = "cups6.ppd";
6893 t->driver.info8.dependent_files->string[2] = "ps5ui.dll";
6894 t->driver.info8.dependent_files->string[3] = "pscript.hlp";
6895 t->driver.info8.dependent_files->string[4] = "pscript.ntf";
6896 t->driver.info8.dependent_files->string[5] = "cups6.ini";
6897 t->driver.info8.dependent_files->string[6] = "cupsps6.dll";
6898 t->driver.info8.dependent_files->string[7] = "cupsui6.dll";
6900 t->driver.local.driver_directory= "/usr/share/cups/drivers";
6902 t->info2.drivername = "Microsoft XPS Document Writer";
6903 t->info2.portname = "LPT1:";
6905 torture_rpc_tcase_add_test_ex(tcase, "add_printer", test_add_printer, t);
6906 torture_rpc_tcase_add_test_ex(tcase, "add_printer_wellknown", test_add_printer_wellknown, t);
6907 torture_rpc_tcase_add_test_ex(tcase, "add_printer_ex", test_add_printer_ex, t);
6908 torture_rpc_tcase_add_test_ex(tcase, "add_printer_ex_wellknown", test_add_printer_ex_wellknown, t);
6910 torture_rpc_tcase_add_test_ex(tcase, "add_printer_with_devmode", test_add_printer_with_devmode, t);
6912 return suite;
6915 static bool test_GetPrinterDriverDirectory_getdir(struct torture_context *tctx,
6916 struct dcerpc_binding_handle *b,
6917 const char *server,
6918 const char *environment,
6919 const char **dir_p)
6921 struct spoolss_GetPrinterDriverDirectory r;
6922 uint32_t needed;
6924 r.in.server = server;
6925 r.in.environment = environment;
6926 r.in.level = 1;
6927 r.in.buffer = NULL;
6928 r.in.offered = 0;
6929 r.out.needed = &needed;
6931 torture_assert_ntstatus_ok(tctx,
6932 dcerpc_spoolss_GetPrinterDriverDirectory_r(b, tctx, &r),
6933 "failed to query driver directory");
6935 if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
6936 DATA_BLOB blob = data_blob_talloc_zero(tctx, needed);
6937 r.in.buffer = &blob;
6938 r.in.offered = needed;
6940 torture_assert_ntstatus_ok(tctx,
6941 dcerpc_spoolss_GetPrinterDriverDirectory_r(b, tctx, &r),
6942 "failed to query driver directory");
6945 torture_assert_werr_ok(tctx, r.out.result,
6946 "failed to query driver directory");
6948 if (dir_p) {
6949 *dir_p = r.out.info->info1.directory_name;
6952 return true;
6955 static const char *get_driver_from_info(struct spoolss_AddDriverInfoCtr *info_ctr)
6957 if (info_ctr == NULL) {
6958 return NULL;
6961 switch (info_ctr->level) {
6962 case 1:
6963 return info_ctr->info.info1->driver_name;
6964 case 2:
6965 return info_ctr->info.info2->driver_name;
6966 case 3:
6967 return info_ctr->info.info3->driver_name;
6968 case 4:
6969 return info_ctr->info.info4->driver_name;
6970 case 6:
6971 return info_ctr->info.info6->driver_name;
6972 case 8:
6973 return info_ctr->info.info8->driver_name;
6974 default:
6975 return NULL;
6979 static const char *get_environment_from_info(struct spoolss_AddDriverInfoCtr *info_ctr)
6981 if (info_ctr == NULL) {
6982 return NULL;
6985 switch (info_ctr->level) {
6986 case 2:
6987 return info_ctr->info.info2->architecture;
6988 case 3:
6989 return info_ctr->info.info3->architecture;
6990 case 4:
6991 return info_ctr->info.info4->architecture;
6992 case 6:
6993 return info_ctr->info.info6->architecture;
6994 case 8:
6995 return info_ctr->info.info8->architecture;
6996 default:
6997 return NULL;
7002 static bool test_AddPrinterDriver_exp(struct torture_context *tctx,
7003 struct dcerpc_binding_handle *b,
7004 const char *servername,
7005 struct spoolss_AddDriverInfoCtr *info_ctr,
7006 WERROR expected_result)
7008 struct spoolss_AddPrinterDriver r;
7009 const char *drivername = get_driver_from_info(info_ctr);
7010 const char *environment = get_environment_from_info(info_ctr);
7012 r.in.servername = servername;
7013 r.in.info_ctr = info_ctr;
7015 torture_comment(tctx, "Testing AddPrinterDriver(%s) level: %d, environment: '%s'\n",
7016 drivername, info_ctr->level, environment);
7018 torture_assert_ntstatus_ok(tctx,
7019 dcerpc_spoolss_AddPrinterDriver_r(b, tctx, &r),
7020 "spoolss_AddPrinterDriver failed");
7021 torture_assert_werr_equal(tctx, r.out.result, expected_result,
7022 "spoolss_AddPrinterDriver failed with unexpected result");
7024 return true;
7028 static bool test_AddPrinterDriverEx_exp(struct torture_context *tctx,
7029 struct dcerpc_binding_handle *b,
7030 const char *servername,
7031 struct spoolss_AddDriverInfoCtr *info_ctr,
7032 uint32_t flags,
7033 WERROR expected_result)
7035 struct spoolss_AddPrinterDriverEx r;
7036 const char *drivername = get_driver_from_info(info_ctr);
7037 const char *environment = get_environment_from_info(info_ctr);
7039 r.in.servername = servername;
7040 r.in.info_ctr = info_ctr;
7041 r.in.flags = flags;
7043 torture_comment(tctx, "Testing AddPrinterDriverEx(%s) level: %d, environment: '%s'\n",
7044 drivername, info_ctr->level, environment);
7046 torture_assert_ntstatus_ok(tctx,
7047 dcerpc_spoolss_AddPrinterDriverEx_r(b, tctx, &r),
7048 "AddPrinterDriverEx failed");
7049 torture_assert_werr_equal(tctx, r.out.result, expected_result,
7050 "AddPrinterDriverEx failed with unexpected result");
7052 return true;
7055 static bool test_AddPrinterDriver_args_level_1(struct torture_context *tctx,
7056 struct dcerpc_binding_handle *b,
7057 const char *server_name,
7058 struct spoolss_AddDriverInfo8 *r,
7059 uint32_t flags,
7060 bool ex)
7062 struct spoolss_AddDriverInfoCtr info_ctr;
7063 struct spoolss_AddDriverInfo1 info1;
7065 ZERO_STRUCT(info1);
7067 info_ctr.level = 1;
7068 info_ctr.info.info1 = &info1;
7070 if (ex) {
7071 torture_assert(tctx,
7072 test_AddPrinterDriverEx_exp(tctx, b, server_name, &info_ctr, flags, WERR_UNKNOWN_LEVEL),
7073 "failed to test AddPrinterDriverEx level 1");
7074 } else {
7075 torture_assert(tctx,
7076 test_AddPrinterDriver_exp(tctx, b, server_name, &info_ctr, WERR_UNKNOWN_LEVEL),
7077 "failed to test AddPrinterDriver level 1");
7080 info1.driver_name = r->driver_name;
7082 if (ex) {
7083 torture_assert(tctx,
7084 test_AddPrinterDriverEx_exp(tctx, b, server_name, &info_ctr, flags, WERR_UNKNOWN_LEVEL),
7085 "failed to test AddPrinterDriverEx level 1");
7086 } else {
7087 torture_assert(tctx,
7088 test_AddPrinterDriver_exp(tctx, b, server_name, &info_ctr, WERR_UNKNOWN_LEVEL),
7089 "failed to test AddPrinterDriver level 1");
7092 return true;
7095 static bool test_AddPrinterDriver_args_level_2(struct torture_context *tctx,
7096 struct dcerpc_binding_handle *b,
7097 const char *server_name,
7098 struct spoolss_AddDriverInfo8 *r,
7099 uint32_t flags,
7100 bool ex)
7102 struct spoolss_AddDriverInfoCtr info_ctr;
7103 struct spoolss_AddDriverInfo2 info2;
7105 ZERO_STRUCT(info2);
7107 info_ctr.level = 2;
7108 info_ctr.info.info2 = &info2;
7110 if (ex) {
7111 torture_assert(tctx,
7112 test_AddPrinterDriverEx_exp(tctx, b, server_name, &info_ctr, flags, WERR_INVALID_PARAM),
7113 "failed to test AddPrinterDriverEx level 2");
7114 } else {
7115 torture_assert(tctx,
7116 test_AddPrinterDriver_exp(tctx, b, server_name, &info_ctr, WERR_INVALID_PARAM),
7117 "failed to test AddPrinterDriver level 2");
7120 info2.driver_name = r->driver_name;
7122 if (ex) {
7123 torture_assert(tctx,
7124 test_AddPrinterDriverEx_exp(tctx, b, server_name, &info_ctr, flags, WERR_INVALID_PARAM),
7125 "failed to test AddPrinterDriverEx level 2");
7126 } else {
7127 torture_assert(tctx,
7128 test_AddPrinterDriver_exp(tctx, b, server_name, &info_ctr, WERR_INVALID_PARAM),
7129 "failed to test AddPrinterDriver level 2");
7132 info2.version = r->version;
7134 if (ex) {
7135 torture_assert(tctx,
7136 test_AddPrinterDriverEx_exp(tctx, b, server_name, &info_ctr, flags, WERR_INVALID_PARAM),
7137 "failed to test AddPrinterDriverEx level 2");
7138 } else {
7139 torture_assert(tctx,
7140 test_AddPrinterDriver_exp(tctx, b, server_name, &info_ctr, WERR_INVALID_PARAM),
7141 "failed to test AddPrinterDriver level 2");
7144 info2.architecture = r->architecture;
7146 if (ex) {
7147 torture_assert(tctx,
7148 test_AddPrinterDriverEx_exp(tctx, b, server_name, &info_ctr, flags, WERR_INVALID_PARAM),
7149 "failed to test AddPrinterDriverEx level 2");
7150 } else {
7151 torture_assert(tctx,
7152 test_AddPrinterDriver_exp(tctx, b, server_name, &info_ctr, WERR_INVALID_PARAM),
7153 "failed to test AddPrinterDriver level 2");
7156 info2.driver_path = r->driver_path;
7158 if (ex) {
7159 torture_assert(tctx,
7160 test_AddPrinterDriverEx_exp(tctx, b, server_name, &info_ctr, flags, WERR_INVALID_PARAM),
7161 "failed to test AddPrinterDriverEx level 2");
7162 } else {
7163 torture_assert(tctx,
7164 test_AddPrinterDriver_exp(tctx, b, server_name, &info_ctr, WERR_INVALID_PARAM),
7165 "failed to test AddPrinterDriver level 2");
7168 info2.data_file = r->data_file;
7170 if (ex) {
7171 torture_assert(tctx,
7172 test_AddPrinterDriverEx_exp(tctx, b, server_name, &info_ctr, flags, WERR_INVALID_PARAM),
7173 "failed to test AddPrinterDriverEx level 2");
7174 } else {
7175 torture_assert(tctx,
7176 test_AddPrinterDriver_exp(tctx, b, server_name, &info_ctr, WERR_INVALID_PARAM),
7177 "failed to test AddPrinterDriver level 2");
7180 info2.config_file = r->config_file;
7182 if (ex) {
7183 torture_assert(tctx,
7184 test_AddPrinterDriverEx_exp(tctx, b, server_name, &info_ctr, 0, WERR_INVALID_PARAM),
7185 "failed to test AddPrinterDriverEx");
7188 if (ex) {
7189 torture_assert(tctx,
7190 test_AddPrinterDriverEx_exp(tctx, b, server_name, &info_ctr, flags, WERR_OK),
7191 "failed to test AddPrinterDriverEx level 2");
7192 } else {
7193 torture_assert(tctx,
7194 test_AddPrinterDriver_exp(tctx, b, server_name, &info_ctr, WERR_OK),
7195 "failed to test AddPrinterDriver level 2");
7198 torture_assert(tctx,
7199 test_EnumPrinterDrivers_findone(tctx, b, server_name, r->architecture, 2, r->driver_name),
7200 "failed to find added printer driver");
7202 return true;
7205 static bool test_AddPrinterDriver_args_level_3(struct torture_context *tctx,
7206 struct dcerpc_binding_handle *b,
7207 const char *server_name,
7208 struct spoolss_AddDriverInfo8 *r,
7209 uint32_t flags,
7210 bool ex)
7212 struct spoolss_AddDriverInfoCtr info_ctr;
7213 struct spoolss_AddDriverInfo3 info3;
7215 info3.driver_name = r->driver_name;
7216 info3.version = r->version;
7217 info3.architecture = r->architecture;
7218 info3.driver_path = r->driver_path;
7219 info3.data_file = r->data_file;
7220 info3.config_file = r->config_file;
7221 info3.help_file = r->help_file;
7222 info3.monitor_name = r->monitor_name;
7223 info3.default_datatype = r->default_datatype;
7224 info3._ndr_size_dependent_files = r->_ndr_size_dependent_files;
7225 info3.dependent_files = r->dependent_files;
7227 info_ctr.level = 3;
7228 info_ctr.info.info3 = &info3;
7230 if (ex) {
7231 torture_assert(tctx,
7232 test_AddPrinterDriverEx_exp(tctx, b, server_name, &info_ctr, flags, WERR_OK),
7233 "failed to test AddPrinterDriverEx level 3");
7234 } else {
7235 torture_assert(tctx,
7236 test_AddPrinterDriver_exp(tctx, b, server_name, &info_ctr, WERR_OK),
7237 "failed to test AddPrinterDriver level 3");
7240 torture_assert(tctx,
7241 test_EnumPrinterDrivers_findone(tctx, b, server_name, r->architecture, 3, r->driver_name),
7242 "failed to find added printer driver");
7244 return true;
7247 static bool test_AddPrinterDriver_args_level_4(struct torture_context *tctx,
7248 struct dcerpc_binding_handle *b,
7249 const char *server_name,
7250 struct spoolss_AddDriverInfo8 *r,
7251 uint32_t flags,
7252 bool ex)
7254 struct spoolss_AddDriverInfoCtr info_ctr;
7255 struct spoolss_AddDriverInfo4 info4;
7257 info4.version = r->version;
7258 info4.driver_name = r->driver_name;
7259 info4.architecture = r->architecture;
7260 info4.driver_path = r->driver_path;
7261 info4.data_file = r->data_file;
7262 info4.config_file = r->config_file;
7263 info4.help_file = r->help_file;
7264 info4.monitor_name = r->monitor_name;
7265 info4.default_datatype = r->default_datatype;
7266 info4._ndr_size_dependent_files = r->_ndr_size_dependent_files;
7267 info4.dependent_files = r->dependent_files;
7268 info4._ndr_size_previous_names = r->_ndr_size_previous_names;
7269 info4.previous_names = r->previous_names;
7271 info_ctr.level = 4;
7272 info_ctr.info.info4 = &info4;
7274 if (ex) {
7275 torture_assert(tctx,
7276 test_AddPrinterDriverEx_exp(tctx, b, server_name, &info_ctr, flags, WERR_OK),
7277 "failed to test AddPrinterDriverEx level 4");
7278 } else {
7279 torture_assert(tctx,
7280 test_AddPrinterDriver_exp(tctx, b, server_name, &info_ctr, WERR_OK),
7281 "failed to test AddPrinterDriver level 4");
7284 torture_assert(tctx,
7285 test_EnumPrinterDrivers_findone(tctx, b, server_name, r->architecture, 4, r->driver_name),
7286 "failed to find added printer driver");
7288 return true;
7291 static bool test_AddPrinterDriver_args_level_6(struct torture_context *tctx,
7292 struct dcerpc_binding_handle *b,
7293 const char *server_name,
7294 struct spoolss_AddDriverInfo8 *r,
7295 uint32_t flags,
7296 bool ex)
7298 struct spoolss_AddDriverInfoCtr info_ctr;
7299 struct spoolss_AddDriverInfo6 info6;
7301 info6.version = r->version;
7302 info6.driver_name = r->driver_name;
7303 info6.architecture = r->architecture;
7304 info6.driver_path = r->driver_path;
7305 info6.data_file = r->data_file;
7306 info6.config_file = r->config_file;
7307 info6.help_file = r->help_file;
7308 info6.monitor_name = r->monitor_name;
7309 info6.default_datatype = r->default_datatype;
7310 info6._ndr_size_dependent_files = r->_ndr_size_dependent_files;
7311 info6.dependent_files = r->dependent_files;
7312 info6._ndr_size_previous_names = r->_ndr_size_previous_names;
7313 info6.previous_names = r->previous_names;
7314 info6.driver_date = r->driver_date;
7315 info6.driver_version = r->driver_version;
7316 info6.manufacturer_name = r->manufacturer_name;
7317 info6.manufacturer_url = r->manufacturer_url;
7318 info6.hardware_id = r->hardware_id;
7319 info6.provider = r->provider;
7321 info_ctr.level = 6;
7322 info_ctr.info.info6 = &info6;
7324 if (ex) {
7325 torture_assert(tctx,
7326 test_AddPrinterDriverEx_exp(tctx, b, server_name, &info_ctr, flags, WERR_OK),
7327 "failed to test AddPrinterDriverEx level 6");
7328 } else {
7329 torture_assert(tctx,
7330 test_AddPrinterDriver_exp(tctx, b, server_name, &info_ctr, WERR_UNKNOWN_LEVEL),
7331 "failed to test AddPrinterDriver level 6");
7334 /* spoolss_AddPrinterDriver does not deal with level 6 or 8 - gd */
7336 if (!ex) {
7337 return true;
7340 torture_assert(tctx,
7341 test_EnumPrinterDrivers_findone(tctx, b, server_name, r->architecture, 6, r->driver_name),
7342 "failed to find added printer driver");
7344 return true;
7347 static bool test_AddPrinterDriver_args_level_8(struct torture_context *tctx,
7348 struct dcerpc_binding_handle *b,
7349 const char *server_name,
7350 struct spoolss_AddDriverInfo8 *r,
7351 uint32_t flags,
7352 bool ex)
7354 struct spoolss_AddDriverInfoCtr info_ctr;
7356 info_ctr.level = 8;
7357 info_ctr.info.info8 = r;
7359 if (ex) {
7360 torture_assert(tctx,
7361 test_AddPrinterDriverEx_exp(tctx, b, server_name, &info_ctr, flags, WERR_OK),
7362 "failed to test AddPrinterDriverEx level 8");
7363 } else {
7364 torture_assert(tctx,
7365 test_AddPrinterDriver_exp(tctx, b, server_name, &info_ctr, WERR_UNKNOWN_LEVEL),
7366 "failed to test AddPrinterDriver level 8");
7369 /* spoolss_AddPrinterDriver does not deal with level 6 or 8 - gd */
7371 if (!ex) {
7372 return true;
7375 torture_assert(tctx,
7376 test_EnumPrinterDrivers_findone(tctx, b, server_name, r->architecture, 8, r->driver_name),
7377 "failed to find added printer driver");
7379 return true;
7382 static bool test_DeletePrinterDriver_exp(struct torture_context *tctx,
7383 struct dcerpc_binding_handle *b,
7384 const char *server,
7385 const char *driver,
7386 const char *environment,
7387 WERROR expected_result)
7389 struct spoolss_DeletePrinterDriver r;
7391 r.in.server = server;
7392 r.in.architecture = environment;
7393 r.in.driver = driver;
7395 torture_comment(tctx, "Testing DeletePrinterDriver(%s)\n", driver);
7397 torture_assert_ntstatus_ok(tctx,
7398 dcerpc_spoolss_DeletePrinterDriver_r(b, tctx, &r),
7399 "DeletePrinterDriver failed");
7400 torture_assert_werr_equal(tctx, r.out.result, expected_result,
7401 "DeletePrinterDriver failed with unexpected result");
7403 return true;
7406 static bool test_DeletePrinterDriverEx_exp(struct torture_context *tctx,
7407 struct dcerpc_binding_handle *b,
7408 const char *server,
7409 const char *driver,
7410 const char *environment,
7411 uint32_t delete_flags,
7412 uint32_t version,
7413 WERROR expected_result)
7415 struct spoolss_DeletePrinterDriverEx r;
7417 r.in.server = server;
7418 r.in.architecture = environment;
7419 r.in.driver = driver;
7420 r.in.delete_flags = delete_flags;
7421 r.in.version = version;
7423 torture_comment(tctx, "Testing DeletePrinterDriverEx(%s)\n", driver);
7425 torture_assert_ntstatus_ok(tctx,
7426 dcerpc_spoolss_DeletePrinterDriverEx_r(b, tctx, &r),
7427 "DeletePrinterDriverEx failed");
7428 torture_assert_werr_equal(tctx, r.out.result, expected_result,
7429 "DeletePrinterDriverEx failed with unexpected result");
7431 return true;
7434 static bool test_DeletePrinterDriver(struct torture_context *tctx,
7435 struct dcerpc_binding_handle *b,
7436 const char *server_name,
7437 const char *driver,
7438 const char *environment)
7440 torture_assert(tctx,
7441 test_DeletePrinterDriver_exp(tctx, b, server_name, driver, "FOOBAR", WERR_INVALID_ENVIRONMENT),
7442 "failed to delete driver");
7444 torture_assert(tctx,
7445 test_DeletePrinterDriver_exp(tctx, b, server_name, driver, environment, WERR_OK),
7446 "failed to delete driver");
7448 if (test_EnumPrinterDrivers_findone(tctx, b, server_name, environment, 1, driver)) {
7449 torture_fail(tctx, "deleted driver still enumerated");
7452 torture_assert(tctx,
7453 test_DeletePrinterDriver_exp(tctx, b, server_name, driver, environment, WERR_UNKNOWN_PRINTER_DRIVER),
7454 "2nd delete failed");
7456 return true;
7459 static bool test_DeletePrinterDriverEx(struct torture_context *tctx,
7460 struct dcerpc_binding_handle *b,
7461 const char *server_name,
7462 const char *driver,
7463 const char *environment,
7464 uint32_t delete_flags,
7465 uint32_t version)
7467 torture_assert(tctx,
7468 test_DeletePrinterDriverEx_exp(tctx, b, server_name, driver, "FOOBAR", delete_flags, version, WERR_INVALID_ENVIRONMENT),
7469 "failed to delete driver");
7471 torture_assert(tctx,
7472 test_DeletePrinterDriverEx_exp(tctx, b, server_name, driver, environment, delete_flags, version, WERR_OK),
7473 "failed to delete driver");
7475 if (test_EnumPrinterDrivers_findone(tctx, b, server_name, environment, 1, driver)) {
7476 torture_fail(tctx, "deleted driver still enumerated");
7479 torture_assert(tctx,
7480 test_DeletePrinterDriverEx_exp(tctx, b, server_name, driver, environment, delete_flags, version, WERR_UNKNOWN_PRINTER_DRIVER),
7481 "2nd delete failed");
7483 return true;
7486 static bool test_PrinterDriver_args(struct torture_context *tctx,
7487 struct dcerpc_binding_handle *b,
7488 const char *server_name,
7489 uint32_t level,
7490 struct spoolss_AddDriverInfo8 *r,
7491 uint32_t add_flags,
7492 uint32_t delete_flags,
7493 uint32_t delete_version,
7494 bool ex)
7496 bool ret = true;
7498 switch (level) {
7499 case 1:
7500 ret = test_AddPrinterDriver_args_level_1(tctx, b, server_name, r, add_flags, ex);
7501 break;
7502 case 2:
7503 ret = test_AddPrinterDriver_args_level_2(tctx, b, server_name, r, add_flags, ex);
7504 break;
7505 case 3:
7506 ret = test_AddPrinterDriver_args_level_3(tctx, b, server_name, r, add_flags, ex);
7507 break;
7508 case 4:
7509 ret = test_AddPrinterDriver_args_level_4(tctx, b, server_name, r, add_flags, ex);
7510 break;
7511 case 6:
7512 ret = test_AddPrinterDriver_args_level_6(tctx, b, server_name, r, add_flags, ex);
7513 break;
7514 case 8:
7515 ret = test_AddPrinterDriver_args_level_8(tctx, b, server_name, r, add_flags, ex);
7516 break;
7517 default:
7518 return false;
7521 if (ret == false) {
7522 return ret;
7525 if (level == 1) {
7526 return ret;
7529 /* spoolss_AddPrinterDriver does not deal with level 6 or 8 - gd */
7531 if (!ex && (level == 6 || level == 8)) {
7532 return ret;
7535 if (ex) {
7536 return test_DeletePrinterDriverEx(tctx, b, server_name, r->driver_name, r->architecture, delete_flags, r->version);
7537 } else {
7538 return test_DeletePrinterDriver(tctx, b, server_name, r->driver_name, r->architecture);
7542 static bool fillup_printserver_info(struct torture_context *tctx,
7543 struct dcerpc_pipe *p,
7544 struct torture_driver_context *d)
7546 struct policy_handle server_handle;
7547 struct dcerpc_binding_handle *b = p->binding_handle;
7548 const char *server_name_slash = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
7550 torture_assert(tctx,
7551 test_OpenPrinter_server(tctx, p, &server_handle),
7552 "failed to open printserver");
7553 torture_assert(tctx,
7554 test_get_environment(tctx, b, &server_handle, &d->remote.environment),
7555 "failed to get environment");
7556 torture_assert(tctx,
7557 test_ClosePrinter(tctx, b, &server_handle),
7558 "failed to close printserver");
7560 torture_assert(tctx,
7561 test_GetPrinterDriverDirectory_getdir(tctx, b, server_name_slash,
7562 d->local.environment ? d->local.environment : d->remote.environment,
7563 &d->remote.driver_directory),
7564 "failed to get driver directory");
7566 return true;
7569 static const char *driver_directory_dir(const char *driver_directory)
7571 char *p;
7573 p = strrchr(driver_directory, '\\');
7574 if (p) {
7575 return p+1;
7578 return NULL;
7581 static const char *driver_directory_share(struct torture_context *tctx,
7582 const char *driver_directory)
7584 const char *p;
7585 char *tok;
7587 if (driver_directory[0] == '\\' && driver_directory[1] == '\\') {
7588 driver_directory += 2;
7591 p = talloc_strdup(tctx, driver_directory);
7593 torture_assert(tctx,
7594 next_token_talloc(tctx, &p, &tok, "\\"),
7595 "cannot explode uri");
7596 torture_assert(tctx,
7597 next_token_talloc(tctx, &p, &tok, "\\"),
7598 "cannot explode uri");
7600 return tok;
7603 static bool upload_printer_driver_file(struct torture_context *tctx,
7604 struct smbcli_state *cli,
7605 struct torture_driver_context *d,
7606 const char *file_name)
7608 XFILE *f;
7609 int fnum;
7610 uint8_t *buf;
7611 int maxwrite = 64512;
7612 off_t nread = 0;
7613 size_t start = 0;
7614 const char *remote_dir = driver_directory_dir(d->remote.driver_directory);
7615 const char *local_name = talloc_asprintf(tctx, "%s/%s", d->local.driver_directory, file_name);
7616 const char *remote_name = talloc_asprintf(tctx, "%s\\%s", remote_dir, file_name);
7618 if (!file_name) {
7619 return true;
7622 torture_comment(tctx, "Uploading %s to %s\n", local_name, remote_name);
7624 fnum = smbcli_open(cli->tree, remote_name, O_RDWR|O_CREAT|O_TRUNC, DENY_NONE);
7625 if (fnum == -1) {
7626 torture_fail(tctx, talloc_asprintf(tctx, "failed to open remote file: %s\n", remote_name));
7629 f = x_fopen(local_name, O_RDONLY, 0);
7630 if (f == NULL) {
7631 torture_fail(tctx, talloc_asprintf(tctx, "failed to open local file: %s\n", local_name));
7634 buf = talloc_array(tctx, uint8_t, maxwrite);
7635 if (!buf) {
7636 return false;
7639 while (!x_feof(f)) {
7640 int n = maxwrite;
7641 int ret;
7643 if ((n = x_fread(buf, 1, n, f)) < 1) {
7644 if((n == 0) && x_feof(f))
7645 break; /* Empty local file. */
7647 torture_warning(tctx,
7648 "failed to read file: %s\n", strerror(errno));
7649 break;
7652 ret = smbcli_write(cli->tree, fnum, 0, buf, nread + start, n);
7654 if (n != ret) {
7655 torture_warning(tctx,
7656 "failed to write file: %s\n", smbcli_errstr(cli->tree));
7657 break;
7660 nread += n;
7663 x_fclose(f);
7665 torture_assert_ntstatus_ok(tctx,
7666 smbcli_close(cli->tree, fnum),
7667 "failed to close file");
7669 return true;
7672 static bool connect_printer_driver_share(struct torture_context *tctx,
7673 const char *server_name,
7674 const char *share_name,
7675 struct smbcli_state **cli)
7677 struct smbcli_options smb_options;
7678 struct smbcli_session_options smb_session_options;
7680 torture_comment(tctx, "Connecting printer driver share '%s' on '%s'\n",
7681 share_name, server_name);
7683 lp_smbcli_options(tctx->lp_ctx, &smb_options);
7684 lp_smbcli_session_options(tctx->lp_ctx, &smb_session_options);
7686 torture_assert_ntstatus_ok(tctx,
7687 smbcli_full_connection(tctx, cli, server_name,
7688 lp_smb_ports(tctx->lp_ctx),
7689 share_name, NULL,
7690 lp_socket_options(tctx->lp_ctx),
7691 cmdline_credentials,
7692 lp_resolve_context(tctx->lp_ctx),
7693 tctx->ev,
7694 &smb_options,
7695 &smb_session_options,
7696 lp_gensec_settings(tctx, tctx->lp_ctx)),
7697 "failed to open driver share");
7699 return true;
7702 static bool upload_printer_driver(struct torture_context *tctx,
7703 const char *server_name,
7704 struct torture_driver_context *d)
7706 struct smbcli_state *cli;
7707 const char *share_name = driver_directory_share(tctx, d->remote.driver_directory);
7708 int i;
7710 torture_assert(tctx,
7711 connect_printer_driver_share(tctx, server_name, share_name, &cli),
7712 "failed to connect to driver share");
7714 torture_comment(tctx, "Uploading printer driver files to \\\\%s\\%s\n",
7715 server_name, share_name);
7717 torture_assert(tctx,
7718 upload_printer_driver_file(tctx, cli, d, d->info8.driver_path),
7719 "failed to upload driver_path");
7720 torture_assert(tctx,
7721 upload_printer_driver_file(tctx, cli, d, d->info8.data_file),
7722 "failed to upload data_file");
7723 torture_assert(tctx,
7724 upload_printer_driver_file(tctx, cli, d, d->info8.config_file),
7725 "failed to upload config_file");
7726 torture_assert(tctx,
7727 upload_printer_driver_file(tctx, cli, d, d->info8.help_file),
7728 "failed to upload help_file");
7729 if (d->info8.dependent_files) {
7730 for (i=0; d->info8.dependent_files->string && d->info8.dependent_files->string[i] != NULL; i++) {
7731 torture_assert(tctx,
7732 upload_printer_driver_file(tctx, cli, d, d->info8.dependent_files->string[i]),
7733 "failed to upload dependent_files");
7737 talloc_free(cli);
7739 return true;
7742 static bool remove_printer_driver_file(struct torture_context *tctx,
7743 struct smbcli_state *cli,
7744 struct torture_driver_context *d,
7745 const char *file_name)
7747 const char *remote_name;
7748 const char *remote_dir = driver_directory_dir(d->remote.driver_directory);
7750 if (!file_name) {
7751 return true;
7754 remote_name = talloc_asprintf(tctx, "%s\\%s", remote_dir, file_name);
7756 torture_comment(tctx, "Removing %s\n", remote_name);
7758 torture_assert_ntstatus_ok(tctx,
7759 smbcli_unlink(cli->tree, remote_name),
7760 "failed to unlink");
7762 return true;
7765 static bool remove_printer_driver(struct torture_context *tctx,
7766 const char *server_name,
7767 struct torture_driver_context *d)
7769 struct smbcli_state *cli;
7770 const char *share_name = driver_directory_share(tctx, d->remote.driver_directory);
7771 int i;
7773 torture_assert(tctx,
7774 connect_printer_driver_share(tctx, server_name, share_name, &cli),
7775 "failed to connect to driver share");
7777 torture_comment(tctx, "Removing printer driver files from \\\\%s\\%s\n",
7778 server_name, share_name);
7780 torture_assert(tctx,
7781 remove_printer_driver_file(tctx, cli, d, d->info8.driver_path),
7782 "failed to remove driver_path");
7783 torture_assert(tctx,
7784 remove_printer_driver_file(tctx, cli, d, d->info8.data_file),
7785 "failed to remove data_file");
7786 torture_assert(tctx,
7787 remove_printer_driver_file(tctx, cli, d, d->info8.config_file),
7788 "failed to remove config_file");
7789 torture_assert(tctx,
7790 remove_printer_driver_file(tctx, cli, d, d->info8.help_file),
7791 "failed to remove help_file");
7792 if (d->info8.dependent_files) {
7793 for (i=0; d->info8.dependent_files->string && d->info8.dependent_files->string[i] != NULL; i++) {
7794 if (strequal(d->info8.dependent_files->string[i], d->info8.driver_path) ||
7795 strequal(d->info8.dependent_files->string[i], d->info8.data_file) ||
7796 strequal(d->info8.dependent_files->string[i], d->info8.config_file) ||
7797 strequal(d->info8.dependent_files->string[i], d->info8.help_file)) {
7798 continue;
7800 torture_assert(tctx,
7801 remove_printer_driver_file(tctx, cli, d, d->info8.dependent_files->string[i]),
7802 "failed to remove dependent_files");
7806 talloc_free(cli);
7808 return true;
7812 static bool test_add_driver_arg(struct torture_context *tctx,
7813 struct dcerpc_pipe *p,
7814 struct torture_driver_context *d)
7816 bool ret = true;
7817 struct dcerpc_binding_handle *b = p->binding_handle;
7818 const char *server_name_slash = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
7819 uint32_t levels[] = { 1, 2, 3, 4, 6, 8 };
7820 int i;
7821 struct spoolss_AddDriverInfo8 info8;
7822 uint32_t add_flags = APD_COPY_NEW_FILES;
7823 uint32_t delete_flags = 0;
7825 ZERO_STRUCT(info8);
7827 torture_comment(tctx, "Testing PrinterDriver%s '%s' for environment '%s'\n",
7828 d->ex ? "Ex" : "", d->info8.driver_name, d->local.environment);
7830 torture_assert(tctx,
7831 fillup_printserver_info(tctx, p, d),
7832 "failed to fillup printserver info");
7834 if (!directory_exist(d->local.driver_directory)) {
7835 torture_skip(tctx, "Skipping Printer Driver test as no local driver is available");
7838 torture_assert(tctx,
7839 upload_printer_driver(tctx, dcerpc_server_name(p), d),
7840 "failed to upload printer driver");
7842 info8.version = d->info8.version;
7843 info8.driver_name = d->info8.driver_name;
7844 info8.architecture = d->local.environment;
7845 info8.driver_path = d->info8.driver_path;
7846 info8.data_file = d->info8.data_file;
7847 info8.config_file = d->info8.config_file;
7849 for (i=0; i < ARRAY_SIZE(levels); i++) {
7851 if (torture_setting_bool(tctx, "samba3", false)) {
7852 switch (levels[i]) {
7853 case 2:
7854 case 4:
7855 case 8:
7856 torture_comment(tctx, "skipping level %d against samba\n", levels[i]);
7857 continue;
7858 default:
7859 break;
7863 torture_comment(tctx,
7864 "Testing PrinterDriver%s '%s' add & delete level %d\n",
7865 d->ex ? "Ex" : "", info8.driver_name, levels[i]);
7867 ret &= test_PrinterDriver_args(tctx, b, server_name_slash, levels[i], &info8, add_flags, delete_flags, d->info8.version, d->ex);
7870 info8.driver_path = talloc_asprintf(tctx, "%s\\%s", d->remote.driver_directory, d->info8.driver_path);
7871 info8.data_file = talloc_asprintf(tctx, "%s\\%s", d->remote.driver_directory, d->info8.data_file);
7872 info8.config_file = talloc_asprintf(tctx, "%s\\%s", d->remote.driver_directory, d->info8.config_file);
7874 for (i=0; i < ARRAY_SIZE(levels); i++) {
7876 if (torture_setting_bool(tctx, "samba3", false)) {
7877 switch (levels[i]) {
7878 case 2:
7879 case 4:
7880 case 8:
7881 torture_comment(tctx, "skipping level %d against samba\n", levels[i]);
7882 continue;
7883 default:
7884 break;
7889 torture_comment(tctx,
7890 "Testing PrinterDriver%s '%s' add & delete level %d (full unc paths)\n",
7891 d->ex ? "Ex" : "", info8.driver_name, levels[i]);
7893 ret &= test_PrinterDriver_args(tctx, b, server_name_slash, levels[i], &info8, add_flags, delete_flags, d->info8.version, d->ex);
7896 torture_assert(tctx,
7897 remove_printer_driver(tctx, dcerpc_server_name(p), d),
7898 "failed to remove printer driver");
7900 torture_comment(tctx, "\n");
7902 return ret;
7905 static bool test_add_driver_ex_64(struct torture_context *tctx,
7906 struct dcerpc_pipe *p,
7907 void *private_data)
7909 struct torture_driver_context *d =
7910 (struct torture_driver_context *)talloc_get_type_abort(private_data, struct torture_driver_context);
7912 d->local.environment = talloc_strdup(d, "Windows x64");
7913 d->local.driver_directory = talloc_strdup(d, "/usr/share/cups/drivers/x64");
7914 d->info8.driver_name = TORTURE_DRIVER_EX;
7915 d->ex = true;
7917 return test_add_driver_arg(tctx, p, d);
7920 static bool test_add_driver_ex_32(struct torture_context *tctx,
7921 struct dcerpc_pipe *p,
7922 void *private_data)
7924 struct torture_driver_context *d =
7925 (struct torture_driver_context *)talloc_get_type_abort(private_data, struct torture_driver_context);
7927 d->local.environment = talloc_strdup(d, "Windows NT x86");
7928 d->local.driver_directory = talloc_strdup(d, "/usr/share/cups/drivers/i386");
7929 d->info8.driver_name = TORTURE_DRIVER_EX;
7930 d->ex = true;
7932 return test_add_driver_arg(tctx, p, d);
7935 static bool test_add_driver_64(struct torture_context *tctx,
7936 struct dcerpc_pipe *p,
7937 void *private_data)
7939 struct torture_driver_context *d =
7940 (struct torture_driver_context *)talloc_get_type_abort(private_data, struct torture_driver_context);
7942 d->local.environment = talloc_strdup(d, "Windows x64");
7943 d->local.driver_directory = talloc_strdup(d, "/usr/share/cups/drivers/x64");
7944 d->info8.driver_name = TORTURE_DRIVER;
7945 d->ex = false;
7947 return test_add_driver_arg(tctx, p, d);
7950 static bool test_add_driver_32(struct torture_context *tctx,
7951 struct dcerpc_pipe *p,
7952 void *private_data)
7954 struct torture_driver_context *d =
7955 (struct torture_driver_context *)talloc_get_type_abort(private_data, struct torture_driver_context);
7957 d->local.environment = talloc_strdup(d, "Windows NT x86");
7958 d->local.driver_directory = talloc_strdup(d, "/usr/share/cups/drivers/i386");
7959 d->info8.driver_name = TORTURE_DRIVER;
7960 d->ex = false;
7962 return test_add_driver_arg(tctx, p, d);
7965 struct torture_suite *torture_rpc_spoolss_driver(TALLOC_CTX *mem_ctx)
7967 struct torture_suite *suite = torture_suite_create(mem_ctx, "SPOOLSS-DRIVER");
7969 struct torture_rpc_tcase *tcase = torture_suite_add_rpc_iface_tcase(suite,
7970 "driver", &ndr_table_spoolss);
7971 struct torture_driver_context *t;
7973 t = talloc_zero(mem_ctx, struct torture_driver_context);
7975 t->info8.version = SPOOLSS_DRIVER_VERSION_200X;
7976 t->info8.driver_name = NULL;
7977 t->info8.architecture = NULL;
7978 t->info8.driver_path = talloc_strdup(t, "pscript5.dll");
7979 t->info8.data_file = talloc_strdup(t, "cups6.ppd");
7980 t->info8.config_file = talloc_strdup(t, "cupsui6.dll");
7982 torture_rpc_tcase_add_test_ex(tcase, "add_driver_64", test_add_driver_64, t);
7983 torture_rpc_tcase_add_test_ex(tcase, "add_driver_ex_64", test_add_driver_ex_64, t);
7985 torture_rpc_tcase_add_test_ex(tcase, "add_driver_32", test_add_driver_32, t);
7986 torture_rpc_tcase_add_test_ex(tcase, "add_driver_ex_32", test_add_driver_ex_32, t);
7988 return suite;