s4:tortore/rpc/spoolss: some compilers don't like .foo.bar = 5
[Samba/gebeck_regimport.git] / source4 / torture / rpc / spoolss.c
blob78eb5c44757185a8a260c7d2a62791139d5a4206
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/rpc.h"
33 #include "param/param.h"
34 #include "lib/registry/registry.h"
36 #define TORTURE_WELLKNOWN_PRINTER "torture_wkn_printer"
37 #define TORTURE_PRINTER "torture_printer"
38 #define TORTURE_WELLKNOWN_PRINTER_EX "torture_wkn_printer_ex"
39 #define TORTURE_PRINTER_EX "torture_printer_ex"
41 #define TOP_LEVEL_PRINT_KEY "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Print"
42 #define TOP_LEVEL_PRINT_PRINTERS_KEY TOP_LEVEL_PRINT_KEY "\\Printers"
43 #define TOP_LEVEL_CONTROL_KEY "SYSTEM\\CurrentControlSet\\Control\\Print"
44 #define TOP_LEVEL_CONTROL_FORMS_KEY TOP_LEVEL_CONTROL_KEY "\\Forms"
45 #define TOP_LEVEL_CONTROL_PRINTERS_KEY TOP_LEVEL_CONTROL_KEY "\\Printers"
47 struct test_spoolss_context {
48 /* print server handle */
49 struct policy_handle server_handle;
51 /* for EnumPorts */
52 uint32_t port_count[3];
53 union spoolss_PortInfo *ports[3];
55 /* for EnumPrinterDrivers */
56 uint32_t driver_count[8];
57 union spoolss_DriverInfo *drivers[8];
59 /* for EnumMonitors */
60 uint32_t monitor_count[3];
61 union spoolss_MonitorInfo *monitors[3];
63 /* for EnumPrintProcessors */
64 uint32_t print_processor_count[2];
65 union spoolss_PrintProcessorInfo *print_processors[2];
67 /* for EnumPrinters */
68 uint32_t printer_count[6];
69 union spoolss_PrinterInfo *printers[6];
72 #define COMPARE_STRING(tctx, c,r,e) \
73 torture_assert_str_equal(tctx, c.e, r.e, "invalid value")
75 /* not every compiler supports __typeof__() */
76 #if (__GNUC__ >= 3)
77 #define _CHECK_FIELD_SIZE(c,r,e,type) do {\
78 if (sizeof(__typeof__(c.e)) != sizeof(type)) { \
79 torture_fail(tctx, #c "." #e "field is not " #type "\n"); \
81 if (sizeof(__typeof__(r.e)) != sizeof(type)) { \
82 torture_fail(tctx, #r "." #e "field is not " #type "\n"); \
84 } while(0)
85 #else
86 #define _CHECK_FIELD_SIZE(c,r,e,type) do {} while(0)
87 #endif
89 #define COMPARE_UINT32(tctx, c, r, e) do {\
90 _CHECK_FIELD_SIZE(c, r, e, uint32_t); \
91 torture_assert_int_equal(tctx, c.e, r.e, "invalid value"); \
92 } while(0)
94 #define COMPARE_UINT64(tctx, c, r, e) do {\
95 _CHECK_FIELD_SIZE(c, r, e, uint64_t); \
96 torture_assert_int_equal(tctx, c.e, r.e, "invalid value"); \
97 } while(0)
100 #define COMPARE_NTTIME(tctx, c, r, e) do {\
101 _CHECK_FIELD_SIZE(c, r, e, NTTIME); \
102 torture_assert_int_equal(tctx, c.e, r.e, "invalid value"); \
103 } while(0)
105 #define COMPARE_STRING_ARRAY(tctx, c,r,e) do {\
106 int __i; \
107 if (!c.e && !r.e) { \
108 break; \
110 if (c.e && !r.e) { \
111 torture_fail(tctx, #r "." #e " field is NULL and " #c "." #e " is not\n"); \
113 if (!c.e && r.e) { \
114 torture_fail(tctx, #c "." #e " field is NULL and " #r "." #e " is not\n"); \
116 for (__i=0;c.e[__i] != NULL; __i++) { \
117 torture_assert_str_equal(tctx, c.e[__i], r.e[__i], "invalid value"); \
119 } while(0)
121 #define CHECK_ALIGN(size, n) do {\
122 if (size % n) {\
123 torture_warning(tctx, "%d is *NOT* %d byte aligned, should be %d",\
124 size, n, size + n - (size % n));\
126 } while(0)
128 #define DO_ROUND(size, n) (((size)+((n)-1)) & ~((n)-1))
130 #define CHECK_NEEDED_SIZE_ENUM_LEVEL(fn, info, level, count, ic, needed, align) do { \
131 if (torture_setting_bool(tctx, "spoolss_check_size", false)) {\
132 uint32_t size = ndr_size_##fn##_info(tctx, ic, level, count, info);\
133 uint32_t round_size = DO_ROUND(size, align);\
134 if (round_size != needed) {\
135 torture_warning(tctx, __location__": "#fn" level %d (count: %d) got unexpected needed size: %d, we calculated: %d", level, count, needed, round_size);\
136 CHECK_ALIGN(size, align);\
139 } while(0)
141 #define CHECK_NEEDED_SIZE_ENUM(fn, info, count, ic, needed, align) do { \
142 if (torture_setting_bool(tctx, "spoolss_check_size", false)) {\
143 uint32_t size = ndr_size_##fn##_info(tctx, ic, count, info);\
144 uint32_t round_size = DO_ROUND(size, align);\
145 if (round_size != needed) {\
146 torture_warning(tctx, __location__": "#fn" (count: %d) got unexpected needed size: %d, we calculated: %d", count, needed, round_size);\
147 CHECK_ALIGN(size, align);\
150 } while(0)
152 #define CHECK_NEEDED_SIZE_LEVEL(fn, info, level, ic, needed, align) do { \
153 if (torture_setting_bool(tctx, "spoolss_check_size", false)) {\
154 uint32_t size = ndr_size_##fn(info, level, ic, 0);\
155 uint32_t round_size = DO_ROUND(size, align);\
156 if (round_size != needed) {\
157 torture_warning(tctx, __location__": "#fn" level %d got unexpected needed size: %d, we calculated: %d", level, needed, round_size);\
158 CHECK_ALIGN(size, align);\
161 } while(0)
163 static bool PrinterInfo_to_SetPrinterInfo(struct torture_context *tctx,
164 const union spoolss_PrinterInfo *i,
165 uint32_t level,
166 union spoolss_SetPrinterInfo *s)
168 switch (level) {
169 case 0:
170 s->info0 = talloc(tctx, struct spoolss_SetPrinterInfo0);
171 break;
172 case 2:
173 s->info2 = talloc(tctx, struct spoolss_SetPrinterInfo2);
174 s->info2->servername = i->info2.servername;
175 s->info2->printername = i->info2.printername;
176 s->info2->sharename = i->info2.sharename;
177 s->info2->portname = i->info2.portname;
178 s->info2->drivername = i->info2.drivername;
179 s->info2->comment = i->info2.comment;
180 s->info2->location = i->info2.location;
181 s->info2->devmode_ptr = 0;
182 s->info2->sepfile = i->info2.sepfile;
183 s->info2->printprocessor = i->info2.printprocessor;
184 s->info2->datatype = i->info2.datatype;
185 s->info2->parameters = i->info2.parameters;
186 s->info2->secdesc_ptr = 0;
187 s->info2->attributes = i->info2.attributes;
188 s->info2->priority = i->info2.priority;
189 s->info2->defaultpriority = i->info2.defaultpriority;
190 s->info2->starttime = i->info2.starttime;
191 s->info2->untiltime = i->info2.untiltime;
192 s->info2->status = i->info2.status;
193 s->info2->cjobs = i->info2.cjobs;
194 s->info2->averageppm = i->info2.averageppm;
195 break;
196 case 3:
197 case 4:
198 case 5:
199 case 6:
200 case 7:
201 case 8:
202 case 9:
203 default:
204 return false;
207 return true;
210 static bool test_OpenPrinter_server(struct torture_context *tctx,
211 struct dcerpc_pipe *p,
212 struct policy_handle *server_handle)
214 NTSTATUS status;
215 struct spoolss_OpenPrinter op;
216 struct dcerpc_binding_handle *b = p->binding_handle;
218 op.in.printername = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
219 op.in.datatype = NULL;
220 op.in.devmode_ctr.devmode= NULL;
221 op.in.access_mask = 0;
222 op.out.handle = server_handle;
224 torture_comment(tctx, "Testing OpenPrinter(%s)\n", op.in.printername);
226 status = dcerpc_spoolss_OpenPrinter_r(b, tctx, &op);
227 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_OpenPrinter failed");
228 torture_assert_werr_ok(tctx, op.out.result, "dcerpc_spoolss_OpenPrinter failed");
230 return true;
233 static bool test_EnumPorts(struct torture_context *tctx,
234 struct dcerpc_binding_handle *b,
235 struct test_spoolss_context *ctx)
237 NTSTATUS status;
238 struct spoolss_EnumPorts r;
239 uint16_t levels[] = { 1, 2 };
240 int i, j;
242 for (i=0;i<ARRAY_SIZE(levels);i++) {
243 int level = levels[i];
244 DATA_BLOB blob;
245 uint32_t needed;
246 uint32_t count;
247 union spoolss_PortInfo *info;
249 r.in.servername = "";
250 r.in.level = level;
251 r.in.buffer = NULL;
252 r.in.offered = 0;
253 r.out.needed = &needed;
254 r.out.count = &count;
255 r.out.info = &info;
257 torture_comment(tctx, "Testing EnumPorts level %u\n", r.in.level);
259 status = dcerpc_spoolss_EnumPorts_r(b, ctx, &r);
260 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EnumPorts failed");
261 if (W_ERROR_IS_OK(r.out.result)) {
262 /* TODO: do some more checks here */
263 continue;
265 torture_assert_werr_equal(tctx, r.out.result, WERR_INSUFFICIENT_BUFFER,
266 "EnumPorts unexpected return code");
268 blob = data_blob_talloc_zero(ctx, needed);
269 r.in.buffer = &blob;
270 r.in.offered = needed;
272 status = dcerpc_spoolss_EnumPorts_r(b, ctx, &r);
273 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EnumPorts failed");
275 torture_assert_werr_ok(tctx, r.out.result, "EnumPorts failed");
277 torture_assert(tctx, info, "EnumPorts returned no info");
279 CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumPorts, info, r.in.level, count, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
281 ctx->port_count[level] = count;
282 ctx->ports[level] = info;
285 for (i=1;i<ARRAY_SIZE(levels);i++) {
286 int level = levels[i];
287 int old_level = levels[i-1];
288 torture_assert_int_equal(tctx, ctx->port_count[level], ctx->port_count[old_level],
289 "EnumPorts invalid value");
291 /* if the array sizes are not the same we would maybe segfault in the following code */
293 for (i=0;i<ARRAY_SIZE(levels);i++) {
294 int level = levels[i];
295 for (j=0;j<ctx->port_count[level];j++) {
296 union spoolss_PortInfo *cur = &ctx->ports[level][j];
297 union spoolss_PortInfo *ref = &ctx->ports[2][j];
298 switch (level) {
299 case 1:
300 COMPARE_STRING(tctx, cur->info1, ref->info2, port_name);
301 break;
302 case 2:
303 /* level 2 is our reference, and it makes no sense to compare it to itself */
304 break;
309 return true;
312 static bool test_GetPrintProcessorDirectory(struct torture_context *tctx,
313 struct dcerpc_pipe *p,
314 const char *environment)
316 NTSTATUS status;
317 struct dcerpc_binding_handle *b = p->binding_handle;
318 struct spoolss_GetPrintProcessorDirectory r;
319 struct {
320 uint16_t level;
321 const char *server;
322 } levels[] = {{
323 .level = 1,
324 .server = NULL
326 .level = 1,
327 .server = ""
329 .level = 78,
330 .server = ""
332 .level = 1,
333 .server = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p))
335 .level = 1024,
336 .server = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p))
339 int i;
340 uint32_t needed;
342 for (i=0;i<ARRAY_SIZE(levels);i++) {
343 int level = levels[i].level;
344 DATA_BLOB blob;
346 r.in.server = levels[i].server;
347 r.in.environment = environment;
348 r.in.level = level;
349 r.in.buffer = NULL;
350 r.in.offered = 0;
351 r.out.needed = &needed;
353 torture_comment(tctx, "Testing GetPrintProcessorDirectory level %u\n", r.in.level);
355 status = dcerpc_spoolss_GetPrintProcessorDirectory_r(b, tctx, &r);
356 torture_assert_ntstatus_ok(tctx, status,
357 "dcerpc_spoolss_GetPrintProcessorDirectory failed");
358 torture_assert_werr_equal(tctx, r.out.result, WERR_INSUFFICIENT_BUFFER,
359 "GetPrintProcessorDirectory unexpected return code");
361 blob = data_blob_talloc_zero(tctx, needed);
362 r.in.buffer = &blob;
363 r.in.offered = needed;
365 status = dcerpc_spoolss_GetPrintProcessorDirectory_r(b, tctx, &r);
366 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_GetPrintProcessorDirectory failed");
368 torture_assert_werr_ok(tctx, r.out.result, "GetPrintProcessorDirectory failed");
370 CHECK_NEEDED_SIZE_LEVEL(spoolss_PrintProcessorDirectoryInfo, r.out.info, r.in.level, lp_iconv_convenience(tctx->lp_ctx), needed, 2);
373 return true;
377 static bool test_GetPrinterDriverDirectory(struct torture_context *tctx,
378 struct dcerpc_pipe *p,
379 const char *environment)
381 NTSTATUS status;
382 struct dcerpc_binding_handle *b = p->binding_handle;
383 struct spoolss_GetPrinterDriverDirectory r;
384 struct {
385 uint16_t level;
386 const char *server;
387 } levels[] = {{
388 .level = 1,
389 .server = NULL
391 .level = 1,
392 .server = ""
394 .level = 78,
395 .server = ""
397 .level = 1,
398 .server = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p))
400 .level = 1024,
401 .server = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p))
404 int i;
405 uint32_t needed;
407 for (i=0;i<ARRAY_SIZE(levels);i++) {
408 int level = levels[i].level;
409 DATA_BLOB blob;
411 r.in.server = levels[i].server;
412 r.in.environment = environment;
413 r.in.level = level;
414 r.in.buffer = NULL;
415 r.in.offered = 0;
416 r.out.needed = &needed;
418 torture_comment(tctx, "Testing GetPrinterDriverDirectory level %u\n", r.in.level);
420 status = dcerpc_spoolss_GetPrinterDriverDirectory_r(b, tctx, &r);
421 torture_assert_ntstatus_ok(tctx, status,
422 "dcerpc_spoolss_GetPrinterDriverDirectory failed");
423 torture_assert_werr_equal(tctx, r.out.result, WERR_INSUFFICIENT_BUFFER,
424 "GetPrinterDriverDirectory unexpected return code");
426 blob = data_blob_talloc_zero(tctx, needed);
427 r.in.buffer = &blob;
428 r.in.offered = needed;
430 status = dcerpc_spoolss_GetPrinterDriverDirectory_r(b, tctx, &r);
431 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_GetPrinterDriverDirectory failed");
433 torture_assert_werr_ok(tctx, r.out.result, "GetPrinterDriverDirectory failed");
435 CHECK_NEEDED_SIZE_LEVEL(spoolss_DriverDirectoryInfo, r.out.info, r.in.level, lp_iconv_convenience(tctx->lp_ctx), needed, 2);
438 return true;
441 static bool test_EnumPrinterDrivers(struct torture_context *tctx,
442 struct dcerpc_pipe *p,
443 struct test_spoolss_context *ctx,
444 const char *architecture)
446 NTSTATUS status;
447 struct dcerpc_binding_handle *b = p->binding_handle;
448 struct spoolss_EnumPrinterDrivers r;
449 uint16_t levels[] = { 1, 2, 3, 4, 5, 6, 8 };
450 int i, j;
452 for (i=0;i<ARRAY_SIZE(levels);i++) {
453 int level = levels[i];
454 DATA_BLOB blob;
455 uint32_t needed;
456 uint32_t count;
457 union spoolss_DriverInfo *info;
459 /* FIXME: gd, come back and fix "" as server, and handle
460 * priority of returned error codes in torture test and samba 3
461 * server */
463 r.in.server = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
464 r.in.environment = architecture;
465 r.in.level = level;
466 r.in.buffer = NULL;
467 r.in.offered = 0;
468 r.out.needed = &needed;
469 r.out.count = &count;
470 r.out.info = &info;
472 torture_comment(tctx, "Testing EnumPrinterDrivers level %u (%s)\n", r.in.level, r.in.environment);
474 status = dcerpc_spoolss_EnumPrinterDrivers_r(b, ctx, &r);
475 torture_assert_ntstatus_ok(tctx, status,
476 "dcerpc_spoolss_EnumPrinterDrivers failed");
477 if (W_ERROR_IS_OK(r.out.result)) {
478 /* TODO: do some more checks here */
479 continue;
481 if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
482 blob = data_blob_talloc_zero(ctx, needed);
483 r.in.buffer = &blob;
484 r.in.offered = needed;
486 status = dcerpc_spoolss_EnumPrinterDrivers_r(b, ctx, &r);
487 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EnumPrinterDrivers failed");
490 torture_assert_werr_ok(tctx, r.out.result, "EnumPrinterDrivers failed");
492 CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumPrinterDrivers, info, r.in.level, count, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
494 ctx->driver_count[level] = count;
495 ctx->drivers[level] = info;
498 for (i=1;i<ARRAY_SIZE(levels);i++) {
499 int level = levels[i];
500 int old_level = levels[i-1];
502 torture_assert_int_equal(tctx, ctx->driver_count[level], ctx->driver_count[old_level],
503 "EnumPrinterDrivers invalid value");
506 for (i=0;i<ARRAY_SIZE(levels);i++) {
507 int level = levels[i];
509 for (j=0;j<ctx->driver_count[level];j++) {
510 union spoolss_DriverInfo *cur = &ctx->drivers[level][j];
511 union spoolss_DriverInfo *ref = &ctx->drivers[8][j];
513 switch (level) {
514 case 1:
515 COMPARE_STRING(tctx, cur->info1, ref->info8, driver_name);
516 break;
517 case 2:
518 COMPARE_UINT32(tctx, cur->info2, ref->info8, version);
519 COMPARE_STRING(tctx, cur->info2, ref->info8, driver_name);
520 COMPARE_STRING(tctx, cur->info2, ref->info8, architecture);
521 COMPARE_STRING(tctx, cur->info2, ref->info8, driver_path);
522 COMPARE_STRING(tctx, cur->info2, ref->info8, data_file);
523 COMPARE_STRING(tctx, cur->info2, ref->info8, config_file);
524 break;
525 case 3:
526 COMPARE_UINT32(tctx, cur->info3, ref->info8, version);
527 COMPARE_STRING(tctx, cur->info3, ref->info8, driver_name);
528 COMPARE_STRING(tctx, cur->info3, ref->info8, architecture);
529 COMPARE_STRING(tctx, cur->info3, ref->info8, driver_path);
530 COMPARE_STRING(tctx, cur->info3, ref->info8, data_file);
531 COMPARE_STRING(tctx, cur->info3, ref->info8, config_file);
532 COMPARE_STRING(tctx, cur->info3, ref->info8, help_file);
533 COMPARE_STRING_ARRAY(tctx, cur->info3, ref->info8, dependent_files);
534 COMPARE_STRING(tctx, cur->info3, ref->info8, monitor_name);
535 COMPARE_STRING(tctx, cur->info3, ref->info8, default_datatype);
536 break;
537 case 4:
538 COMPARE_UINT32(tctx, cur->info4, ref->info8, version);
539 COMPARE_STRING(tctx, cur->info4, ref->info8, driver_name);
540 COMPARE_STRING(tctx, cur->info4, ref->info8, architecture);
541 COMPARE_STRING(tctx, cur->info4, ref->info8, driver_path);
542 COMPARE_STRING(tctx, cur->info4, ref->info8, data_file);
543 COMPARE_STRING(tctx, cur->info4, ref->info8, config_file);
544 COMPARE_STRING(tctx, cur->info4, ref->info8, help_file);
545 COMPARE_STRING_ARRAY(tctx, cur->info4, ref->info8, dependent_files);
546 COMPARE_STRING(tctx, cur->info4, ref->info8, monitor_name);
547 COMPARE_STRING(tctx, cur->info4, ref->info8, default_datatype);
548 COMPARE_STRING_ARRAY(tctx, cur->info4, ref->info8, previous_names);
549 break;
550 case 5:
551 COMPARE_UINT32(tctx, cur->info5, ref->info8, version);
552 COMPARE_STRING(tctx, cur->info5, ref->info8, driver_name);
553 COMPARE_STRING(tctx, cur->info5, ref->info8, architecture);
554 COMPARE_STRING(tctx, cur->info5, ref->info8, driver_path);
555 COMPARE_STRING(tctx, cur->info5, ref->info8, data_file);
556 COMPARE_STRING(tctx, cur->info5, ref->info8, config_file);
557 /*COMPARE_UINT32(tctx, cur->info5, ref->info8, driver_attributes);*/
558 /*COMPARE_UINT32(tctx, cur->info5, ref->info8, config_version);*/
559 /*TODO: ! COMPARE_UINT32(tctx, cur->info5, ref->info8, driver_version); */
560 break;
561 case 6:
562 COMPARE_UINT32(tctx, cur->info6, ref->info8, version);
563 COMPARE_STRING(tctx, cur->info6, ref->info8, driver_name);
564 COMPARE_STRING(tctx, cur->info6, ref->info8, architecture);
565 COMPARE_STRING(tctx, cur->info6, ref->info8, driver_path);
566 COMPARE_STRING(tctx, cur->info6, ref->info8, data_file);
567 COMPARE_STRING(tctx, cur->info6, ref->info8, config_file);
568 COMPARE_STRING(tctx, cur->info6, ref->info8, help_file);
569 COMPARE_STRING_ARRAY(tctx, cur->info6, ref->info8, dependent_files);
570 COMPARE_STRING(tctx, cur->info6, ref->info8, monitor_name);
571 COMPARE_STRING(tctx, cur->info6, ref->info8, default_datatype);
572 COMPARE_STRING_ARRAY(tctx, cur->info6, ref->info8, previous_names);
573 COMPARE_NTTIME(tctx, cur->info6, ref->info8, driver_date);
574 COMPARE_UINT64(tctx, cur->info6, ref->info8, driver_version);
575 COMPARE_STRING(tctx, cur->info6, ref->info8, manufacturer_name);
576 COMPARE_STRING(tctx, cur->info6, ref->info8, manufacturer_url);
577 COMPARE_STRING(tctx, cur->info6, ref->info8, hardware_id);
578 COMPARE_STRING(tctx, cur->info6, ref->info8, provider);
579 break;
580 case 8:
581 /* level 8 is our reference, and it makes no sense to compare it to itself */
582 break;
587 return true;
590 static bool test_EnumMonitors(struct torture_context *tctx,
591 struct dcerpc_binding_handle *b,
592 struct test_spoolss_context *ctx)
594 NTSTATUS status;
595 struct spoolss_EnumMonitors r;
596 uint16_t levels[] = { 1, 2 };
597 int i, j;
599 for (i=0;i<ARRAY_SIZE(levels);i++) {
600 int level = levels[i];
601 DATA_BLOB blob;
602 uint32_t needed;
603 uint32_t count;
604 union spoolss_MonitorInfo *info;
606 r.in.servername = "";
607 r.in.level = level;
608 r.in.buffer = NULL;
609 r.in.offered = 0;
610 r.out.needed = &needed;
611 r.out.count = &count;
612 r.out.info = &info;
614 torture_comment(tctx, "Testing EnumMonitors level %u\n", r.in.level);
616 status = dcerpc_spoolss_EnumMonitors_r(b, ctx, &r);
617 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EnumMonitors failed");
618 if (W_ERROR_IS_OK(r.out.result)) {
619 /* TODO: do some more checks here */
620 continue;
622 torture_assert_werr_equal(tctx, r.out.result, WERR_INSUFFICIENT_BUFFER,
623 "EnumMonitors failed");
625 blob = data_blob_talloc_zero(ctx, needed);
626 r.in.buffer = &blob;
627 r.in.offered = needed;
629 status = dcerpc_spoolss_EnumMonitors_r(b, ctx, &r);
630 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EnumMonitors failed");
632 torture_assert_werr_ok(tctx, r.out.result, "EnumMonitors failed");
634 CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumMonitors, info, r.in.level, count, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
636 ctx->monitor_count[level] = count;
637 ctx->monitors[level] = info;
640 for (i=1;i<ARRAY_SIZE(levels);i++) {
641 int level = levels[i];
642 int old_level = levels[i-1];
643 torture_assert_int_equal(tctx, ctx->monitor_count[level], ctx->monitor_count[old_level],
644 "EnumMonitors invalid value");
647 for (i=0;i<ARRAY_SIZE(levels);i++) {
648 int level = levels[i];
649 for (j=0;j<ctx->monitor_count[level];j++) {
650 union spoolss_MonitorInfo *cur = &ctx->monitors[level][j];
651 union spoolss_MonitorInfo *ref = &ctx->monitors[2][j];
652 switch (level) {
653 case 1:
654 COMPARE_STRING(tctx, cur->info1, ref->info2, monitor_name);
655 break;
656 case 2:
657 /* level 2 is our reference, and it makes no sense to compare it to itself */
658 break;
663 return true;
666 static bool test_EnumPrintProcessors(struct torture_context *tctx,
667 struct dcerpc_binding_handle *b,
668 struct test_spoolss_context *ctx,
669 const char *environment)
671 NTSTATUS status;
672 struct spoolss_EnumPrintProcessors r;
673 uint16_t levels[] = { 1 };
674 int i, j;
676 for (i=0;i<ARRAY_SIZE(levels);i++) {
677 int level = levels[i];
678 DATA_BLOB blob;
679 uint32_t needed;
680 uint32_t count;
681 union spoolss_PrintProcessorInfo *info;
683 r.in.servername = "";
684 r.in.environment = environment;
685 r.in.level = level;
686 r.in.buffer = NULL;
687 r.in.offered = 0;
688 r.out.needed = &needed;
689 r.out.count = &count;
690 r.out.info = &info;
692 torture_comment(tctx, "Testing EnumPrintProcessors level %u\n", r.in.level);
694 status = dcerpc_spoolss_EnumPrintProcessors_r(b, ctx, &r);
695 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EnumPrintProcessors failed");
696 if (W_ERROR_IS_OK(r.out.result)) {
697 /* TODO: do some more checks here */
698 continue;
700 torture_assert_werr_equal(tctx, r.out.result, WERR_INSUFFICIENT_BUFFER,
701 "EnumPrintProcessors unexpected return code");
703 blob = data_blob_talloc_zero(ctx, needed);
704 r.in.buffer = &blob;
705 r.in.offered = needed;
707 status = dcerpc_spoolss_EnumPrintProcessors_r(b, ctx, &r);
708 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EnumPrintProcessors failed");
710 torture_assert_werr_ok(tctx, r.out.result, "EnumPrintProcessors failed");
712 CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumPrintProcessors, info, r.in.level, count, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
714 ctx->print_processor_count[level] = count;
715 ctx->print_processors[level] = info;
718 for (i=1;i<ARRAY_SIZE(levels);i++) {
719 int level = levels[i];
720 int old_level = levels[i-1];
721 torture_assert_int_equal(tctx, ctx->print_processor_count[level], ctx->print_processor_count[old_level],
722 "EnumPrintProcessors failed");
725 for (i=0;i<ARRAY_SIZE(levels);i++) {
726 int level = levels[i];
727 for (j=0;j<ctx->print_processor_count[level];j++) {
728 #if 0
729 union spoolss_PrintProcessorInfo *cur = &ctx->print_processors[level][j];
730 union spoolss_PrintProcessorInfo *ref = &ctx->print_processors[1][j];
731 #endif
732 switch (level) {
733 case 1:
734 /* level 1 is our reference, and it makes no sense to compare it to itself */
735 break;
740 return true;
743 static bool test_EnumPrintProcDataTypes(struct torture_context *tctx,
744 struct dcerpc_binding_handle *b)
746 NTSTATUS status;
747 struct spoolss_EnumPrintProcDataTypes r;
748 uint16_t levels[] = { 1 };
749 int i;
751 for (i=0;i<ARRAY_SIZE(levels);i++) {
752 int level = levels[i];
753 DATA_BLOB blob;
754 uint32_t needed;
755 uint32_t count;
756 union spoolss_PrintProcDataTypesInfo *info;
758 r.in.servername = "";
759 r.in.print_processor_name = "winprint";
760 r.in.level = level;
761 r.in.buffer = NULL;
762 r.in.offered = 0;
763 r.out.needed = &needed;
764 r.out.count = &count;
765 r.out.info = &info;
767 torture_comment(tctx, "Testing EnumPrintProcDataTypes level %u\n", r.in.level);
769 status = dcerpc_spoolss_EnumPrintProcDataTypes_r(b, tctx, &r);
770 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EnumPrintProcDataType failed");
771 if (W_ERROR_IS_OK(r.out.result)) {
772 /* TODO: do some more checks here */
773 continue;
775 torture_assert_werr_equal(tctx, r.out.result, WERR_INSUFFICIENT_BUFFER,
776 "EnumPrintProcDataTypes unexpected return code");
778 blob = data_blob_talloc_zero(tctx, needed);
779 r.in.buffer = &blob;
780 r.in.offered = needed;
782 status = dcerpc_spoolss_EnumPrintProcDataTypes_r(b, tctx, &r);
783 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EnumPrintProcDataTypes failed");
785 torture_assert_werr_ok(tctx, r.out.result, "EnumPrintProcDataTypes failed");
787 CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumPrintProcDataTypes, info, r.in.level, count, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
791 return true;
795 static bool test_EnumPrinters(struct torture_context *tctx,
796 struct dcerpc_binding_handle *b,
797 struct test_spoolss_context *ctx)
799 struct spoolss_EnumPrinters r;
800 NTSTATUS status;
801 uint16_t levels[] = { 0, 1, 2, 4, 5 };
802 int i, j;
804 for (i=0;i<ARRAY_SIZE(levels);i++) {
805 int level = levels[i];
806 DATA_BLOB blob;
807 uint32_t needed;
808 uint32_t count;
809 union spoolss_PrinterInfo *info;
811 r.in.flags = PRINTER_ENUM_LOCAL;
812 r.in.server = "";
813 r.in.level = level;
814 r.in.buffer = NULL;
815 r.in.offered = 0;
816 r.out.needed = &needed;
817 r.out.count = &count;
818 r.out.info = &info;
820 torture_comment(tctx, "Testing EnumPrinters level %u\n", r.in.level);
822 status = dcerpc_spoolss_EnumPrinters_r(b, ctx, &r);
823 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EnumPrinters failed");
824 if (W_ERROR_IS_OK(r.out.result)) {
825 /* TODO: do some more checks here */
826 continue;
828 torture_assert_werr_equal(tctx, r.out.result, WERR_INSUFFICIENT_BUFFER,
829 "EnumPrinters unexpected return code");
831 blob = data_blob_talloc_zero(ctx, needed);
832 r.in.buffer = &blob;
833 r.in.offered = needed;
835 status = dcerpc_spoolss_EnumPrinters_r(b, ctx, &r);
836 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EnumPrinters failed");
838 torture_assert_werr_ok(tctx, r.out.result, "EnumPrinters failed");
840 CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumPrinters, info, r.in.level, count, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
842 ctx->printer_count[level] = count;
843 ctx->printers[level] = info;
846 for (i=1;i<ARRAY_SIZE(levels);i++) {
847 int level = levels[i];
848 int old_level = levels[i-1];
849 torture_assert_int_equal(tctx, ctx->printer_count[level], ctx->printer_count[old_level],
850 "EnumPrinters invalid value");
853 for (i=0;i<ARRAY_SIZE(levels);i++) {
854 int level = levels[i];
855 for (j=0;j<ctx->printer_count[level];j++) {
856 union spoolss_PrinterInfo *cur = &ctx->printers[level][j];
857 union spoolss_PrinterInfo *ref = &ctx->printers[2][j];
858 switch (level) {
859 case 0:
860 COMPARE_STRING(tctx, cur->info0, ref->info2, printername);
861 COMPARE_STRING(tctx, cur->info0, ref->info2, servername);
862 COMPARE_UINT32(tctx, cur->info0, ref->info2, cjobs);
863 /*COMPARE_UINT32(tctx, cur->info0, ref->info2, total_jobs);
864 COMPARE_UINT32(tctx, cur->info0, ref->info2, total_bytes);
865 COMPARE_SPOOLSS_TIME(cur->info0, ref->info2, spoolss_Time time);
866 COMPARE_UINT32(tctx, cur->info0, ref->info2, global_counter);
867 COMPARE_UINT32(tctx, cur->info0, ref->info2, total_pages);
868 COMPARE_UINT32(tctx, cur->info0, ref->info2, version);
869 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown10);
870 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown11);
871 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown12);
872 COMPARE_UINT32(tctx, cur->info0, ref->info2, session_counter);
873 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown14);
874 COMPARE_UINT32(tctx, cur->info0, ref->info2, printer_errors);
875 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown16);
876 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown17);
877 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown18);
878 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown19);
879 COMPARE_UINT32(tctx, cur->info0, ref->info2, change_id);
880 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown21);*/
881 COMPARE_UINT32(tctx, cur->info0, ref->info2, status);
882 /*COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown23);
883 COMPARE_UINT32(tctx, cur->info0, ref->info2, c_setprinter);
884 COMPARE_UINT16(cur->info0, ref->info2, unknown25);
885 COMPARE_UINT16(cur->info0, ref->info2, unknown26);
886 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown27);
887 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown28);
888 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown29);*/
889 break;
890 case 1:
891 /*COMPARE_UINT32(tctx, cur->info1, ref->info2, flags);*/
892 /*COMPARE_STRING(tctx, cur->info1, ref->info2, name);*/
893 /*COMPARE_STRING(tctx, cur->info1, ref->info2, description);*/
894 COMPARE_STRING(tctx, cur->info1, ref->info2, comment);
895 break;
896 case 2:
897 /* level 2 is our reference, and it makes no sense to compare it to itself */
898 break;
899 case 4:
900 COMPARE_STRING(tctx, cur->info4, ref->info2, printername);
901 COMPARE_STRING(tctx, cur->info4, ref->info2, servername);
902 COMPARE_UINT32(tctx, cur->info4, ref->info2, attributes);
903 break;
904 case 5:
905 COMPARE_STRING(tctx, cur->info5, ref->info2, printername);
906 COMPARE_STRING(tctx, cur->info5, ref->info2, portname);
907 COMPARE_UINT32(tctx, cur->info5, ref->info2, attributes);
908 /*COMPARE_UINT32(tctx, cur->info5, ref->info2, device_not_selected_timeout);
909 COMPARE_UINT32(tctx, cur->info5, ref->info2, transmission_retry_timeout);*/
910 break;
915 /* TODO:
916 * - verify that the port of a printer was in the list returned by EnumPorts
919 return true;
922 static bool test_GetPrinterDriver2(struct torture_context *tctx,
923 struct dcerpc_binding_handle *b,
924 struct policy_handle *handle,
925 const char *driver_name,
926 const char *environment);
928 bool test_GetPrinter_level(struct torture_context *tctx,
929 struct dcerpc_binding_handle *b,
930 struct policy_handle *handle,
931 uint32_t level,
932 union spoolss_PrinterInfo *info)
934 struct spoolss_GetPrinter r;
935 uint32_t needed;
937 r.in.handle = handle;
938 r.in.level = level;
939 r.in.buffer = NULL;
940 r.in.offered = 0;
941 r.out.needed = &needed;
943 torture_comment(tctx, "Testing GetPrinter level %u\n", r.in.level);
945 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_GetPrinter_r(b, tctx, &r),
946 "GetPrinter failed");
948 if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
949 DATA_BLOB blob = data_blob_talloc_zero(tctx, needed);
950 r.in.buffer = &blob;
951 r.in.offered = needed;
953 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_GetPrinter_r(b, tctx, &r),
954 "GetPrinter failed");
957 torture_assert_werr_ok(tctx, r.out.result, "GetPrinter failed");
959 CHECK_NEEDED_SIZE_LEVEL(spoolss_PrinterInfo, r.out.info, r.in.level, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
961 if (info && r.out.info) {
962 *info = *r.out.info;
965 return true;
969 static bool test_GetPrinter(struct torture_context *tctx,
970 struct dcerpc_binding_handle *b,
971 struct policy_handle *handle,
972 const char *environment)
974 uint32_t levels[] = {0, 1, 2, 3, 4, 5, 6, 7, 8};
975 int i;
977 for (i=0;i<ARRAY_SIZE(levels);i++) {
979 union spoolss_PrinterInfo info;
981 ZERO_STRUCT(info);
983 torture_assert(tctx, test_GetPrinter_level(tctx, b, handle, levels[i], &info),
984 "failed to call GetPrinter");
986 if ((levels[i] == 2) && info.info2.drivername && strlen(info.info2.drivername)) {
987 torture_assert(tctx,
988 test_GetPrinterDriver2(tctx, b, handle, info.info2.drivername, environment),
989 "failed to call test_GetPrinterDriver2");
993 return true;
996 static bool test_SetPrinter(struct torture_context *tctx,
997 struct dcerpc_binding_handle *b,
998 struct policy_handle *handle,
999 struct spoolss_SetPrinterInfoCtr *info_ctr,
1000 struct spoolss_DevmodeContainer *devmode_ctr,
1001 struct sec_desc_buf *secdesc_ctr,
1002 enum spoolss_PrinterControl command)
1004 struct spoolss_SetPrinter r;
1006 r.in.handle = handle;
1007 r.in.info_ctr = info_ctr;
1008 r.in.devmode_ctr = devmode_ctr;
1009 r.in.secdesc_ctr = secdesc_ctr;
1010 r.in.command = command;
1012 torture_comment(tctx, "Testing SetPrinter level %d\n", r.in.info_ctr->level);
1014 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_SetPrinter_r(b, tctx, &r),
1015 "failed to call SetPrinter");
1016 torture_assert_werr_ok(tctx, r.out.result,
1017 "failed to call SetPrinter");
1019 return true;
1022 static bool test_SetPrinter_errors(struct torture_context *tctx,
1023 struct dcerpc_binding_handle *b,
1024 struct policy_handle *handle)
1026 struct spoolss_SetPrinter r;
1027 uint16_t levels[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
1028 int i;
1030 struct spoolss_SetPrinterInfoCtr info_ctr;
1031 struct spoolss_DevmodeContainer devmode_ctr;
1032 struct sec_desc_buf secdesc_ctr;
1034 info_ctr.level = 0;
1035 info_ctr.info.info0 = NULL;
1037 ZERO_STRUCT(devmode_ctr);
1038 ZERO_STRUCT(secdesc_ctr);
1040 r.in.handle = handle;
1041 r.in.info_ctr = &info_ctr;
1042 r.in.devmode_ctr = &devmode_ctr;
1043 r.in.secdesc_ctr = &secdesc_ctr;
1044 r.in.command = 0;
1046 torture_comment(tctx, "Testing SetPrinter all zero\n");
1048 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_SetPrinter_r(b, tctx, &r),
1049 "failed to call SetPrinter");
1050 torture_assert_werr_equal(tctx, r.out.result, WERR_INVALID_PARAM,
1051 "failed to call SetPrinter");
1053 again:
1054 for (i=0; i < ARRAY_SIZE(levels); i++) {
1056 struct spoolss_SetPrinterInfo0 info0;
1057 struct spoolss_SetPrinterInfo1 info1;
1058 struct spoolss_SetPrinterInfo2 info2;
1059 struct spoolss_SetPrinterInfo3 info3;
1060 struct spoolss_SetPrinterInfo4 info4;
1061 struct spoolss_SetPrinterInfo5 info5;
1062 struct spoolss_SetPrinterInfo6 info6;
1063 struct spoolss_SetPrinterInfo7 info7;
1064 struct spoolss_SetPrinterInfo8 info8;
1065 struct spoolss_SetPrinterInfo9 info9;
1068 info_ctr.level = levels[i];
1069 switch (levels[i]) {
1070 case 0:
1071 ZERO_STRUCT(info0);
1072 info_ctr.info.info0 = &info0;
1073 break;
1074 case 1:
1075 ZERO_STRUCT(info1);
1076 info_ctr.info.info1 = &info1;
1077 break;
1078 case 2:
1079 ZERO_STRUCT(info2);
1080 info_ctr.info.info2 = &info2;
1081 break;
1082 case 3:
1083 ZERO_STRUCT(info3);
1084 info_ctr.info.info3 = &info3;
1085 break;
1086 case 4:
1087 ZERO_STRUCT(info4);
1088 info_ctr.info.info4 = &info4;
1089 break;
1090 case 5:
1091 ZERO_STRUCT(info5);
1092 info_ctr.info.info5 = &info5;
1093 break;
1094 case 6:
1095 ZERO_STRUCT(info6);
1096 info_ctr.info.info6 = &info6;
1097 break;
1098 case 7:
1099 ZERO_STRUCT(info7);
1100 info_ctr.info.info7 = &info7;
1101 break;
1102 case 8:
1103 ZERO_STRUCT(info8);
1104 info_ctr.info.info8 = &info8;
1105 break;
1106 case 9:
1107 ZERO_STRUCT(info9);
1108 info_ctr.info.info9 = &info9;
1109 break;
1112 torture_comment(tctx, "Testing SetPrinter level %d, command %d\n",
1113 info_ctr.level, r.in.command);
1115 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_SetPrinter_r(b, tctx, &r),
1116 "failed to call SetPrinter");
1118 switch (r.in.command) {
1119 case SPOOLSS_PRINTER_CONTROL_UNPAUSE: /* 0 */
1120 /* is ignored for all levels other then 0 */
1121 if (info_ctr.level > 0) {
1122 /* ignored then */
1123 break;
1125 case SPOOLSS_PRINTER_CONTROL_PAUSE: /* 1 */
1126 case SPOOLSS_PRINTER_CONTROL_RESUME: /* 2 */
1127 case SPOOLSS_PRINTER_CONTROL_PURGE: /* 3 */
1128 if (info_ctr.level > 0) {
1129 /* is invalid for all levels other then 0 */
1130 torture_assert_werr_equal(tctx, r.out.result, WERR_INVALID_PRINTER_COMMAND,
1131 "unexpected error code returned");
1132 continue;
1133 } else {
1134 torture_assert_werr_ok(tctx, r.out.result,
1135 "failed to call SetPrinter with non 0 command");
1136 continue;
1138 break;
1140 case SPOOLSS_PRINTER_CONTROL_SET_STATUS: /* 4 */
1141 /* FIXME: gd needs further investigation */
1142 default:
1143 torture_assert_werr_equal(tctx, r.out.result, WERR_INVALID_PRINTER_COMMAND,
1144 "unexpected error code returned");
1145 continue;
1148 switch (info_ctr.level) {
1149 case 1:
1150 torture_assert_werr_equal(tctx, r.out.result, WERR_UNKNOWN_LEVEL,
1151 "unexpected error code returned");
1152 break;
1153 case 2:
1154 torture_assert_werr_equal(tctx, r.out.result, WERR_UNKNOWN_PRINTER_DRIVER,
1155 "unexpected error code returned");
1156 break;
1157 case 3:
1158 case 4:
1159 case 5:
1160 case 7:
1161 torture_assert_werr_equal(tctx, r.out.result, WERR_INVALID_PARAM,
1162 "unexpected error code returned");
1163 break;
1164 case 9:
1165 torture_assert_werr_equal(tctx, r.out.result, WERR_NOT_SUPPORTED,
1166 "unexpected error code returned");
1167 break;
1168 default:
1169 torture_assert_werr_ok(tctx, r.out.result,
1170 "failed to call SetPrinter");
1171 break;
1175 if (r.in.command < 5) {
1176 r.in.command++;
1177 goto again;
1180 return true;
1183 static void clear_info2(struct spoolss_SetPrinterInfoCtr *r)
1185 if ((r->level == 2) && (r->info.info2)) {
1186 r->info.info2->secdesc_ptr = 0;
1187 r->info.info2->devmode_ptr = 0;
1191 static bool test_PrinterInfo(struct torture_context *tctx,
1192 struct dcerpc_binding_handle *b,
1193 struct policy_handle *handle)
1195 NTSTATUS status;
1196 struct spoolss_SetPrinter s;
1197 struct spoolss_GetPrinter q;
1198 struct spoolss_GetPrinter q0;
1199 struct spoolss_SetPrinterInfoCtr info_ctr;
1200 union spoolss_PrinterInfo info;
1201 struct spoolss_DevmodeContainer devmode_ctr;
1202 struct sec_desc_buf secdesc_ctr;
1203 uint32_t needed;
1204 bool ret = true;
1205 int i;
1207 uint32_t status_list[] = {
1208 /* these do not stick
1209 PRINTER_STATUS_PAUSED,
1210 PRINTER_STATUS_ERROR,
1211 PRINTER_STATUS_PENDING_DELETION, */
1212 PRINTER_STATUS_PAPER_JAM,
1213 PRINTER_STATUS_PAPER_OUT,
1214 PRINTER_STATUS_MANUAL_FEED,
1215 PRINTER_STATUS_PAPER_PROBLEM,
1216 PRINTER_STATUS_OFFLINE,
1217 PRINTER_STATUS_IO_ACTIVE,
1218 PRINTER_STATUS_BUSY,
1219 PRINTER_STATUS_PRINTING,
1220 PRINTER_STATUS_OUTPUT_BIN_FULL,
1221 PRINTER_STATUS_NOT_AVAILABLE,
1222 PRINTER_STATUS_WAITING,
1223 PRINTER_STATUS_PROCESSING,
1224 PRINTER_STATUS_INITIALIZING,
1225 PRINTER_STATUS_WARMING_UP,
1226 PRINTER_STATUS_TONER_LOW,
1227 PRINTER_STATUS_NO_TONER,
1228 PRINTER_STATUS_PAGE_PUNT,
1229 PRINTER_STATUS_USER_INTERVENTION,
1230 PRINTER_STATUS_OUT_OF_MEMORY,
1231 PRINTER_STATUS_DOOR_OPEN,
1232 PRINTER_STATUS_SERVER_UNKNOWN,
1233 PRINTER_STATUS_POWER_SAVE,
1234 /* these do not stick
1235 0x02000000,
1236 0x04000000,
1237 0x08000000,
1238 0x10000000,
1239 0x20000000,
1240 0x40000000,
1241 0x80000000 */
1243 uint32_t default_attribute = PRINTER_ATTRIBUTE_LOCAL;
1244 uint32_t attribute_list[] = {
1245 PRINTER_ATTRIBUTE_QUEUED,
1246 /* fails with WERR_INVALID_DATATYPE:
1247 PRINTER_ATTRIBUTE_DIRECT, */
1248 /* does not stick
1249 PRINTER_ATTRIBUTE_DEFAULT, */
1250 PRINTER_ATTRIBUTE_SHARED,
1251 /* does not stick
1252 PRINTER_ATTRIBUTE_NETWORK, */
1253 PRINTER_ATTRIBUTE_HIDDEN,
1254 PRINTER_ATTRIBUTE_LOCAL,
1255 PRINTER_ATTRIBUTE_ENABLE_DEVQ,
1256 PRINTER_ATTRIBUTE_KEEPPRINTEDJOBS,
1257 PRINTER_ATTRIBUTE_DO_COMPLETE_FIRST,
1258 PRINTER_ATTRIBUTE_WORK_OFFLINE,
1259 /* does not stick
1260 PRINTER_ATTRIBUTE_ENABLE_BIDI, */
1261 /* fails with WERR_INVALID_DATATYPE:
1262 PRINTER_ATTRIBUTE_RAW_ONLY, */
1263 /* these do not stick
1264 PRINTER_ATTRIBUTE_PUBLISHED,
1265 PRINTER_ATTRIBUTE_FAX,
1266 PRINTER_ATTRIBUTE_TS,
1267 0x00010000,
1268 0x00020000,
1269 0x00040000,
1270 0x00080000,
1271 0x00100000,
1272 0x00200000,
1273 0x00400000,
1274 0x00800000,
1275 0x01000000,
1276 0x02000000,
1277 0x04000000,
1278 0x08000000,
1279 0x10000000,
1280 0x20000000,
1281 0x40000000,
1282 0x80000000 */
1285 ZERO_STRUCT(devmode_ctr);
1286 ZERO_STRUCT(secdesc_ctr);
1288 s.in.handle = handle;
1289 s.in.command = 0;
1290 s.in.info_ctr = &info_ctr;
1291 s.in.devmode_ctr = &devmode_ctr;
1292 s.in.secdesc_ctr = &secdesc_ctr;
1294 q.in.handle = handle;
1295 q.out.info = &info;
1296 q0 = q;
1298 #define TESTGETCALL(call, r) \
1299 r.in.buffer = NULL; \
1300 r.in.offered = 0;\
1301 r.out.needed = &needed; \
1302 status = dcerpc_spoolss_ ##call## _r(b, tctx, &r); \
1303 if (!NT_STATUS_IS_OK(status)) { \
1304 torture_comment(tctx, #call " level %u failed - %s (%s)\n", \
1305 r.in.level, nt_errstr(status), __location__); \
1306 ret = false; \
1307 break; \
1309 if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {\
1310 DATA_BLOB blob = data_blob_talloc_zero(tctx, needed); \
1311 r.in.buffer = &blob; \
1312 r.in.offered = needed; \
1314 status = dcerpc_spoolss_ ##call## _r(b, tctx, &r); \
1315 if (!NT_STATUS_IS_OK(status)) { \
1316 torture_comment(tctx, #call " level %u failed - %s (%s)\n", \
1317 r.in.level, nt_errstr(status), __location__); \
1318 ret = false; \
1319 break; \
1321 if (!W_ERROR_IS_OK(r.out.result)) { \
1322 torture_comment(tctx, #call " level %u failed - %s (%s)\n", \
1323 r.in.level, win_errstr(r.out.result), __location__); \
1324 ret = false; \
1325 break; \
1329 #define TESTSETCALL_EXP(call, r, err) \
1330 clear_info2(&info_ctr);\
1331 status = dcerpc_spoolss_ ##call## _r(b, tctx, &r); \
1332 if (!NT_STATUS_IS_OK(status)) { \
1333 torture_comment(tctx, #call " level %u failed - %s (%s)\n", \
1334 r.in.info_ctr->level, nt_errstr(status), __location__); \
1335 ret = false; \
1336 break; \
1338 if (!W_ERROR_IS_OK(err)) { \
1339 if (!W_ERROR_EQUAL(err, r.out.result)) { \
1340 torture_comment(tctx, #call " level %u failed - %s, expected %s (%s)\n", \
1341 r.in.info_ctr->level, win_errstr(r.out.result), win_errstr(err), __location__); \
1342 ret = false; \
1344 break; \
1346 if (!W_ERROR_IS_OK(r.out.result)) { \
1347 torture_comment(tctx, #call " level %u failed - %s (%s)\n", \
1348 r.in.info_ctr->level, win_errstr(r.out.result), __location__); \
1349 ret = false; \
1350 break; \
1353 #define TESTSETCALL(call, r) \
1354 TESTSETCALL_EXP(call, r, WERR_OK)
1356 #define STRING_EQUAL(s1, s2, field) \
1357 if ((s1 && !s2) || (s2 && !s1) || strcmp(s1, s2)) { \
1358 torture_comment(tctx, "Failed to set %s to '%s' (%s)\n", \
1359 #field, s2, __location__); \
1360 ret = false; \
1361 break; \
1364 #define MEM_EQUAL(s1, s2, length, field) \
1365 if ((s1 && !s2) || (s2 && !s1) || memcmp(s1, s2, length)) { \
1366 torture_comment(tctx, "Failed to set %s to '%s' (%s)\n", \
1367 #field, (const char *)s2, __location__); \
1368 ret = false; \
1369 break; \
1372 #define INT_EQUAL(i1, i2, field) \
1373 if (i1 != i2) { \
1374 torture_comment(tctx, "Failed to set %s to 0x%llx - got 0x%llx (%s)\n", \
1375 #field, (unsigned long long)i2, (unsigned long long)i1, __location__); \
1376 ret = false; \
1377 break; \
1380 #define SD_EQUAL(sd1, sd2, field) \
1381 if (!security_descriptor_equal(sd1, sd2)) { \
1382 torture_comment(tctx, "Failed to set %s (%s)\n", \
1383 #field, __location__); \
1384 ret = false; \
1385 break; \
1388 #define TEST_PRINTERINFO_STRING_EXP_ERR(lvl1, field1, lvl2, field2, value, err) do { \
1389 torture_comment(tctx, "field test %d/%s vs %d/%s\n", lvl1, #field1, lvl2, #field2); \
1390 q.in.level = lvl1; \
1391 TESTGETCALL(GetPrinter, q) \
1392 info_ctr.level = lvl1; \
1393 info_ctr.info.info ## lvl1 = (struct spoolss_SetPrinterInfo ## lvl1 *)(void *)&q.out.info->info ## lvl1; \
1394 info_ctr.info.info ## lvl1->field1 = value;\
1395 TESTSETCALL_EXP(SetPrinter, s, err) \
1396 info_ctr.info.info ## lvl1->field1 = ""; \
1397 TESTGETCALL(GetPrinter, q) \
1398 info_ctr.info.info ## lvl1->field1 = value; \
1399 STRING_EQUAL(info_ctr.info.info ## lvl1->field1, value, field1); \
1400 q.in.level = lvl2; \
1401 TESTGETCALL(GetPrinter, q) \
1402 info_ctr.info.info ## lvl2 = (struct spoolss_SetPrinterInfo ## lvl2 *)(void *)&q.out.info->info ## lvl2; \
1403 STRING_EQUAL(info_ctr.info.info ## lvl2->field2, value, field2); \
1404 } while (0)
1406 #define TEST_PRINTERINFO_STRING(lvl1, field1, lvl2, field2, value) do { \
1407 TEST_PRINTERINFO_STRING_EXP_ERR(lvl1, field1, lvl2, field2, value, WERR_OK); \
1408 } while (0);
1410 #define TEST_PRINTERINFO_INT_EXP(lvl1, field1, lvl2, field2, value, exp_value) do { \
1411 torture_comment(tctx, "field test %d/%s vs %d/%s\n", lvl1, #field1, lvl2, #field2); \
1412 q.in.level = lvl1; \
1413 TESTGETCALL(GetPrinter, q) \
1414 info_ctr.level = lvl1; \
1415 info_ctr.info.info ## lvl1 = (struct spoolss_SetPrinterInfo ## lvl1 *)(void *)&q.out.info->info ## lvl1; \
1416 info_ctr.info.info ## lvl1->field1 = value; \
1417 TESTSETCALL(SetPrinter, s) \
1418 info_ctr.info.info ## lvl1->field1 = 0; \
1419 TESTGETCALL(GetPrinter, q) \
1420 info_ctr.info.info ## lvl1 = (struct spoolss_SetPrinterInfo ## lvl1 *)(void *)&q.out.info->info ## lvl1; \
1421 INT_EQUAL(info_ctr.info.info ## lvl1->field1, exp_value, field1); \
1422 q.in.level = lvl2; \
1423 TESTGETCALL(GetPrinter, q) \
1424 info_ctr.info.info ## lvl2 = (struct spoolss_SetPrinterInfo ## lvl2 *)(void *)&q.out.info->info ## lvl2; \
1425 INT_EQUAL(info_ctr.info.info ## lvl2->field2, exp_value, field1); \
1426 } while (0)
1428 #define TEST_PRINTERINFO_INT(lvl1, field1, lvl2, field2, value) do { \
1429 TEST_PRINTERINFO_INT_EXP(lvl1, field1, lvl2, field2, value, value); \
1430 } while (0)
1432 q0.in.level = 0;
1433 do { TESTGETCALL(GetPrinter, q0) } while (0);
1435 TEST_PRINTERINFO_STRING(2, comment, 1, comment, "xx2-1 comment");
1436 TEST_PRINTERINFO_STRING(2, comment, 2, comment, "xx2-2 comment");
1438 /* level 0 printername does not stick */
1439 /* TEST_PRINTERINFO_STRING(2, printername, 0, printername, "xx2-0 printer"); */
1440 TEST_PRINTERINFO_STRING(2, printername, 1, name, "xx2-1 printer");
1441 TEST_PRINTERINFO_STRING(2, printername, 2, printername, "xx2-2 printer");
1442 TEST_PRINTERINFO_STRING(2, printername, 4, printername, "xx2-4 printer");
1443 TEST_PRINTERINFO_STRING(2, printername, 5, printername, "xx2-5 printer");
1444 /* TEST_PRINTERINFO_STRING(4, printername, 0, printername, "xx4-0 printer"); */
1445 TEST_PRINTERINFO_STRING(4, printername, 1, name, "xx4-1 printer");
1446 TEST_PRINTERINFO_STRING(4, printername, 2, printername, "xx4-2 printer");
1447 TEST_PRINTERINFO_STRING(4, printername, 4, printername, "xx4-4 printer");
1448 TEST_PRINTERINFO_STRING(4, printername, 5, printername, "xx4-5 printer");
1449 /* TEST_PRINTERINFO_STRING(5, printername, 0, printername, "xx5-0 printer"); */
1450 TEST_PRINTERINFO_STRING(5, printername, 1, name, "xx5-1 printer");
1451 TEST_PRINTERINFO_STRING(5, printername, 2, printername, "xx5-2 printer");
1452 TEST_PRINTERINFO_STRING(5, printername, 4, printername, "xx5-4 printer");
1453 TEST_PRINTERINFO_STRING(5, printername, 5, printername, "xx5-5 printer");
1455 /* servername can be set but does not stick
1456 TEST_PRINTERINFO_STRING(2, servername, 0, servername, "xx2-0 servername");
1457 TEST_PRINTERINFO_STRING(2, servername, 2, servername, "xx2-2 servername");
1458 TEST_PRINTERINFO_STRING(2, servername, 4, servername, "xx2-4 servername");
1461 /* passing an invalid port will result in WERR_UNKNOWN_PORT */
1462 TEST_PRINTERINFO_STRING_EXP_ERR(2, portname, 2, portname, "xx2-2 portname", WERR_UNKNOWN_PORT);
1463 TEST_PRINTERINFO_STRING_EXP_ERR(2, portname, 5, portname, "xx2-5 portname", WERR_UNKNOWN_PORT);
1464 TEST_PRINTERINFO_STRING_EXP_ERR(5, portname, 2, portname, "xx5-2 portname", WERR_UNKNOWN_PORT);
1465 TEST_PRINTERINFO_STRING_EXP_ERR(5, portname, 5, portname, "xx5-5 portname", WERR_UNKNOWN_PORT);
1467 TEST_PRINTERINFO_STRING(2, sharename, 2, sharename, "xx2-2 sharename");
1468 /* passing an invalid driver will result in WERR_UNKNOWN_PRINTER_DRIVER */
1469 TEST_PRINTERINFO_STRING_EXP_ERR(2, drivername, 2, drivername, "xx2-2 drivername", WERR_UNKNOWN_PRINTER_DRIVER);
1470 TEST_PRINTERINFO_STRING(2, location, 2, location, "xx2-2 location");
1471 /* passing an invalid sepfile will result in WERR_INVALID_SEPARATOR_FILE */
1472 TEST_PRINTERINFO_STRING_EXP_ERR(2, sepfile, 2, sepfile, "xx2-2 sepfile", WERR_INVALID_SEPARATOR_FILE);
1473 /* passing an invalid printprocessor will result in WERR_UNKNOWN_PRINTPROCESSOR */
1474 TEST_PRINTERINFO_STRING_EXP_ERR(2, printprocessor, 2, printprocessor, "xx2-2 printprocessor", WERR_UNKNOWN_PRINTPROCESSOR);
1475 TEST_PRINTERINFO_STRING(2, datatype, 2, datatype, "xx2-2 datatype");
1476 TEST_PRINTERINFO_STRING(2, parameters, 2, parameters, "xx2-2 parameters");
1478 for (i=0; i < ARRAY_SIZE(attribute_list); i++) {
1479 /* TEST_PRINTERINFO_INT_EXP(2, attributes, 1, flags,
1480 attribute_list[i],
1481 (attribute_list[i] | default_attribute)
1482 ); */
1483 TEST_PRINTERINFO_INT_EXP(2, attributes, 2, attributes,
1484 attribute_list[i],
1485 (attribute_list[i] | default_attribute)
1487 TEST_PRINTERINFO_INT_EXP(2, attributes, 4, attributes,
1488 attribute_list[i],
1489 (attribute_list[i] | default_attribute)
1491 TEST_PRINTERINFO_INT_EXP(2, attributes, 5, attributes,
1492 attribute_list[i],
1493 (attribute_list[i] | default_attribute)
1495 /* TEST_PRINTERINFO_INT_EXP(4, attributes, 1, flags,
1496 attribute_list[i],
1497 (attribute_list[i] | default_attribute)
1498 ); */
1499 TEST_PRINTERINFO_INT_EXP(4, attributes, 2, attributes,
1500 attribute_list[i],
1501 (attribute_list[i] | default_attribute)
1503 TEST_PRINTERINFO_INT_EXP(4, attributes, 4, attributes,
1504 attribute_list[i],
1505 (attribute_list[i] | default_attribute)
1507 TEST_PRINTERINFO_INT_EXP(4, attributes, 5, attributes,
1508 attribute_list[i],
1509 (attribute_list[i] | default_attribute)
1511 /* TEST_PRINTERINFO_INT_EXP(5, attributes, 1, flags,
1512 attribute_list[i],
1513 (attribute_list[i] | default_attribute)
1514 ); */
1515 TEST_PRINTERINFO_INT_EXP(5, attributes, 2, attributes,
1516 attribute_list[i],
1517 (attribute_list[i] | default_attribute)
1519 TEST_PRINTERINFO_INT_EXP(5, attributes, 4, attributes,
1520 attribute_list[i],
1521 (attribute_list[i] | default_attribute)
1523 TEST_PRINTERINFO_INT_EXP(5, attributes, 5, attributes,
1524 attribute_list[i],
1525 (attribute_list[i] | default_attribute)
1529 for (i=0; i < ARRAY_SIZE(status_list); i++) {
1530 /* level 2 sets do not stick
1531 TEST_PRINTERINFO_INT(2, status, 0, status, status_list[i]);
1532 TEST_PRINTERINFO_INT(2, status, 2, status, status_list[i]);
1533 TEST_PRINTERINFO_INT(2, status, 6, status, status_list[i]); */
1534 TEST_PRINTERINFO_INT(6, status, 0, status, status_list[i]);
1535 TEST_PRINTERINFO_INT(6, status, 2, status, status_list[i]);
1536 TEST_PRINTERINFO_INT(6, status, 6, status, status_list[i]);
1539 /* priorities need to be between 0 and 99
1540 passing an invalid priority will result in WERR_INVALID_PRIORITY */
1541 TEST_PRINTERINFO_INT(2, priority, 2, priority, 0);
1542 TEST_PRINTERINFO_INT(2, priority, 2, priority, 1);
1543 TEST_PRINTERINFO_INT(2, priority, 2, priority, 99);
1544 /* TEST_PRINTERINFO_INT(2, priority, 2, priority, 100); */
1545 TEST_PRINTERINFO_INT(2, defaultpriority,2, defaultpriority, 0);
1546 TEST_PRINTERINFO_INT(2, defaultpriority,2, defaultpriority, 1);
1547 TEST_PRINTERINFO_INT(2, defaultpriority,2, defaultpriority, 99);
1548 /* TEST_PRINTERINFO_INT(2, defaultpriority,2, defaultpriority, 100); */
1550 TEST_PRINTERINFO_INT(2, starttime, 2, starttime, __LINE__);
1551 TEST_PRINTERINFO_INT(2, untiltime, 2, untiltime, __LINE__);
1553 /* does not stick
1554 TEST_PRINTERINFO_INT(2, cjobs, 2, cjobs, __LINE__);
1555 TEST_PRINTERINFO_INT(2, averageppm, 2, averageppm, __LINE__); */
1557 /* does not stick
1558 TEST_PRINTERINFO_INT(5, device_not_selected_timeout, 5, device_not_selected_timeout, __LINE__);
1559 TEST_PRINTERINFO_INT(5, transmission_retry_timeout, 5, transmission_retry_timeout, __LINE__); */
1561 /* FIXME: gd also test devmode and secdesc behavior */
1564 /* verify composition of level 1 description field */
1565 const char *description;
1566 const char *tmp;
1568 q0.in.level = 1;
1569 do { TESTGETCALL(GetPrinter, q0) } while (0);
1571 description = talloc_strdup(tctx, q0.out.info->info1.description);
1573 q0.in.level = 2;
1574 do { TESTGETCALL(GetPrinter, q0) } while (0);
1576 tmp = talloc_asprintf(tctx, "%s,%s,%s",
1577 q0.out.info->info2.printername,
1578 q0.out.info->info2.drivername,
1579 q0.out.info->info2.location);
1581 do { STRING_EQUAL(description, tmp, "description")} while (0);
1584 return ret;
1587 #define torture_assert_sid_equal(torture_ctx,got,expected,cmt)\
1588 do { struct dom_sid *__got = (got), *__expected = (expected); \
1589 if (!dom_sid_equal(__got, __expected)) { \
1590 torture_result(torture_ctx, TORTURE_FAIL, \
1591 __location__": "#got" was %s, expected %s: %s", \
1592 dom_sid_string(torture_ctx, __got), dom_sid_string(torture_ctx, __expected), cmt); \
1593 return false; \
1595 } while(0)
1597 static bool test_security_descriptor_equal(struct torture_context *tctx,
1598 const struct security_descriptor *sd1,
1599 const struct security_descriptor *sd2)
1601 if (sd1 == sd2) {
1602 return true;
1605 if (!sd1 || !sd2) {
1606 torture_comment(tctx, "%s\n", __location__);
1607 return false;
1610 torture_assert_int_equal(tctx, sd1->revision, sd2->revision, "revision mismatch");
1611 torture_assert_int_equal(tctx, sd1->type, sd2->type, "type mismatch");
1613 torture_assert_sid_equal(tctx, sd1->owner_sid, sd2->owner_sid, "owner mismatch");
1614 torture_assert_sid_equal(tctx, sd1->group_sid, sd2->group_sid, "group mismatch");
1616 if (!security_acl_equal(sd1->sacl, sd2->sacl)) {
1617 torture_comment(tctx, "%s: sacl mismatch\n", __location__);
1618 NDR_PRINT_DEBUG(security_acl, sd1->sacl);
1619 NDR_PRINT_DEBUG(security_acl, sd2->sacl);
1620 return false;
1622 if (!security_acl_equal(sd1->dacl, sd2->dacl)) {
1623 torture_comment(tctx, "%s: dacl mismatch\n", __location__);
1624 NDR_PRINT_DEBUG(security_acl, sd1->dacl);
1625 NDR_PRINT_DEBUG(security_acl, sd2->dacl);
1626 return false;
1629 return true;
1632 static bool test_sd_set_level(struct torture_context *tctx,
1633 struct dcerpc_binding_handle *b,
1634 struct policy_handle *handle,
1635 uint32_t level,
1636 struct security_descriptor *sd)
1638 struct spoolss_SetPrinterInfoCtr info_ctr;
1639 struct spoolss_DevmodeContainer devmode_ctr;
1640 struct sec_desc_buf secdesc_ctr;
1641 union spoolss_SetPrinterInfo sinfo;
1643 ZERO_STRUCT(devmode_ctr);
1644 ZERO_STRUCT(secdesc_ctr);
1646 switch (level) {
1647 case 2: {
1648 union spoolss_PrinterInfo info;
1649 torture_assert(tctx, test_GetPrinter_level(tctx, b, handle, 2, &info), "");
1650 torture_assert(tctx, PrinterInfo_to_SetPrinterInfo(tctx, &info, 2, &sinfo), "");
1652 info_ctr.level = 2;
1653 info_ctr.info = sinfo;
1655 break;
1657 case 3: {
1658 struct spoolss_SetPrinterInfo3 info3;
1660 info3.sec_desc_ptr = 0;
1662 info_ctr.level = 3;
1663 info_ctr.info.info3 = &info3;
1665 break;
1667 default:
1668 return false;
1671 secdesc_ctr.sd = sd;
1673 torture_assert(tctx,
1674 test_SetPrinter(tctx, b, handle, &info_ctr, &devmode_ctr, &secdesc_ctr, 0), "");
1676 return true;
1679 static bool test_PrinterInfo_SDs(struct torture_context *tctx,
1680 struct dcerpc_binding_handle *b,
1681 struct policy_handle *handle)
1683 union spoolss_PrinterInfo info;
1684 struct security_descriptor *sd1, *sd2;
1685 int i;
1687 /* just compare level 2 and level 3 */
1689 torture_assert(tctx, test_GetPrinter_level(tctx, b, handle, 2, &info), "");
1691 sd1 = info.info2.secdesc;
1693 torture_assert(tctx, test_GetPrinter_level(tctx, b, handle, 3, &info), "");
1695 sd2 = info.info3.secdesc;
1697 torture_assert(tctx, test_security_descriptor_equal(tctx, sd1, sd2),
1698 "SD level 2 != SD level 3");
1701 /* query level 2, set level 2, query level 2 */
1703 torture_assert(tctx, test_GetPrinter_level(tctx, b, handle, 2, &info), "");
1705 sd1 = info.info2.secdesc;
1707 torture_assert(tctx, test_sd_set_level(tctx, b, handle, 2, sd1), "");
1709 torture_assert(tctx, test_GetPrinter_level(tctx, b, handle, 2, &info), "");
1711 sd2 = info.info2.secdesc;
1712 if (sd1->type & SEC_DESC_DACL_DEFAULTED) {
1713 torture_comment(tctx, "removing SEC_DESC_DACL_DEFAULTED\n");
1714 sd1->type &= ~SEC_DESC_DACL_DEFAULTED;
1717 torture_assert(tctx, test_security_descriptor_equal(tctx, sd1, sd2),
1718 "SD level 2 != SD level 2 after SD has been set via level 2");
1721 /* query level 2, set level 3, query level 2 */
1723 torture_assert(tctx, test_GetPrinter_level(tctx, b, handle, 2, &info), "");
1725 sd1 = info.info2.secdesc;
1727 torture_assert(tctx, test_sd_set_level(tctx, b, handle, 3, sd1), "");
1729 torture_assert(tctx, test_GetPrinter_level(tctx, b, handle, 2, &info), "");
1731 sd2 = info.info2.secdesc;
1733 torture_assert(tctx, test_security_descriptor_equal(tctx, sd1, sd2),
1734 "SD level 2 != SD level 2 after SD has been set via level 3");
1736 /* set modified sd level 3, query level 2 */
1738 for (i=0; i < 93; i++) {
1739 struct security_ace a;
1740 const char *sid_string = talloc_asprintf(tctx, "S-1-5-32-9999%i", i);
1741 a.type = SEC_ACE_TYPE_ACCESS_ALLOWED;
1742 a.flags = 0;
1743 a.size = 0; /* autogenerated */
1744 a.access_mask = 0;
1745 a.trustee = *dom_sid_parse_talloc(tctx, sid_string);
1746 torture_assert_ntstatus_ok(tctx, security_descriptor_dacl_add(sd1, &a), "");
1749 torture_assert(tctx, test_sd_set_level(tctx, b, handle, 3, sd1), "");
1751 torture_assert(tctx, test_GetPrinter_level(tctx, b, handle, 2, &info), "");
1752 sd2 = info.info2.secdesc;
1754 if (sd1->type & SEC_DESC_DACL_DEFAULTED) {
1755 torture_comment(tctx, "removing SEC_DESC_DACL_DEFAULTED\n");
1756 sd1->type &= ~SEC_DESC_DACL_DEFAULTED;
1759 torture_assert(tctx, test_security_descriptor_equal(tctx, sd1, sd2),
1760 "modified SD level 2 != SD level 2 after SD has been set via level 3");
1763 return true;
1767 * wrapper call that saves original sd, runs tests, and restores sd
1770 static bool test_PrinterInfo_SD(struct torture_context *tctx,
1771 struct dcerpc_binding_handle *b,
1772 struct policy_handle *handle)
1774 union spoolss_PrinterInfo info;
1775 struct security_descriptor *sd;
1776 bool ret = true;
1778 torture_comment(tctx, "Testing Printer Security Descriptors\n");
1780 /* save original sd */
1782 torture_assert(tctx, test_GetPrinter_level(tctx, b, handle, 2, &info),
1783 "failed to get initial security descriptor");
1785 sd = security_descriptor_copy(tctx, info.info2.secdesc);
1787 /* run tests */
1789 ret = test_PrinterInfo_SDs(tctx, b, handle);
1791 /* restore original sd */
1793 torture_assert(tctx, test_sd_set_level(tctx, b, handle, 3, sd),
1794 "failed to restore initial security descriptor");
1796 torture_comment(tctx, "Printer Security Descriptors test %s\n\n",
1797 ret ? "succeeded" : "failed");
1800 return ret;
1803 static bool test_devmode_set_level(struct torture_context *tctx,
1804 struct dcerpc_binding_handle *b,
1805 struct policy_handle *handle,
1806 uint32_t level,
1807 struct spoolss_DeviceMode *devmode)
1809 struct spoolss_SetPrinterInfoCtr info_ctr;
1810 struct spoolss_DevmodeContainer devmode_ctr;
1811 struct sec_desc_buf secdesc_ctr;
1812 union spoolss_SetPrinterInfo sinfo;
1814 ZERO_STRUCT(devmode_ctr);
1815 ZERO_STRUCT(secdesc_ctr);
1817 switch (level) {
1818 case 2: {
1819 union spoolss_PrinterInfo info;
1820 torture_assert(tctx, test_GetPrinter_level(tctx, b, handle, 2, &info), "");
1821 torture_assert(tctx, PrinterInfo_to_SetPrinterInfo(tctx, &info, 2, &sinfo), "");
1823 info_ctr.level = 2;
1824 info_ctr.info = sinfo;
1826 break;
1828 case 8: {
1829 struct spoolss_SetPrinterInfo8 info8;
1831 info8.devmode_ptr = 0;
1833 info_ctr.level = 8;
1834 info_ctr.info.info8 = &info8;
1836 break;
1838 default:
1839 return false;
1842 devmode_ctr.devmode = devmode;
1844 torture_assert(tctx,
1845 test_SetPrinter(tctx, b, handle, &info_ctr, &devmode_ctr, &secdesc_ctr, 0), "");
1847 return true;
1851 static bool test_devicemode_equal(struct torture_context *tctx,
1852 const struct spoolss_DeviceMode *d1,
1853 const struct spoolss_DeviceMode *d2)
1855 if (d1 == d2) {
1856 return true;
1859 if (!d1 || !d2) {
1860 torture_comment(tctx, "%s\n", __location__);
1861 return false;
1863 torture_assert_str_equal(tctx, d1->devicename, d2->devicename, "devicename mismatch");
1864 torture_assert_int_equal(tctx, d1->specversion, d2->specversion, "specversion mismatch");
1865 torture_assert_int_equal(tctx, d1->driverversion, d2->driverversion, "driverversion mismatch");
1866 torture_assert_int_equal(tctx, d1->size, d2->size, "size mismatch");
1867 torture_assert_int_equal(tctx, d1->__driverextra_length, d2->__driverextra_length, "__driverextra_length mismatch");
1868 torture_assert_int_equal(tctx, d1->fields, d2->fields, "fields mismatch");
1869 torture_assert_int_equal(tctx, d1->orientation, d2->orientation, "orientation mismatch");
1870 torture_assert_int_equal(tctx, d1->papersize, d2->papersize, "papersize mismatch");
1871 torture_assert_int_equal(tctx, d1->paperlength, d2->paperlength, "paperlength mismatch");
1872 torture_assert_int_equal(tctx, d1->paperwidth, d2->paperwidth, "paperwidth mismatch");
1873 torture_assert_int_equal(tctx, d1->scale, d2->scale, "scale mismatch");
1874 torture_assert_int_equal(tctx, d1->copies, d2->copies, "copies mismatch");
1875 torture_assert_int_equal(tctx, d1->defaultsource, d2->defaultsource, "defaultsource mismatch");
1876 torture_assert_int_equal(tctx, d1->printquality, d2->printquality, "printquality mismatch");
1877 torture_assert_int_equal(tctx, d1->color, d2->color, "color mismatch");
1878 torture_assert_int_equal(tctx, d1->duplex, d2->duplex, "duplex mismatch");
1879 torture_assert_int_equal(tctx, d1->yresolution, d2->yresolution, "yresolution mismatch");
1880 torture_assert_int_equal(tctx, d1->ttoption, d2->ttoption, "ttoption mismatch");
1881 torture_assert_int_equal(tctx, d1->collate, d2->collate, "collate mismatch");
1882 torture_assert_str_equal(tctx, d1->formname, d2->formname, "formname mismatch");
1883 torture_assert_int_equal(tctx, d1->logpixels, d2->logpixels, "logpixels mismatch");
1884 torture_assert_int_equal(tctx, d1->bitsperpel, d2->bitsperpel, "bitsperpel mismatch");
1885 torture_assert_int_equal(tctx, d1->pelswidth, d2->pelswidth, "pelswidth mismatch");
1886 torture_assert_int_equal(tctx, d1->pelsheight, d2->pelsheight, "pelsheight mismatch");
1887 torture_assert_int_equal(tctx, d1->displayflags, d2->displayflags, "displayflags mismatch");
1888 torture_assert_int_equal(tctx, d1->displayfrequency, d2->displayfrequency, "displayfrequency mismatch");
1889 torture_assert_int_equal(tctx, d1->icmmethod, d2->icmmethod, "icmmethod mismatch");
1890 torture_assert_int_equal(tctx, d1->icmintent, d2->icmintent, "icmintent mismatch");
1891 torture_assert_int_equal(tctx, d1->mediatype, d2->mediatype, "mediatype mismatch");
1892 torture_assert_int_equal(tctx, d1->dithertype, d2->dithertype, "dithertype mismatch");
1893 torture_assert_int_equal(tctx, d1->reserved1, d2->reserved1, "reserved1 mismatch");
1894 torture_assert_int_equal(tctx, d1->reserved2, d2->reserved2, "reserved2 mismatch");
1895 torture_assert_int_equal(tctx, d1->panningwidth, d2->panningwidth, "panningwidth mismatch");
1896 torture_assert_int_equal(tctx, d1->panningheight, d2->panningheight, "panningheight mismatch");
1897 torture_assert_data_blob_equal(tctx, d1->driverextra_data, d2->driverextra_data, "driverextra_data mismatch");
1899 return true;
1902 static bool test_devicemode_full(struct torture_context *tctx,
1903 struct dcerpc_binding_handle *b,
1904 struct policy_handle *handle)
1906 struct spoolss_SetPrinter s;
1907 struct spoolss_GetPrinter q;
1908 struct spoolss_GetPrinter q0;
1909 struct spoolss_SetPrinterInfoCtr info_ctr;
1910 struct spoolss_SetPrinterInfo8 info8;
1911 union spoolss_PrinterInfo info;
1912 struct spoolss_DevmodeContainer devmode_ctr;
1913 struct sec_desc_buf secdesc_ctr;
1914 uint32_t needed;
1915 bool ret = true;
1916 NTSTATUS status;
1918 #define TEST_DEVMODE_INT_EXP(lvl1, field1, lvl2, field2, value, exp_value) do { \
1919 torture_comment(tctx, "field test %d/%s vs %d/%s\n", lvl1, #field1, lvl2, #field2); \
1920 q.in.level = lvl1; \
1921 TESTGETCALL(GetPrinter, q) \
1922 info_ctr.level = lvl1; \
1923 if (lvl1 == 2) {\
1924 info_ctr.info.info ## lvl1 = (struct spoolss_SetPrinterInfo ## lvl1 *)(void *)&q.out.info->info ## lvl1; \
1925 } else if (lvl1 == 8) {\
1926 info_ctr.info.info ## lvl1 = &info8; \
1928 devmode_ctr.devmode = q.out.info->info ## lvl1.devmode; \
1929 devmode_ctr.devmode->field1 = value; \
1930 TESTSETCALL(SetPrinter, s) \
1931 TESTGETCALL(GetPrinter, q) \
1932 INT_EQUAL(q.out.info->info ## lvl1.devmode->field1, exp_value, field1); \
1933 q.in.level = lvl2; \
1934 TESTGETCALL(GetPrinter, q) \
1935 INT_EQUAL(q.out.info->info ## lvl2.devmode->field2, exp_value, field1); \
1936 } while (0)
1938 #define TEST_DEVMODE_INT(lvl1, field1, lvl2, field2, value) do { \
1939 TEST_DEVMODE_INT_EXP(lvl1, field1, lvl2, field2, value, value); \
1940 } while (0)
1942 ZERO_STRUCT(devmode_ctr);
1943 ZERO_STRUCT(secdesc_ctr);
1944 ZERO_STRUCT(info8);
1946 s.in.handle = handle;
1947 s.in.command = 0;
1948 s.in.info_ctr = &info_ctr;
1949 s.in.devmode_ctr = &devmode_ctr;
1950 s.in.secdesc_ctr = &secdesc_ctr;
1952 q.in.handle = handle;
1953 q.out.info = &info;
1954 q0 = q;
1956 #if 0
1957 const char *devicename;/* [charset(UTF16)] */
1958 enum spoolss_DeviceModeSpecVersion specversion;
1959 uint16_t driverversion;
1960 uint16_t size;
1961 uint16_t __driverextra_length;/* [value(r->driverextra_data.length)] */
1962 uint32_t fields;
1963 #endif
1965 TEST_DEVMODE_INT(8, orientation, 8, orientation, __LINE__);
1966 TEST_DEVMODE_INT(8, papersize, 8, papersize, __LINE__);
1967 TEST_DEVMODE_INT(8, paperlength, 8, paperlength, __LINE__);
1968 TEST_DEVMODE_INT(8, paperwidth, 8, paperwidth, __LINE__);
1969 TEST_DEVMODE_INT(8, scale, 8, scale, __LINE__);
1970 TEST_DEVMODE_INT(8, copies, 8, copies, __LINE__);
1971 TEST_DEVMODE_INT(8, defaultsource, 8, defaultsource, __LINE__);
1972 TEST_DEVMODE_INT(8, printquality, 8, printquality, __LINE__);
1973 TEST_DEVMODE_INT(8, color, 8, color, __LINE__);
1974 TEST_DEVMODE_INT(8, duplex, 8, duplex, __LINE__);
1975 TEST_DEVMODE_INT(8, yresolution, 8, yresolution, __LINE__);
1976 TEST_DEVMODE_INT(8, ttoption, 8, ttoption, __LINE__);
1977 TEST_DEVMODE_INT(8, collate, 8, collate, __LINE__);
1978 #if 0
1979 const char *formname;/* [charset(UTF16)] */
1980 #endif
1981 TEST_DEVMODE_INT(8, logpixels, 8, logpixels, __LINE__);
1982 TEST_DEVMODE_INT(8, bitsperpel, 8, bitsperpel, __LINE__);
1983 TEST_DEVMODE_INT(8, pelswidth, 8, pelswidth, __LINE__);
1984 TEST_DEVMODE_INT(8, pelsheight, 8, pelsheight, __LINE__);
1985 TEST_DEVMODE_INT(8, displayflags, 8, displayflags, __LINE__);
1986 TEST_DEVMODE_INT(8, displayfrequency, 8, displayfrequency, __LINE__);
1987 TEST_DEVMODE_INT(8, icmmethod, 8, icmmethod, __LINE__);
1988 TEST_DEVMODE_INT(8, icmintent, 8, icmintent, __LINE__);
1989 TEST_DEVMODE_INT(8, mediatype, 8, mediatype, __LINE__);
1990 TEST_DEVMODE_INT(8, dithertype, 8, dithertype, __LINE__);
1991 TEST_DEVMODE_INT(8, reserved1, 8, reserved1, __LINE__);
1992 TEST_DEVMODE_INT(8, reserved2, 8, reserved2, __LINE__);
1993 TEST_DEVMODE_INT(8, panningwidth, 8, panningwidth, __LINE__);
1994 TEST_DEVMODE_INT(8, panningheight, 8, panningheight, __LINE__);
1996 return ret;
1999 static bool call_OpenPrinterEx(struct torture_context *tctx,
2000 struct dcerpc_pipe *p,
2001 const char *name,
2002 struct spoolss_DeviceMode *devmode,
2003 struct policy_handle *handle);
2005 static bool test_ClosePrinter(struct torture_context *tctx,
2006 struct dcerpc_binding_handle *b,
2007 struct policy_handle *handle);
2009 static bool test_PrinterInfo_DevModes(struct torture_context *tctx,
2010 struct dcerpc_pipe *p,
2011 struct policy_handle *handle,
2012 const char *name)
2014 union spoolss_PrinterInfo info;
2015 struct spoolss_DeviceMode *devmode;
2016 struct spoolss_DeviceMode *devmode2;
2017 struct policy_handle handle_devmode;
2018 struct dcerpc_binding_handle *b = p->binding_handle;
2020 /* simply compare level8 and level2 devmode */
2022 torture_assert(tctx, test_GetPrinter_level(tctx, b, handle, 8, &info), "");
2024 devmode = info.info8.devmode;
2026 torture_assert(tctx, test_GetPrinter_level(tctx, b, handle, 2, &info), "");
2028 devmode2 = info.info2.devmode;
2030 torture_assert(tctx, test_devicemode_equal(tctx, devmode, devmode2),
2031 "DM level 8 != DM level 2");
2034 /* set devicemode level 8 and see if it persists */
2036 devmode->copies = 93;
2037 devmode->formname = talloc_strdup(tctx, "Legal");
2039 torture_assert(tctx, test_devmode_set_level(tctx, b, handle, 8, devmode), "");
2041 torture_assert(tctx, test_GetPrinter_level(tctx, b, handle, 8, &info), "");
2043 devmode2 = info.info8.devmode;
2045 torture_assert(tctx, test_devicemode_equal(tctx, devmode, devmode2),
2046 "modified DM level 8 != DM level 8 after DM has been set via level 8");
2048 torture_assert(tctx, test_GetPrinter_level(tctx, b, handle, 2, &info), "");
2050 devmode2 = info.info2.devmode;
2052 torture_assert(tctx, test_devicemode_equal(tctx, devmode, devmode2),
2053 "modified DM level 8 != DM level 2");
2056 /* set devicemode level 2 and see if it persists */
2058 devmode->copies = 39;
2059 devmode->formname = talloc_strdup(tctx, "Executive");
2061 torture_assert(tctx, test_devmode_set_level(tctx, b, handle, 2, devmode), "");
2063 torture_assert(tctx, test_GetPrinter_level(tctx, b, handle, 8, &info), "");
2065 devmode2 = info.info8.devmode;
2067 torture_assert(tctx, test_devicemode_equal(tctx, devmode, devmode2),
2068 "modified DM level 8 != DM level 8 after DM has been set via level 2");
2070 torture_assert(tctx, test_GetPrinter_level(tctx, b, handle, 2, &info), "");
2072 devmode2 = info.info2.devmode;
2074 torture_assert(tctx, test_devicemode_equal(tctx, devmode, devmode2),
2075 "modified DM level 8 != DM level 2");
2078 /* check every single bit in public part of devicemode */
2080 torture_assert(tctx, test_devicemode_full(tctx, b, handle),
2081 "failed to set every single devicemode component");
2084 /* change formname upon open and see if it persists in getprinter calls */
2086 devmode->formname = talloc_strdup(tctx, "A4");
2087 devmode->copies = 42;
2089 torture_assert(tctx, call_OpenPrinterEx(tctx, p, name, devmode, &handle_devmode),
2090 "failed to open printer handle");
2092 torture_assert(tctx, test_GetPrinter_level(tctx, b, &handle_devmode, 8, &info), "");
2094 devmode2 = info.info8.devmode;
2096 if (strequal(devmode->devicename, devmode2->devicename)) {
2097 torture_warning(tctx, "devicenames are the same\n");
2098 } else {
2099 torture_comment(tctx, "devicename passed in for open: %s\n", devmode->devicename);
2100 torture_comment(tctx, "devicename after level 8 get: %s\n", devmode2->devicename);
2103 if (strequal(devmode->formname, devmode2->formname)) {
2104 torture_warning(tctx, "formname are the same\n");
2105 } else {
2106 torture_comment(tctx, "formname passed in for open: %s\n", devmode->formname);
2107 torture_comment(tctx, "formname after level 8 get: %s\n", devmode2->formname);
2110 if (devmode->copies == devmode2->copies) {
2111 torture_warning(tctx, "copies are the same\n");
2112 } else {
2113 torture_comment(tctx, "copies passed in for open: %d\n", devmode->copies);
2114 torture_comment(tctx, "copies after level 8 get: %d\n", devmode2->copies);
2117 torture_assert(tctx, test_GetPrinter_level(tctx, b, &handle_devmode, 2, &info), "");
2119 devmode2 = info.info2.devmode;
2121 if (strequal(devmode->devicename, devmode2->devicename)) {
2122 torture_warning(tctx, "devicenames are the same\n");
2123 } else {
2124 torture_comment(tctx, "devicename passed in for open: %s\n", devmode->devicename);
2125 torture_comment(tctx, "devicename after level 2 get: %s\n", devmode2->devicename);
2128 if (strequal(devmode->formname, devmode2->formname)) {
2129 torture_warning(tctx, "formname is the same\n");
2130 } else {
2131 torture_comment(tctx, "formname passed in for open: %s\n", devmode->formname);
2132 torture_comment(tctx, "formname after level 2 get: %s\n", devmode2->formname);
2135 if (devmode->copies == devmode2->copies) {
2136 torture_warning(tctx, "copies are the same\n");
2137 } else {
2138 torture_comment(tctx, "copies passed in for open: %d\n", devmode->copies);
2139 torture_comment(tctx, "copies after level 2 get: %d\n", devmode2->copies);
2142 test_ClosePrinter(tctx, b, &handle_devmode);
2144 return true;
2148 * wrapper call that saves original devmode, runs tests, and restores devmode
2151 static bool test_PrinterInfo_DevMode(struct torture_context *tctx,
2152 struct dcerpc_pipe *p,
2153 struct policy_handle *handle,
2154 const char *name)
2156 union spoolss_PrinterInfo info;
2157 struct spoolss_DeviceMode *devmode;
2158 bool ret = true;
2159 struct dcerpc_binding_handle *b = p->binding_handle;
2161 torture_comment(tctx, "Testing Printer Devicemodes\n");
2163 /* save original devmode */
2165 torture_assert(tctx, test_GetPrinter_level(tctx, b, handle, 8, &info),
2166 "failed to get initial global devicemode");
2168 devmode = info.info8.devmode;
2170 /* run tests */
2172 ret = test_PrinterInfo_DevModes(tctx, p, handle, name);
2174 /* restore original devmode */
2176 torture_assert(tctx, test_devmode_set_level(tctx, b, handle, 8, devmode),
2177 "failed to restore initial global device mode");
2179 torture_comment(tctx, "Printer Devicemodes test %s\n\n",
2180 ret ? "succeeded" : "failed");
2183 return ret;
2186 static bool test_ClosePrinter(struct torture_context *tctx,
2187 struct dcerpc_binding_handle *b,
2188 struct policy_handle *handle)
2190 NTSTATUS status;
2191 struct spoolss_ClosePrinter r;
2193 r.in.handle = handle;
2194 r.out.handle = handle;
2196 torture_comment(tctx, "Testing ClosePrinter\n");
2198 status = dcerpc_spoolss_ClosePrinter_r(b, tctx, &r);
2199 torture_assert_ntstatus_ok(tctx, status, "ClosePrinter failed");
2200 torture_assert_werr_ok(tctx, r.out.result, "ClosePrinter failed");
2202 return true;
2205 static bool test_GetForm_args(struct torture_context *tctx,
2206 struct dcerpc_binding_handle *b,
2207 struct policy_handle *handle,
2208 const char *form_name,
2209 uint32_t level,
2210 union spoolss_FormInfo *info_p)
2212 NTSTATUS status;
2213 struct spoolss_GetForm r;
2214 uint32_t needed;
2216 r.in.handle = handle;
2217 r.in.form_name = form_name;
2218 r.in.level = level;
2219 r.in.buffer = NULL;
2220 r.in.offered = 0;
2221 r.out.needed = &needed;
2223 torture_comment(tctx, "Testing GetForm(%s) level %d\n", form_name, r.in.level);
2225 status = dcerpc_spoolss_GetForm_r(b, tctx, &r);
2226 torture_assert_ntstatus_ok(tctx, status, "GetForm failed");
2228 if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
2229 DATA_BLOB blob = data_blob_talloc_zero(tctx, needed);
2230 r.in.buffer = &blob;
2231 r.in.offered = needed;
2232 status = dcerpc_spoolss_GetForm_r(b, tctx, &r);
2233 torture_assert_ntstatus_ok(tctx, status, "GetForm failed");
2235 torture_assert_werr_ok(tctx, r.out.result, "GetForm failed");
2237 torture_assert(tctx, r.out.info, "No form info returned");
2240 torture_assert_werr_ok(tctx, r.out.result, "GetForm failed");
2242 CHECK_NEEDED_SIZE_LEVEL(spoolss_FormInfo, r.out.info, r.in.level, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
2244 if (info_p) {
2245 *info_p = *r.out.info;
2248 return true;
2251 static bool test_GetForm(struct torture_context *tctx,
2252 struct dcerpc_binding_handle *b,
2253 struct policy_handle *handle,
2254 const char *form_name,
2255 uint32_t level)
2257 return test_GetForm_args(tctx, b, handle, form_name, level, NULL);
2260 static bool test_EnumForms(struct torture_context *tctx,
2261 struct dcerpc_binding_handle *b,
2262 struct policy_handle *handle,
2263 bool print_server,
2264 uint32_t level,
2265 uint32_t *count_p,
2266 union spoolss_FormInfo **info_p)
2268 struct spoolss_EnumForms r;
2269 uint32_t needed;
2270 uint32_t count;
2271 union spoolss_FormInfo *info;
2273 r.in.handle = handle;
2274 r.in.level = level;
2275 r.in.buffer = NULL;
2276 r.in.offered = 0;
2277 r.out.needed = &needed;
2278 r.out.count = &count;
2279 r.out.info = &info;
2281 torture_comment(tctx, "Testing EnumForms level %d\n", r.in.level);
2283 torture_assert_ntstatus_ok(tctx,
2284 dcerpc_spoolss_EnumForms_r(b, tctx, &r),
2285 "EnumForms failed");
2287 if ((r.in.level == 2) && (W_ERROR_EQUAL(r.out.result, WERR_UNKNOWN_LEVEL))) {
2288 torture_skip(tctx, "EnumForms level 2 not supported");
2291 if (print_server && W_ERROR_EQUAL(r.out.result, WERR_BADFID)) {
2292 torture_fail(tctx, "EnumForms on the PrintServer isn't supported by test server (NT4)");
2295 if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
2296 DATA_BLOB blob = data_blob_talloc_zero(tctx, needed);
2297 r.in.buffer = &blob;
2298 r.in.offered = needed;
2300 torture_assert_ntstatus_ok(tctx,
2301 dcerpc_spoolss_EnumForms_r(b, tctx, &r),
2302 "EnumForms failed");
2304 torture_assert(tctx, info, "No forms returned");
2307 torture_assert_werr_ok(tctx, r.out.result, "EnumForms failed");
2309 CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumForms, info, r.in.level, count, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
2311 if (info_p) {
2312 *info_p = info;
2314 if (count_p) {
2315 *count_p = count;
2318 return true;
2321 static bool test_EnumForms_all(struct torture_context *tctx,
2322 struct dcerpc_binding_handle *b,
2323 struct policy_handle *handle,
2324 bool print_server)
2326 uint32_t levels[] = { 1, 2 };
2327 int i, j;
2329 for (i=0; i<ARRAY_SIZE(levels); i++) {
2331 uint32_t count = 0;
2332 union spoolss_FormInfo *info = NULL;
2334 torture_assert(tctx,
2335 test_EnumForms(tctx, b, handle, print_server, levels[i], &count, &info),
2336 "failed to enum forms");
2338 for (j = 0; j < count; j++) {
2339 if (!print_server) {
2340 torture_assert(tctx,
2341 test_GetForm(tctx, b, handle, info[j].info1.form_name, levels[i]),
2342 "failed to get form");
2347 return true;
2350 static bool test_EnumForms_find_one(struct torture_context *tctx,
2351 struct dcerpc_binding_handle *b,
2352 struct policy_handle *handle,
2353 bool print_server,
2354 const char *form_name)
2356 union spoolss_FormInfo *info;
2357 uint32_t count;
2358 bool found = false;
2359 int i;
2361 torture_assert(tctx,
2362 test_EnumForms(tctx, b, handle, print_server, 1, &count, &info),
2363 "failed to enumerate forms");
2365 for (i=0; i<count; i++) {
2366 if (strequal(form_name, info[i].info1.form_name)) {
2367 found = true;
2368 break;
2372 return found;
2375 static bool test_DeleteForm(struct torture_context *tctx,
2376 struct dcerpc_binding_handle *b,
2377 struct policy_handle *handle,
2378 const char *form_name,
2379 WERROR expected_result)
2381 struct spoolss_DeleteForm r;
2383 r.in.handle = handle;
2384 r.in.form_name = form_name;
2386 torture_comment(tctx, "Testing DeleteForm(%s)\n", form_name);
2388 torture_assert_ntstatus_ok(tctx,
2389 dcerpc_spoolss_DeleteForm_r(b, tctx, &r),
2390 "DeleteForm failed");
2391 torture_assert_werr_equal(tctx, r.out.result, expected_result,
2392 "DeleteForm gave unexpected result");
2393 if (W_ERROR_IS_OK(r.out.result)) {
2394 torture_assert_ntstatus_ok(tctx,
2395 dcerpc_spoolss_DeleteForm_r(b, tctx, &r),
2396 "2nd DeleteForm failed");
2397 torture_assert_werr_equal(tctx, r.out.result, WERR_INVALID_FORM_NAME,
2398 "2nd DeleteForm failed");
2401 return true;
2404 static bool test_AddForm(struct torture_context *tctx,
2405 struct dcerpc_binding_handle *b,
2406 struct policy_handle *handle,
2407 uint32_t level,
2408 union spoolss_AddFormInfo *info,
2409 WERROR expected_result)
2411 struct spoolss_AddForm r;
2413 if (level != 1) {
2414 torture_skip(tctx, "only level 1 supported");
2417 r.in.handle = handle;
2418 r.in.level = level;
2419 r.in.info = *info;
2421 torture_comment(tctx, "Testing AddForm(%s) level %d, type %d\n",
2422 r.in.info.info1->form_name, r.in.level,
2423 r.in.info.info1->flags);
2425 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_AddForm_r(b, tctx, &r),
2426 "AddForm failed");
2427 torture_assert_werr_equal(tctx, r.out.result, expected_result,
2428 "AddForm gave unexpected result");
2430 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_AddForm_r(b, tctx, &r),
2431 "2nd AddForm failed");
2432 if (W_ERROR_EQUAL(expected_result, WERR_INVALID_PARAM)) {
2433 torture_assert_werr_equal(tctx, r.out.result, WERR_INVALID_PARAM,
2434 "2nd AddForm gave unexpected result");
2435 } else {
2436 torture_assert_werr_equal(tctx, r.out.result, WERR_FILE_EXISTS,
2437 "2nd AddForm gave unexpected result");
2440 return true;
2443 static bool test_SetForm(struct torture_context *tctx,
2444 struct dcerpc_binding_handle *b,
2445 struct policy_handle *handle,
2446 const char *form_name,
2447 uint32_t level,
2448 union spoolss_AddFormInfo *info)
2450 struct spoolss_SetForm r;
2452 r.in.handle = handle;
2453 r.in.form_name = form_name;
2454 r.in.level = level;
2455 r.in.info = *info;
2457 torture_comment(tctx, "Testing SetForm(%s) level %d\n",
2458 form_name, r.in.level);
2460 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_SetForm_r(b, tctx, &r),
2461 "SetForm failed");
2463 torture_assert_werr_ok(tctx, r.out.result,
2464 "SetForm failed");
2466 return true;
2469 static bool test_GetForm_winreg(struct torture_context *tctx,
2470 struct dcerpc_binding_handle *b,
2471 struct policy_handle *handle,
2472 const char *key_name,
2473 const char *form_name,
2474 enum winreg_Type *w_type,
2475 uint32_t *w_size,
2476 uint32_t *w_length,
2477 uint8_t **w_data);
2479 static bool test_Forms_args(struct torture_context *tctx,
2480 struct dcerpc_binding_handle *b,
2481 struct policy_handle *handle,
2482 bool print_server,
2483 const char *printer_name,
2484 struct dcerpc_binding_handle *winreg_handle,
2485 struct policy_handle *hive_handle,
2486 const char *form_name,
2487 struct spoolss_AddFormInfo1 *info1,
2488 WERROR expected_add_result,
2489 WERROR expected_delete_result)
2491 union spoolss_FormInfo info;
2492 union spoolss_AddFormInfo add_info;
2494 enum winreg_Type w_type;
2495 uint32_t w_size;
2496 uint32_t w_length;
2497 uint8_t *w_data;
2499 add_info.info1 = info1;
2501 torture_assert(tctx,
2502 test_AddForm(tctx, b, handle, 1, &add_info, expected_add_result),
2503 "failed to add form");
2505 if (winreg_handle && hive_handle && W_ERROR_IS_OK(expected_add_result)) {
2507 torture_assert(tctx,
2508 test_GetForm_winreg(tctx, winreg_handle, hive_handle, TOP_LEVEL_CONTROL_FORMS_KEY, form_name, &w_type, &w_size, &w_length, &w_data),
2509 "failed to get form via winreg");
2511 torture_assert_int_equal(tctx, w_type, REG_BINARY, "unexpected type");
2512 torture_assert_int_equal(tctx, w_size, 0x20, "unexpected size");
2513 torture_assert_int_equal(tctx, w_length, 0x20, "unexpected length");
2514 torture_assert_mem_equal(tctx, &w_data[0], &add_info.info1->size.width, 4, "width mismatch");
2515 torture_assert_mem_equal(tctx, &w_data[4], &add_info.info1->size.height, 4, "height mismatch");
2516 torture_assert_mem_equal(tctx, &w_data[8], &add_info.info1->area.left, 4, "left mismatch");
2517 torture_assert_mem_equal(tctx, &w_data[12], &add_info.info1->area.top, 4, "top mismatch");
2518 torture_assert_mem_equal(tctx, &w_data[16], &add_info.info1->area.right, 4, "right mismatch");
2519 torture_assert_mem_equal(tctx, &w_data[20], &add_info.info1->area.bottom, 4, "bottom mismatch");
2520 /* skip index here */
2521 torture_assert_mem_equal(tctx, &w_data[28], &add_info.info1->flags, 4, "flags mismatch");
2524 if (!print_server && W_ERROR_IS_OK(expected_add_result)) {
2525 torture_assert(tctx,
2526 test_GetForm_args(tctx, b, handle, form_name, 1, &info),
2527 "failed to get added form");
2529 torture_assert_int_equal(tctx, info.info1.size.width, add_info.info1->size.width, "width mismatch");
2530 torture_assert_int_equal(tctx, info.info1.size.height, add_info.info1->size.height, "height mismatch");
2531 torture_assert_int_equal(tctx, info.info1.area.left, add_info.info1->area.left, "left mismatch");
2532 torture_assert_int_equal(tctx, info.info1.area.top, add_info.info1->area.top, "top mismatch");
2533 torture_assert_int_equal(tctx, info.info1.area.right, add_info.info1->area.right, "right mismatch");
2534 torture_assert_int_equal(tctx, info.info1.area.bottom, add_info.info1->area.bottom, "bottom mismatch");
2535 torture_assert_int_equal(tctx, info.info1.flags, add_info.info1->flags, "flags mismatch");
2537 if (winreg_handle && hive_handle) {
2538 torture_assert_mem_equal(tctx, &w_data[0], &info.info1.size.width, 4, "width mismatch");
2539 torture_assert_mem_equal(tctx, &w_data[4], &info.info1.size.height, 4, "height mismatch");
2540 torture_assert_mem_equal(tctx, &w_data[8], &info.info1.area.left, 4, "left mismatch");
2541 torture_assert_mem_equal(tctx, &w_data[12], &info.info1.area.top, 4, "top mismatch");
2542 torture_assert_mem_equal(tctx, &w_data[16], &info.info1.area.right, 4, "right mismatch");
2543 torture_assert_mem_equal(tctx, &w_data[20], &info.info1.area.bottom, 4, "bottom mismatch");
2544 /* skip index here */
2545 torture_assert_mem_equal(tctx, &w_data[28], &info.info1.flags, 4, "flags mismatch");
2548 add_info.info1->size.width = 1234;
2550 torture_assert(tctx,
2551 test_SetForm(tctx, b, handle, form_name, 1, &add_info),
2552 "failed to set form");
2553 torture_assert(tctx,
2554 test_GetForm_args(tctx, b, handle, form_name, 1, &info),
2555 "failed to get setted form");
2557 torture_assert_int_equal(tctx, info.info1.size.width, add_info.info1->size.width, "width mismatch");
2560 if (!W_ERROR_EQUAL(expected_add_result, WERR_INVALID_PARAM)) {
2561 torture_assert(tctx,
2562 test_EnumForms_find_one(tctx, b, handle, print_server, form_name),
2563 "Newly added form not found in enum call");
2566 torture_assert(tctx,
2567 test_DeleteForm(tctx, b, handle, form_name, expected_delete_result),
2568 "failed to delete form");
2570 return true;
2573 static bool test_Forms(struct torture_context *tctx,
2574 struct dcerpc_binding_handle *b,
2575 struct policy_handle *handle,
2576 bool print_server,
2577 const char *printer_name,
2578 struct dcerpc_binding_handle *winreg_handle,
2579 struct policy_handle *hive_handle)
2581 const struct spoolss_FormSize size = {
2582 .width = 50,
2583 .height = 25
2585 const struct spoolss_FormArea area = {
2586 .left = 5,
2587 .top = 10,
2588 .right = 45,
2589 .bottom = 15
2591 int i;
2593 struct {
2594 struct spoolss_AddFormInfo1 info1;
2595 WERROR expected_add_result;
2596 WERROR expected_delete_result;
2597 } forms[] = {
2599 .info1 = {
2600 .flags = SPOOLSS_FORM_USER,
2601 .form_name = "testform_user",
2602 .size = size,
2603 .area = area,
2605 .expected_add_result = WERR_OK,
2606 .expected_delete_result = WERR_OK
2609 weird, we can add a builtin form but we can never remove it
2610 again - gd
2613 .info1 = {
2614 .flags = SPOOLSS_FORM_BUILTIN,
2615 .form_name = "testform_builtin",
2616 .size = size,
2617 .area = area,
2619 .expected_add_result = WERR_OK,
2620 .expected_delete_result = WERR_INVALID_PARAM,
2624 .info1 = {
2625 .flags = SPOOLSS_FORM_PRINTER,
2626 .form_name = "testform_printer",
2627 .size = size,
2628 .area = area,
2630 .expected_add_result = WERR_OK,
2631 .expected_delete_result = WERR_OK
2634 .info1 = {
2635 .flags = SPOOLSS_FORM_USER,
2636 .form_name = "Letter",
2637 .size = size,
2638 .area = area,
2640 .expected_add_result = WERR_FILE_EXISTS,
2641 .expected_delete_result = WERR_INVALID_PARAM
2644 .info1 = {
2645 .flags = SPOOLSS_FORM_BUILTIN,
2646 .form_name = "Letter",
2647 .size = size,
2648 .area = area,
2650 .expected_add_result = WERR_FILE_EXISTS,
2651 .expected_delete_result = WERR_INVALID_PARAM
2654 .info1 = {
2655 .flags = SPOOLSS_FORM_PRINTER,
2656 .form_name = "Letter",
2657 .size = size,
2658 .area = area,
2660 .expected_add_result = WERR_FILE_EXISTS,
2661 .expected_delete_result = WERR_INVALID_PARAM
2664 .info1 = {
2665 .flags = 12345,
2666 .form_name = "invalid_flags",
2667 .size = size,
2668 .area = area,
2670 .expected_add_result = WERR_INVALID_PARAM,
2671 .expected_delete_result = WERR_INVALID_FORM_NAME
2676 for (i=0; i < ARRAY_SIZE(forms); i++) {
2677 torture_assert(tctx,
2678 test_Forms_args(tctx, b, handle, print_server, printer_name,
2679 winreg_handle, hive_handle,
2680 forms[i].info1.form_name,
2681 &forms[i].info1,
2682 forms[i].expected_add_result,
2683 forms[i].expected_delete_result),
2684 talloc_asprintf(tctx, "failed to test form '%s'", forms[i].info1.form_name));
2687 return true;
2690 static bool test_EnumPorts_old(struct torture_context *tctx,
2691 struct dcerpc_pipe *p)
2693 NTSTATUS status;
2694 struct spoolss_EnumPorts r;
2695 uint32_t needed;
2696 uint32_t count;
2697 union spoolss_PortInfo *info;
2698 struct dcerpc_binding_handle *b = p->binding_handle;
2700 r.in.servername = talloc_asprintf(tctx, "\\\\%s",
2701 dcerpc_server_name(p));
2702 r.in.level = 2;
2703 r.in.buffer = NULL;
2704 r.in.offered = 0;
2705 r.out.needed = &needed;
2706 r.out.count = &count;
2707 r.out.info = &info;
2709 torture_comment(tctx, "Testing EnumPorts\n");
2711 status = dcerpc_spoolss_EnumPorts_r(b, tctx, &r);
2713 torture_assert_ntstatus_ok(tctx, status, "EnumPorts failed");
2715 if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
2716 DATA_BLOB blob = data_blob_talloc_zero(tctx, needed);
2717 r.in.buffer = &blob;
2718 r.in.offered = needed;
2720 status = dcerpc_spoolss_EnumPorts_r(b, tctx, &r);
2721 torture_assert_ntstatus_ok(tctx, status, "EnumPorts failed");
2722 torture_assert_werr_ok(tctx, r.out.result, "EnumPorts failed");
2724 torture_assert(tctx, info, "No ports returned");
2727 torture_assert_werr_ok(tctx, r.out.result, "EnumPorts failed");
2729 CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumPorts, info, 2, count, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
2731 return true;
2734 static bool test_AddPort(struct torture_context *tctx,
2735 struct dcerpc_pipe *p)
2737 NTSTATUS status;
2738 struct spoolss_AddPort r;
2739 struct dcerpc_binding_handle *b = p->binding_handle;
2741 r.in.server_name = talloc_asprintf(tctx, "\\\\%s",
2742 dcerpc_server_name(p));
2743 r.in.unknown = 0;
2744 r.in.monitor_name = "foo";
2746 torture_comment(tctx, "Testing AddPort\n");
2748 status = dcerpc_spoolss_AddPort_r(b, tctx, &r);
2750 torture_assert_ntstatus_ok(tctx, status, "AddPort failed");
2752 /* win2k3 returns WERR_NOT_SUPPORTED */
2754 #if 0
2756 if (!W_ERROR_IS_OK(r.out.result)) {
2757 printf("AddPort failed - %s\n", win_errstr(r.out.result));
2758 return false;
2761 #endif
2763 return true;
2766 static bool test_GetJob_args(struct torture_context *tctx,
2767 struct dcerpc_binding_handle *b,
2768 struct policy_handle *handle,
2769 uint32_t job_id,
2770 uint32_t level,
2771 union spoolss_JobInfo *info_p)
2773 NTSTATUS status;
2774 struct spoolss_GetJob r;
2775 union spoolss_JobInfo info;
2776 uint32_t needed;
2778 r.in.handle = handle;
2779 r.in.job_id = job_id;
2780 r.in.level = level;
2781 r.in.buffer = NULL;
2782 r.in.offered = 0;
2783 r.out.needed = &needed;
2784 r.out.info = &info;
2786 torture_comment(tctx, "Testing GetJob(%d), level %d\n", job_id, r.in.level);
2788 status = dcerpc_spoolss_GetJob_r(b, tctx, &r);
2789 torture_assert_ntstatus_ok(tctx, status, "GetJob failed");
2790 if (level == 0) {
2791 torture_assert_werr_equal(tctx, r.out.result, WERR_UNKNOWN_LEVEL, "Unexpected return code");
2794 if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
2795 DATA_BLOB blob = data_blob_talloc_zero(tctx, needed);
2796 r.in.buffer = &blob;
2797 r.in.offered = needed;
2799 status = dcerpc_spoolss_GetJob_r(b, tctx, &r);
2800 torture_assert_ntstatus_ok(tctx, status, "GetJob failed");
2803 torture_assert_werr_ok(tctx, r.out.result, "GetJob failed");
2804 torture_assert(tctx, r.out.info, "No job info returned");
2806 CHECK_NEEDED_SIZE_LEVEL(spoolss_JobInfo, r.out.info, r.in.level, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
2808 if (info_p) {
2809 *info_p = *r.out.info;
2812 return true;
2815 static bool test_GetJob(struct torture_context *tctx,
2816 struct dcerpc_binding_handle *b,
2817 struct policy_handle *handle,
2818 uint32_t job_id)
2820 uint32_t levels[] = {0, 1, 2 /* 3, 4 */};
2821 uint32_t i;
2823 for (i=0; i < ARRAY_SIZE(levels); i++) {
2824 torture_assert(tctx,
2825 test_GetJob_args(tctx, b, handle, job_id, levels[i], NULL),
2826 "GetJob failed");
2829 return true;
2832 static bool test_SetJob(struct torture_context *tctx,
2833 struct dcerpc_binding_handle *b,
2834 struct policy_handle *handle, uint32_t job_id,
2835 enum spoolss_JobControl command)
2837 NTSTATUS status;
2838 struct spoolss_SetJob r;
2840 r.in.handle = handle;
2841 r.in.job_id = job_id;
2842 r.in.ctr = NULL;
2843 r.in.command = command;
2845 switch (command) {
2846 case SPOOLSS_JOB_CONTROL_PAUSE:
2847 torture_comment(tctx, "Testing SetJob(%d), SPOOLSS_JOB_CONTROL_PAUSE\n", job_id);
2848 break;
2849 case SPOOLSS_JOB_CONTROL_RESUME:
2850 torture_comment(tctx, "Testing SetJob(%d), SPOOLSS_JOB_CONTROL_RESUME\n", job_id);
2851 break;
2852 case SPOOLSS_JOB_CONTROL_CANCEL:
2853 torture_comment(tctx, "Testing SetJob(%d), SPOOLSS_JOB_CONTROL_CANCEL\n", job_id);
2854 break;
2855 case SPOOLSS_JOB_CONTROL_RESTART:
2856 torture_comment(tctx, "Testing SetJob(%d), SPOOLSS_JOB_CONTROL_RESTART\n", job_id);
2857 break;
2858 case SPOOLSS_JOB_CONTROL_DELETE:
2859 torture_comment(tctx, "Testing SetJob(%d), SPOOLSS_JOB_CONTROL_DELETE\n", job_id);
2860 break;
2861 case SPOOLSS_JOB_CONTROL_SEND_TO_PRINTER:
2862 torture_comment(tctx, "Testing SetJob(%d), SPOOLSS_JOB_CONTROL_SEND_TO_PRINTER\n", job_id);
2863 break;
2864 case SPOOLSS_JOB_CONTROL_LAST_PAGE_EJECTED:
2865 torture_comment(tctx, "Testing SetJob(%d), SPOOLSS_JOB_CONTROL_LAST_PAGE_EJECTED\n", job_id);
2866 break;
2867 case SPOOLSS_JOB_CONTROL_RETAIN:
2868 torture_comment(tctx, "Testing SetJob(%d), SPOOLSS_JOB_CONTROL_RETAIN\n", job_id);
2869 break;
2870 case SPOOLSS_JOB_CONTROL_RELEASE:
2871 torture_comment(tctx, "Testing SetJob(%d), SPOOLSS_JOB_CONTROL_RELEASE\n", job_id);
2872 break;
2873 default:
2874 torture_comment(tctx, "Testing SetJob(%d)\n", job_id);
2875 break;
2878 status = dcerpc_spoolss_SetJob_r(b, tctx, &r);
2879 torture_assert_ntstatus_ok(tctx, status, "SetJob failed");
2880 torture_assert_werr_ok(tctx, r.out.result, "SetJob failed");
2882 return true;
2885 static bool test_AddJob(struct torture_context *tctx,
2886 struct dcerpc_binding_handle *b,
2887 struct policy_handle *handle)
2889 NTSTATUS status;
2890 struct spoolss_AddJob r;
2891 uint32_t needed;
2893 r.in.level = 0;
2894 r.in.handle = handle;
2895 r.in.offered = 0;
2896 r.out.needed = &needed;
2897 r.in.buffer = r.out.buffer = NULL;
2899 torture_comment(tctx, "Testing AddJob\n");
2901 status = dcerpc_spoolss_AddJob_r(b, tctx, &r);
2902 torture_assert_werr_equal(tctx, r.out.result, WERR_UNKNOWN_LEVEL, "AddJob failed");
2904 r.in.level = 1;
2906 status = dcerpc_spoolss_AddJob_r(b, tctx, &r);
2907 torture_assert_werr_equal(tctx, r.out.result, WERR_INVALID_PARAM, "AddJob failed");
2909 return true;
2913 static bool test_EnumJobs_args(struct torture_context *tctx,
2914 struct dcerpc_binding_handle *b,
2915 struct policy_handle *handle,
2916 uint32_t level,
2917 uint32_t *count_p,
2918 union spoolss_JobInfo **info_p)
2920 NTSTATUS status;
2921 struct spoolss_EnumJobs r;
2922 uint32_t needed;
2923 uint32_t count;
2924 union spoolss_JobInfo *info;
2926 r.in.handle = handle;
2927 r.in.firstjob = 0;
2928 r.in.numjobs = 0xffffffff;
2929 r.in.level = level;
2930 r.in.buffer = NULL;
2931 r.in.offered = 0;
2932 r.out.needed = &needed;
2933 r.out.count = &count;
2934 r.out.info = &info;
2936 torture_comment(tctx, "Testing EnumJobs level %d\n", level);
2938 status = dcerpc_spoolss_EnumJobs_r(b, tctx, &r);
2940 torture_assert_ntstatus_ok(tctx, status, "EnumJobs failed");
2942 if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
2943 DATA_BLOB blob = data_blob_talloc_zero(tctx, needed);
2944 r.in.buffer = &blob;
2945 r.in.offered = needed;
2947 status = dcerpc_spoolss_EnumJobs_r(b, tctx, &r);
2949 torture_assert_ntstatus_ok(tctx, status, "EnumJobs failed");
2950 torture_assert_werr_ok(tctx, r.out.result, "EnumJobs failed");
2951 torture_assert(tctx, info, "No jobs returned");
2953 CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumJobs, *r.out.info, r.in.level, count, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
2955 } else {
2956 torture_assert_werr_ok(tctx, r.out.result, "EnumJobs failed");
2959 if (count_p) {
2960 *count_p = count;
2962 if (info_p) {
2963 *info_p = info;
2966 return true;
2969 static bool test_DoPrintTest_add_one_job(struct torture_context *tctx,
2970 struct dcerpc_binding_handle *b,
2971 struct policy_handle *handle,
2972 uint32_t *job_id)
2974 NTSTATUS status;
2975 struct spoolss_StartDocPrinter s;
2976 struct spoolss_DocumentInfo1 info1;
2977 struct spoolss_StartPagePrinter sp;
2978 struct spoolss_WritePrinter w;
2979 struct spoolss_EndPagePrinter ep;
2980 struct spoolss_EndDocPrinter e;
2981 int i;
2982 uint32_t num_written;
2984 torture_comment(tctx, "Testing StartDocPrinter\n");
2986 s.in.handle = handle;
2987 s.in.level = 1;
2988 s.in.info.info1 = &info1;
2989 s.out.job_id = job_id;
2990 info1.document_name = "TorturePrintJob";
2991 info1.output_file = NULL;
2992 info1.datatype = "RAW";
2994 status = dcerpc_spoolss_StartDocPrinter_r(b, tctx, &s);
2995 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_StartDocPrinter failed");
2996 torture_assert_werr_ok(tctx, s.out.result, "StartDocPrinter failed");
2998 for (i=1; i < 4; i++) {
2999 torture_comment(tctx, "Testing StartPagePrinter: Page[%d], JobId[%d]\n", i, *job_id);
3001 sp.in.handle = handle;
3003 status = dcerpc_spoolss_StartPagePrinter_r(b, tctx, &sp);
3004 torture_assert_ntstatus_ok(tctx, status,
3005 "dcerpc_spoolss_StartPagePrinter failed");
3006 torture_assert_werr_ok(tctx, sp.out.result, "StartPagePrinter failed");
3008 torture_comment(tctx, "Testing WritePrinter: Page[%d], JobId[%d]\n", i, *job_id);
3010 w.in.handle = handle;
3011 w.in.data = data_blob_string_const(talloc_asprintf(tctx,"TortureTestPage: %d\nData\n",i));
3012 w.out.num_written = &num_written;
3014 status = dcerpc_spoolss_WritePrinter_r(b, tctx, &w);
3015 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_WritePrinter failed");
3016 torture_assert_werr_ok(tctx, w.out.result, "WritePrinter failed");
3018 torture_comment(tctx, "Testing EndPagePrinter: Page[%d], JobId[%d]\n", i, *job_id);
3020 ep.in.handle = handle;
3022 status = dcerpc_spoolss_EndPagePrinter_r(b, tctx, &ep);
3023 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EndPagePrinter failed");
3024 torture_assert_werr_ok(tctx, ep.out.result, "EndPagePrinter failed");
3027 torture_comment(tctx, "Testing EndDocPrinter: JobId[%d]\n", *job_id);
3029 e.in.handle = handle;
3031 status = dcerpc_spoolss_EndDocPrinter_r(b, tctx, &e);
3032 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EndDocPrinter failed");
3033 torture_assert_werr_ok(tctx, e.out.result, "EndDocPrinter failed");
3035 return true;
3038 static bool test_DoPrintTest_check_jobs(struct torture_context *tctx,
3039 struct dcerpc_binding_handle *b,
3040 struct policy_handle *handle,
3041 uint32_t num_jobs,
3042 uint32_t *job_ids)
3044 uint32_t count;
3045 union spoolss_JobInfo *info = NULL;
3046 int i;
3048 torture_assert(tctx,
3049 test_AddJob(tctx, b, handle),
3050 "AddJob failed");
3052 torture_assert(tctx,
3053 test_EnumJobs_args(tctx, b, handle, 1, &count, &info),
3054 "EnumJobs level 1 failed");
3056 torture_assert_int_equal(tctx, count, num_jobs, "unexpected number of jobs in queue");
3058 for (i=0; i < num_jobs; i++) {
3059 union spoolss_JobInfo ginfo;
3061 torture_assert_int_equal(tctx, info[i].info1.job_id, job_ids[i], "job id mismatch");
3063 torture_assert(tctx,
3064 test_GetJob_args(tctx, b, handle, info[i].info1.job_id, 1, &ginfo),
3065 "failed to call test_GetJob");
3067 torture_assert_int_equal(tctx, ginfo.info1.job_id, info[i].info1.job_id, "job id mismatch");
3070 for (i=0; i < num_jobs; i++) {
3071 torture_assert(tctx,
3072 test_SetJob(tctx, b, handle, info[i].info1.job_id, SPOOLSS_JOB_CONTROL_PAUSE),
3073 "failed to pause printjob");
3074 torture_assert(tctx,
3075 test_SetJob(tctx, b, handle, info[i].info1.job_id, SPOOLSS_JOB_CONTROL_RESUME),
3076 "failed to resume printjob");
3079 return true;
3082 static bool test_DoPrintTest(struct torture_context *tctx,
3083 struct dcerpc_binding_handle *b,
3084 struct policy_handle *handle)
3086 bool ret = true;
3087 uint32_t num_jobs = 8;
3088 uint32_t *job_ids;
3089 int i;
3091 job_ids = talloc_zero_array(tctx, uint32_t, num_jobs);
3093 for (i=0; i < num_jobs; i++) {
3094 ret &= test_DoPrintTest_add_one_job(tctx, b, handle, &job_ids[i]);
3097 ret &= test_DoPrintTest_check_jobs(tctx, b, handle, num_jobs, job_ids);
3099 for (i=0; i < num_jobs; i++) {
3100 ret &= test_SetJob(tctx, b, handle, job_ids[i], SPOOLSS_JOB_CONTROL_DELETE);
3103 return ret;
3106 static bool test_PausePrinter(struct torture_context *tctx,
3107 struct dcerpc_binding_handle *b,
3108 struct policy_handle *handle)
3110 NTSTATUS status;
3111 struct spoolss_SetPrinter r;
3112 struct spoolss_SetPrinterInfoCtr info_ctr;
3113 struct spoolss_DevmodeContainer devmode_ctr;
3114 struct sec_desc_buf secdesc_ctr;
3116 info_ctr.level = 0;
3117 info_ctr.info.info0 = NULL;
3119 ZERO_STRUCT(devmode_ctr);
3120 ZERO_STRUCT(secdesc_ctr);
3122 r.in.handle = handle;
3123 r.in.info_ctr = &info_ctr;
3124 r.in.devmode_ctr = &devmode_ctr;
3125 r.in.secdesc_ctr = &secdesc_ctr;
3126 r.in.command = SPOOLSS_PRINTER_CONTROL_PAUSE;
3128 torture_comment(tctx, "Testing SetPrinter: SPOOLSS_PRINTER_CONTROL_PAUSE\n");
3130 status = dcerpc_spoolss_SetPrinter_r(b, tctx, &r);
3132 torture_assert_ntstatus_ok(tctx, status, "SetPrinter failed");
3134 torture_assert_werr_ok(tctx, r.out.result, "SetPrinter failed");
3136 return true;
3139 static bool test_ResumePrinter(struct torture_context *tctx,
3140 struct dcerpc_binding_handle *b,
3141 struct policy_handle *handle)
3143 NTSTATUS status;
3144 struct spoolss_SetPrinter r;
3145 struct spoolss_SetPrinterInfoCtr info_ctr;
3146 struct spoolss_DevmodeContainer devmode_ctr;
3147 struct sec_desc_buf secdesc_ctr;
3149 info_ctr.level = 0;
3150 info_ctr.info.info0 = NULL;
3152 ZERO_STRUCT(devmode_ctr);
3153 ZERO_STRUCT(secdesc_ctr);
3155 r.in.handle = handle;
3156 r.in.info_ctr = &info_ctr;
3157 r.in.devmode_ctr = &devmode_ctr;
3158 r.in.secdesc_ctr = &secdesc_ctr;
3159 r.in.command = SPOOLSS_PRINTER_CONTROL_RESUME;
3161 torture_comment(tctx, "Testing SetPrinter: SPOOLSS_PRINTER_CONTROL_RESUME\n");
3163 status = dcerpc_spoolss_SetPrinter_r(b, tctx, &r);
3165 torture_assert_ntstatus_ok(tctx, status, "SetPrinter failed");
3167 torture_assert_werr_ok(tctx, r.out.result, "SetPrinter failed");
3169 return true;
3172 static bool test_GetPrinterData(struct torture_context *tctx,
3173 struct dcerpc_binding_handle *b,
3174 struct policy_handle *handle,
3175 const char *value_name,
3176 enum winreg_Type *type_p,
3177 uint8_t **data_p,
3178 uint32_t *needed_p)
3180 NTSTATUS status;
3181 struct spoolss_GetPrinterData r;
3182 uint32_t needed;
3183 enum winreg_Type type;
3184 union spoolss_PrinterData data;
3186 r.in.handle = handle;
3187 r.in.value_name = value_name;
3188 r.in.offered = 0;
3189 r.out.needed = &needed;
3190 r.out.type = &type;
3191 r.out.data = talloc_zero_array(tctx, uint8_t, r.in.offered);
3193 torture_comment(tctx, "Testing GetPrinterData(%s)\n", r.in.value_name);
3195 status = dcerpc_spoolss_GetPrinterData_r(b, tctx, &r);
3196 torture_assert_ntstatus_ok(tctx, status, "GetPrinterData failed");
3198 if (W_ERROR_EQUAL(r.out.result, WERR_MORE_DATA)) {
3199 r.in.offered = needed;
3200 r.out.data = talloc_zero_array(tctx, uint8_t, r.in.offered);
3201 status = dcerpc_spoolss_GetPrinterData_r(b, tctx, &r);
3202 torture_assert_ntstatus_ok(tctx, status, "GetPrinterData failed");
3205 torture_assert_werr_ok(tctx, r.out.result,
3206 talloc_asprintf(tctx, "GetPrinterData(%s) failed", r.in.value_name));
3208 CHECK_NEEDED_SIZE_LEVEL(spoolss_PrinterData, &data, type, lp_iconv_convenience(tctx->lp_ctx), needed, 1);
3210 if (type_p) {
3211 *type_p = type;
3214 if (data_p) {
3215 *data_p = r.out.data;
3218 if (needed_p) {
3219 *needed_p = needed;
3222 return true;
3225 static bool test_GetPrinterDataEx(struct torture_context *tctx,
3226 struct dcerpc_pipe *p,
3227 struct policy_handle *handle,
3228 const char *key_name,
3229 const char *value_name,
3230 enum winreg_Type *type_p,
3231 uint8_t **data_p,
3232 uint32_t *needed_p)
3234 NTSTATUS status;
3235 struct spoolss_GetPrinterDataEx r;
3236 enum winreg_Type type;
3237 uint32_t needed;
3238 union spoolss_PrinterData data;
3239 struct dcerpc_binding_handle *b = p->binding_handle;
3241 r.in.handle = handle;
3242 r.in.key_name = key_name;
3243 r.in.value_name = value_name;
3244 r.in.offered = 0;
3245 r.out.type = &type;
3246 r.out.needed = &needed;
3247 r.out.data = talloc_zero_array(tctx, uint8_t, r.in.offered);
3249 torture_comment(tctx, "Testing GetPrinterDataEx(%s - %s)\n",
3250 r.in.key_name, r.in.value_name);
3252 status = dcerpc_spoolss_GetPrinterDataEx_r(b, tctx, &r);
3253 if (!NT_STATUS_IS_OK(status)) {
3254 if (NT_STATUS_EQUAL(status,NT_STATUS_NET_WRITE_FAULT) &&
3255 p->last_fault_code == DCERPC_FAULT_OP_RNG_ERROR) {
3256 torture_skip(tctx, "GetPrinterDataEx not supported by server\n");
3258 torture_assert_ntstatus_ok(tctx, status, "GetPrinterDataEx failed");
3261 if (W_ERROR_EQUAL(r.out.result, WERR_MORE_DATA)) {
3262 r.in.offered = needed;
3263 r.out.data = talloc_zero_array(tctx, uint8_t, r.in.offered);
3264 status = dcerpc_spoolss_GetPrinterDataEx_r(b, tctx, &r);
3265 torture_assert_ntstatus_ok(tctx, status, "GetPrinterDataEx failed");
3268 torture_assert_werr_ok(tctx, r.out.result,
3269 talloc_asprintf(tctx, "GetPrinterDataEx(%s - %s) failed", r.in.key_name, r.in.value_name));
3271 CHECK_NEEDED_SIZE_LEVEL(spoolss_PrinterData, &data, type, lp_iconv_convenience(tctx->lp_ctx), needed, 1);
3273 if (type_p) {
3274 *type_p = type;
3277 if (data_p) {
3278 *data_p = r.out.data;
3281 if (needed_p) {
3282 *needed_p = needed;
3285 return true;
3288 static bool test_GetPrinterData_list(struct torture_context *tctx,
3289 struct dcerpc_pipe *p,
3290 struct policy_handle *handle,
3291 const char **architecture)
3293 struct dcerpc_binding_handle *b = p->binding_handle;
3294 const char *list[] = {
3295 "W3SvcInstalled",
3296 "BeepEnabled",
3297 "EventLog",
3298 /* "NetPopup", not on w2k8 */
3299 /* "NetPopupToComputer", not on w2k8 */
3300 "MajorVersion",
3301 "MinorVersion",
3302 "DefaultSpoolDirectory",
3303 "Architecture",
3304 "DsPresent",
3305 "OSVersion",
3306 /* "OSVersionEx", not on s3 */
3307 "DNSMachineName"
3309 int i;
3311 for (i=0; i < ARRAY_SIZE(list); i++) {
3312 enum winreg_Type type, type_ex;
3313 uint8_t *data, *data_ex;
3314 uint32_t needed, needed_ex;
3316 torture_assert(tctx, test_GetPrinterData(tctx, b, handle, list[i], &type, &data, &needed),
3317 talloc_asprintf(tctx, "GetPrinterData failed on %s\n", list[i]));
3318 torture_assert(tctx, test_GetPrinterDataEx(tctx, p, handle, "random_string", list[i], &type_ex, &data_ex, &needed_ex),
3319 talloc_asprintf(tctx, "GetPrinterDataEx failed on %s\n", list[i]));
3320 torture_assert_int_equal(tctx, type, type_ex, "type mismatch");
3321 torture_assert_int_equal(tctx, needed, needed_ex, "needed mismatch");
3322 torture_assert_mem_equal(tctx, data, data_ex, needed, "data mismatch");
3324 if (strequal(list[i], "Architecture")) {
3325 if (architecture) {
3326 DATA_BLOB blob = data_blob_const(data, needed);
3327 *architecture = reg_val_data_string(tctx, lp_iconv_convenience(tctx->lp_ctx), REG_SZ, blob);
3332 return true;
3335 static bool test_EnumPrinterData(struct torture_context *tctx,
3336 struct dcerpc_pipe *p,
3337 struct policy_handle *handle,
3338 uint32_t enum_index,
3339 uint32_t value_offered,
3340 uint32_t data_offered,
3341 enum winreg_Type *type_p,
3342 uint32_t *value_needed_p,
3343 uint32_t *data_needed_p,
3344 const char **value_name_p,
3345 uint8_t **data_p,
3346 WERROR *result_p)
3348 struct spoolss_EnumPrinterData r;
3349 uint32_t data_needed;
3350 uint32_t value_needed;
3351 enum winreg_Type type;
3352 struct dcerpc_binding_handle *b = p->binding_handle;
3354 r.in.handle = handle;
3355 r.in.enum_index = enum_index;
3356 r.in.value_offered = value_offered;
3357 r.in.data_offered = data_offered;
3358 r.out.data_needed = &data_needed;
3359 r.out.value_needed = &value_needed;
3360 r.out.type = &type;
3361 r.out.data = talloc_zero_array(tctx, uint8_t, r.in.data_offered);
3362 r.out.value_name = talloc_zero_array(tctx, const char, r.in.value_offered);
3364 torture_comment(tctx, "Testing EnumPrinterData(%d)\n", enum_index);
3366 torture_assert_ntstatus_ok(tctx,
3367 dcerpc_spoolss_EnumPrinterData_r(b, tctx, &r),
3368 "EnumPrinterData failed");
3370 if (type_p) {
3371 *type_p = type;
3373 if (value_needed_p) {
3374 *value_needed_p = value_needed;
3376 if (data_needed_p) {
3377 *data_needed_p = data_needed;
3379 if (value_name_p) {
3380 *value_name_p = r.out.value_name;
3382 if (data_p) {
3383 *data_p = r.out.data;
3385 if (result_p) {
3386 *result_p = r.out.result;
3389 return true;
3393 static bool test_EnumPrinterData_all(struct torture_context *tctx,
3394 struct dcerpc_pipe *p,
3395 struct policy_handle *handle)
3397 uint32_t enum_index = 0;
3398 enum winreg_Type type;
3399 uint32_t value_needed;
3400 uint32_t data_needed;
3401 uint8_t *data;
3402 const char *value_name;
3403 WERROR result;
3405 torture_comment(tctx, "Testing EnumPrinterData\n");
3407 do {
3408 torture_assert(tctx,
3409 test_EnumPrinterData(tctx, p, handle, enum_index, 0, 0,
3410 &type, &value_needed, &data_needed,
3411 &value_name, &data, &result),
3412 "EnumPrinterData failed");
3414 if (W_ERROR_EQUAL(result, WERR_NO_MORE_ITEMS)) {
3415 break;
3418 torture_assert(tctx,
3419 test_EnumPrinterData(tctx, p, handle, enum_index, value_needed, data_needed,
3420 &type, &value_needed, &data_needed,
3421 &value_name, &data, &result),
3422 "EnumPrinterData failed");
3424 if (W_ERROR_EQUAL(result, WERR_NO_MORE_ITEMS)) {
3425 break;
3428 enum_index++;
3430 } while (W_ERROR_IS_OK(result));
3432 torture_comment(tctx, "EnumPrinterData test succeeded\n");
3434 return true;
3437 static bool test_EnumPrinterDataEx(struct torture_context *tctx,
3438 struct dcerpc_binding_handle *b,
3439 struct policy_handle *handle,
3440 const char *key_name,
3441 uint32_t *count_p,
3442 struct spoolss_PrinterEnumValues **info_p)
3444 struct spoolss_EnumPrinterDataEx r;
3445 struct spoolss_PrinterEnumValues *info;
3446 uint32_t needed;
3447 uint32_t count;
3449 r.in.handle = handle;
3450 r.in.key_name = key_name;
3451 r.in.offered = 0;
3452 r.out.needed = &needed;
3453 r.out.count = &count;
3454 r.out.info = &info;
3456 torture_comment(tctx, "Testing EnumPrinterDataEx(%s)\n", key_name);
3458 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_EnumPrinterDataEx_r(b, tctx, &r),
3459 "EnumPrinterDataEx failed");
3460 if (W_ERROR_EQUAL(r.out.result, WERR_MORE_DATA)) {
3461 r.in.offered = needed;
3462 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_EnumPrinterDataEx_r(b, tctx, &r),
3463 "EnumPrinterDataEx failed");
3466 torture_assert_werr_ok(tctx, r.out.result, "EnumPrinterDataEx failed");
3468 CHECK_NEEDED_SIZE_ENUM(spoolss_EnumPrinterDataEx, info, count, lp_iconv_convenience(tctx->lp_ctx), needed, 1);
3470 if (count_p) {
3471 *count_p = count;
3473 if (info_p) {
3474 *info_p = info;
3477 return true;
3480 static bool test_SetPrinterData(struct torture_context *tctx,
3481 struct dcerpc_binding_handle *b,
3482 struct policy_handle *handle,
3483 const char *value_name,
3484 enum winreg_Type type,
3485 uint8_t *data,
3486 uint32_t offered);
3487 static bool test_DeletePrinterData(struct torture_context *tctx,
3488 struct dcerpc_binding_handle *b,
3489 struct policy_handle *handle,
3490 const char *value_name);
3492 static bool test_EnumPrinterData_consistency(struct torture_context *tctx,
3493 struct dcerpc_pipe *p,
3494 struct policy_handle *handle)
3496 uint32_t count;
3497 struct spoolss_PrinterEnumValues *info;
3498 int i;
3499 uint32_t value_needed, data_needed;
3500 uint32_t value_offered, data_offered;
3501 WERROR result;
3502 struct dcerpc_binding_handle *b = p->binding_handle;
3504 enum winreg_Type type;
3505 DATA_BLOB blob;
3507 torture_comment(tctx, "Testing EnumPrinterData vs EnumPrinterDataEx consistency\n");
3509 torture_assert(tctx,
3510 reg_string_to_val(tctx, lp_iconv_convenience(tctx->lp_ctx),
3511 "REG_SZ", "torture_data1", &type, &blob), "");
3513 torture_assert(tctx,
3514 test_SetPrinterData(tctx, b, handle, "torture_value1", type, blob.data, blob.length),
3515 "SetPrinterData failed");
3517 blob = data_blob_string_const("torture_data2");
3519 torture_assert(tctx,
3520 test_SetPrinterData(tctx, b, handle, "torture_value2", REG_BINARY, blob.data, blob.length),
3521 "SetPrinterData failed");
3523 blob = data_blob_talloc(tctx, NULL, 4);
3524 SIVAL(blob.data, 0, 0x11223344);
3526 torture_assert(tctx,
3527 test_SetPrinterData(tctx, b, handle, "torture_value3", type, blob.data, blob.length),
3528 "SetPrinterData failed");
3530 torture_assert(tctx,
3531 test_EnumPrinterDataEx(tctx, b, handle, "PrinterDriverData", &count, &info),
3532 "failed to call EnumPrinterDataEx");
3534 /* get the max sizes for value and data */
3536 torture_assert(tctx,
3537 test_EnumPrinterData(tctx, p, handle, 0, 0, 0,
3538 NULL, &value_needed, &data_needed,
3539 NULL, NULL, &result),
3540 "EnumPrinterData failed");
3541 torture_assert_werr_ok(tctx, result, "unexpected result");
3543 /* check if the reply from the EnumPrinterData really matches max values */
3545 for (i=0; i < count; i++) {
3546 if (info[i].value_name_len > value_needed) {
3547 torture_fail(tctx,
3548 talloc_asprintf(tctx,
3549 "EnumPrinterDataEx gave a reply with value length %d which is larger then expected max value length %d from EnumPrinterData",
3550 info[i].value_name_len, value_needed));
3552 if (info[i].data_length > data_needed) {
3553 torture_fail(tctx,
3554 talloc_asprintf(tctx,
3555 "EnumPrinterDataEx gave a reply with data length %d which is larger then expected max data length %d from EnumPrinterData",
3556 info[i].data_length, data_needed));
3560 /* assuming that both EnumPrinterData and EnumPrinterDataEx do either
3561 * sort or not sort the replies by value name, we should be able to do
3562 * the following entry comparison */
3564 data_offered = data_needed;
3565 value_offered = value_needed;
3567 for (i=0; i < count; i++) {
3569 const char *value_name;
3570 uint8_t *data;
3572 torture_assert(tctx,
3573 test_EnumPrinterData(tctx, p, handle, i, value_offered, data_offered,
3574 &type, &value_needed, &data_needed,
3575 &value_name, &data, &result),
3576 "EnumPrinterData failed");
3578 if (i -1 == count) {
3579 torture_assert_werr_equal(tctx, result, WERR_NO_MORE_ITEMS,
3580 "unexpected result");
3581 break;
3582 } else {
3583 torture_assert_werr_ok(tctx, result, "unexpected result");
3586 torture_assert_int_equal(tctx, type, info[i].type, "type mismatch");
3587 torture_assert_int_equal(tctx, value_needed, info[i].value_name_len, "value name length mismatch");
3588 torture_assert_str_equal(tctx, value_name, info[i].value_name, "value name mismatch");
3589 torture_assert_int_equal(tctx, data_needed, info[i].data_length, "data length mismatch");
3590 torture_assert_mem_equal(tctx, data, info[i].data->data, info[i].data_length, "data mismatch");
3593 torture_assert(tctx,
3594 test_DeletePrinterData(tctx, b, handle, "torture_value1"),
3595 "DeletePrinterData failed");
3596 torture_assert(tctx,
3597 test_DeletePrinterData(tctx, b, handle, "torture_value2"),
3598 "DeletePrinterData failed");
3599 torture_assert(tctx,
3600 test_DeletePrinterData(tctx, b, handle, "torture_value3"),
3601 "DeletePrinterData failed");
3603 torture_comment(tctx, "EnumPrinterData vs EnumPrinterDataEx consistency test succeeded\n\n");
3605 return true;
3608 static bool test_DeletePrinterData(struct torture_context *tctx,
3609 struct dcerpc_binding_handle *b,
3610 struct policy_handle *handle,
3611 const char *value_name)
3613 NTSTATUS status;
3614 struct spoolss_DeletePrinterData r;
3616 r.in.handle = handle;
3617 r.in.value_name = value_name;
3619 torture_comment(tctx, "Testing DeletePrinterData(%s)\n",
3620 r.in.value_name);
3622 status = dcerpc_spoolss_DeletePrinterData_r(b, tctx, &r);
3624 torture_assert_ntstatus_ok(tctx, status, "DeletePrinterData failed");
3625 torture_assert_werr_ok(tctx, r.out.result, "DeletePrinterData failed");
3627 return true;
3630 static bool test_DeletePrinterDataEx(struct torture_context *tctx,
3631 struct dcerpc_binding_handle *b,
3632 struct policy_handle *handle,
3633 const char *key_name,
3634 const char *value_name)
3636 struct spoolss_DeletePrinterDataEx r;
3638 r.in.handle = handle;
3639 r.in.key_name = key_name;
3640 r.in.value_name = value_name;
3642 torture_comment(tctx, "Testing DeletePrinterDataEx(%s - %s)\n",
3643 r.in.key_name, r.in.value_name);
3645 torture_assert_ntstatus_ok(tctx,
3646 dcerpc_spoolss_DeletePrinterDataEx_r(b, tctx, &r),
3647 "DeletePrinterDataEx failed");
3648 torture_assert_werr_ok(tctx, r.out.result,
3649 "DeletePrinterDataEx failed");
3651 return true;
3654 static bool test_DeletePrinterKey(struct torture_context *tctx,
3655 struct dcerpc_binding_handle *b,
3656 struct policy_handle *handle,
3657 const char *key_name)
3659 struct spoolss_DeletePrinterKey r;
3661 r.in.handle = handle;
3662 r.in.key_name = key_name;
3664 torture_comment(tctx, "Testing DeletePrinterKey(%s)\n", r.in.key_name);
3666 if (strequal(key_name, "") && !torture_setting_bool(tctx, "dangerous", false)) {
3667 torture_skip(tctx, "not wiping out printer registry - enable dangerous tests to use\n");
3668 return true;
3671 torture_assert_ntstatus_ok(tctx,
3672 dcerpc_spoolss_DeletePrinterKey_r(b, tctx, &r),
3673 "DeletePrinterKey failed");
3674 torture_assert_werr_ok(tctx, r.out.result,
3675 "DeletePrinterKey failed");
3677 return true;
3680 static bool test_winreg_OpenHKLM(struct torture_context *tctx,
3681 struct dcerpc_binding_handle *b,
3682 struct policy_handle *handle)
3684 struct winreg_OpenHKLM r;
3686 r.in.system_name = NULL;
3687 r.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
3688 r.out.handle = handle;
3690 torture_comment(tctx, "Testing winreg_OpenHKLM\n");
3692 torture_assert_ntstatus_ok(tctx, dcerpc_winreg_OpenHKLM_r(b, tctx, &r), "OpenHKLM failed");
3693 torture_assert_werr_ok(tctx, r.out.result, "OpenHKLM failed");
3695 return true;
3698 static void init_winreg_String(struct winreg_String *name, const char *s)
3700 name->name = s;
3701 if (s) {
3702 name->name_len = 2 * (strlen_m(s) + 1);
3703 name->name_size = name->name_len;
3704 } else {
3705 name->name_len = 0;
3706 name->name_size = 0;
3710 static bool test_winreg_OpenKey_opts(struct torture_context *tctx,
3711 struct dcerpc_binding_handle *b,
3712 struct policy_handle *hive_handle,
3713 const char *keyname,
3714 uint32_t options,
3715 struct policy_handle *key_handle)
3717 struct winreg_OpenKey r;
3719 r.in.parent_handle = hive_handle;
3720 init_winreg_String(&r.in.keyname, keyname);
3721 r.in.options = options;
3722 r.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
3723 r.out.handle = key_handle;
3725 torture_comment(tctx, "Testing winreg_OpenKey(%s)\n", keyname);
3727 torture_assert_ntstatus_ok(tctx, dcerpc_winreg_OpenKey_r(b, tctx, &r), "OpenKey failed");
3728 torture_assert_werr_ok(tctx, r.out.result, "OpenKey failed");
3730 return true;
3733 static bool test_winreg_OpenKey(struct torture_context *tctx,
3734 struct dcerpc_binding_handle *b,
3735 struct policy_handle *hive_handle,
3736 const char *keyname,
3737 struct policy_handle *key_handle)
3739 return test_winreg_OpenKey_opts(tctx, b, hive_handle, keyname,
3740 REG_OPTION_NON_VOLATILE, key_handle);
3743 static bool test_winreg_CloseKey(struct torture_context *tctx,
3744 struct dcerpc_binding_handle *b,
3745 struct policy_handle *handle)
3747 struct winreg_CloseKey r;
3749 r.in.handle = handle;
3750 r.out.handle = handle;
3752 torture_comment(tctx, "Testing winreg_CloseKey\n");
3754 torture_assert_ntstatus_ok(tctx, dcerpc_winreg_CloseKey_r(b, tctx, &r), "CloseKey failed");
3755 torture_assert_werr_ok(tctx, r.out.result, "CloseKey failed");
3757 return true;
3760 bool test_winreg_QueryValue(struct torture_context *tctx,
3761 struct dcerpc_binding_handle *b,
3762 struct policy_handle *handle,
3763 const char *value_name,
3764 enum winreg_Type *type_p,
3765 uint32_t *data_size_p,
3766 uint32_t *data_length_p,
3767 uint8_t **data_p)
3769 struct winreg_QueryValue r;
3770 enum winreg_Type type = REG_NONE;
3771 uint32_t data_size = 0;
3772 uint32_t data_length = 0;
3773 struct winreg_String valuename;
3774 uint8_t *data = NULL;
3776 init_winreg_String(&valuename, value_name);
3778 data = talloc_zero_array(tctx, uint8_t, 0);
3780 r.in.handle = handle;
3781 r.in.value_name = &valuename;
3782 r.in.type = &type;
3783 r.in.data_size = &data_size;
3784 r.in.data_length = &data_length;
3785 r.in.data = data;
3786 r.out.type = &type;
3787 r.out.data = data;
3788 r.out.data_size = &data_size;
3789 r.out.data_length = &data_length;
3791 torture_comment(tctx, "Testing winreg_QueryValue(%s)\n", value_name);
3793 torture_assert_ntstatus_ok(tctx, dcerpc_winreg_QueryValue_r(b, tctx, &r), "QueryValue failed");
3794 if (W_ERROR_EQUAL(r.out.result, WERR_MORE_DATA)) {
3795 *r.in.data_size = *r.out.data_size;
3796 data = talloc_zero_array(tctx, uint8_t, *r.in.data_size);
3797 r.in.data = data;
3798 r.out.data = data;
3799 torture_assert_ntstatus_ok(tctx, dcerpc_winreg_QueryValue_r(b, tctx, &r), "QueryValue failed");
3801 torture_assert_werr_ok(tctx, r.out.result, "QueryValue failed");
3803 if (type_p) {
3804 *type_p = *r.out.type;
3806 if (data_size_p) {
3807 *data_size_p = *r.out.data_size;
3809 if (data_length_p) {
3810 *data_length_p = *r.out.data_length;
3812 if (data_p) {
3813 *data_p = r.out.data;
3816 return true;
3819 static bool test_winreg_query_printerdata(struct torture_context *tctx,
3820 struct dcerpc_binding_handle *b,
3821 struct policy_handle *handle,
3822 const char *printer_name,
3823 const char *key_name,
3824 const char *value_name,
3825 enum winreg_Type *w_type,
3826 uint32_t *w_size,
3827 uint32_t *w_length,
3828 uint8_t **w_data)
3830 const char *printer_key;
3831 struct policy_handle key_handle;
3833 printer_key = talloc_asprintf(tctx, "%s\\%s\\%s",
3834 TOP_LEVEL_PRINT_PRINTERS_KEY, printer_name, key_name);
3836 torture_assert(tctx,
3837 test_winreg_OpenKey(tctx, b, handle, printer_key, &key_handle), "");
3839 torture_assert(tctx,
3840 test_winreg_QueryValue(tctx, b, &key_handle, value_name, w_type, w_size, w_length, w_data), "");
3842 torture_assert(tctx,
3843 test_winreg_CloseKey(tctx, b, &key_handle), "");
3845 return true;
3848 static bool test_GetForm_winreg(struct torture_context *tctx,
3849 struct dcerpc_binding_handle *b,
3850 struct policy_handle *handle,
3851 const char *key_name,
3852 const char *form_name,
3853 enum winreg_Type *w_type,
3854 uint32_t *w_size,
3855 uint32_t *w_length,
3856 uint8_t **w_data)
3858 struct policy_handle key_handle;
3860 torture_assert(tctx,
3861 test_winreg_OpenKey(tctx, b, handle, key_name, &key_handle), "");
3863 torture_assert(tctx,
3864 test_winreg_QueryValue(tctx, b, &key_handle, form_name, w_type, w_size, w_length, w_data), "");
3866 torture_assert(tctx,
3867 test_winreg_CloseKey(tctx, b, &key_handle), "");
3869 return true;
3872 static bool test_winreg_symbolic_link(struct torture_context *tctx,
3873 struct dcerpc_binding_handle *b,
3874 struct policy_handle *handle,
3875 const char *symlink_keyname,
3876 const char *symlink_destination)
3878 /* check if the first key is a symlink to the second key */
3880 enum winreg_Type w_type;
3881 uint32_t w_size;
3882 uint32_t w_length;
3883 uint8_t *w_data;
3884 struct policy_handle key_handle;
3885 DATA_BLOB blob;
3886 const char *str;
3888 if (torture_setting_bool(tctx, "samba3", false)) {
3889 torture_skip(tctx, "skip winreg symlink test against samba");
3892 torture_assert(tctx,
3893 test_winreg_OpenKey_opts(tctx, b, handle, symlink_keyname, REG_OPTION_OPEN_LINK, &key_handle),
3894 "failed to open key link");
3896 torture_assert(tctx,
3897 test_winreg_QueryValue(tctx, b, &key_handle,
3898 "SymbolicLinkValue",
3899 &w_type, &w_size, &w_length, &w_data),
3900 "failed to query for 'SymbolicLinkValue' attribute");
3902 torture_assert_int_equal(tctx, w_type, REG_LINK, "unexpected type");
3904 blob = data_blob(w_data, w_size);
3905 str = reg_val_data_string(tctx, lp_iconv_convenience(tctx->lp_ctx), REG_SZ, blob);
3907 torture_assert_str_equal(tctx, str, symlink_destination, "unexpected symlink target string");
3909 torture_assert(tctx,
3910 test_winreg_CloseKey(tctx, b, &key_handle),
3911 "failed to close key link");
3913 return true;
3916 static const char *strip_unc(const char *unc)
3918 char *name;
3920 if (!unc) {
3921 return NULL;
3924 if (unc[0] == '\\' && unc[1] == '\\') {
3925 unc +=2;
3928 name = strchr(unc, '\\');
3929 if (name) {
3930 return name+1;
3933 return unc;
3936 static bool test_GetPrinterInfo_winreg(struct torture_context *tctx,
3937 struct dcerpc_binding_handle *b,
3938 struct policy_handle *handle,
3939 const char *printer_name,
3940 struct dcerpc_binding_handle *winreg_handle,
3941 struct policy_handle *hive_handle)
3943 union spoolss_PrinterInfo info;
3944 const char *keys[] = {
3945 TOP_LEVEL_CONTROL_PRINTERS_KEY,
3946 TOP_LEVEL_PRINT_PRINTERS_KEY
3948 int i;
3949 const char *printername, *sharename;
3951 torture_comment(tctx, "Testing Printer Info and winreg consistency\n");
3953 torture_assert(tctx,
3954 test_GetPrinter_level(tctx, b, handle, 2, &info),
3955 "failed to get printer info level 2");
3957 printername = strip_unc(info.info2.printername);
3958 sharename = strip_unc(info.info2.sharename);
3960 #define test_sz(key, wname, iname) \
3961 do {\
3962 DATA_BLOB blob;\
3963 const char *str;\
3964 enum winreg_Type w_type;\
3965 uint32_t w_size;\
3966 uint32_t w_length;\
3967 uint8_t *w_data;\
3968 torture_assert(tctx,\
3969 test_winreg_QueryValue(tctx, winreg_handle, &key_handle, wname,\
3970 &w_type, &w_size, &w_length, &w_data),\
3971 "failed to query winreg");\
3972 torture_assert_int_equal(tctx, w_type, REG_SZ, "unexpected type");\
3973 blob = data_blob(w_data, w_size);\
3974 str = reg_val_data_string(tctx, lp_iconv_convenience(tctx->lp_ctx), REG_SZ, blob);\
3975 if (w_size == 2 && iname == NULL) {\
3976 /*torture_comment(tctx, "%s: \"\", %s: (null)\n", #wname, #iname);\ */\
3977 } else {\
3978 torture_assert_str_equal(tctx, str, iname,\
3979 talloc_asprintf(tctx, "%s - %s mismatch", #wname, #iname));\
3981 } while(0);
3983 #define test_dword(key, wname, iname) \
3984 do {\
3985 uint32_t value;\
3986 enum winreg_Type w_type;\
3987 uint32_t w_size;\
3988 uint32_t w_length;\
3989 uint8_t *w_data;\
3990 torture_assert(tctx,\
3991 test_winreg_QueryValue(tctx, winreg_handle, &key_handle, wname,\
3992 &w_type, &w_size, &w_length, &w_data),\
3993 "failed to query winreg");\
3994 torture_assert_int_equal(tctx, w_type, REG_DWORD, "unexpected type");\
3995 torture_assert_int_equal(tctx, w_size, 4, "unexpected size");\
3996 torture_assert_int_equal(tctx, w_length, 4, "unexpected length");\
3997 value = IVAL(w_data, 0);\
3998 torture_assert_int_equal(tctx, value, iname,\
3999 talloc_asprintf(tctx, "%s - %s mismatch", #wname, #iname));\
4000 } while(0);
4002 #define test_dm(key, wname, iname) \
4003 do {\
4004 DATA_BLOB blob;\
4005 struct spoolss_DeviceMode dm;\
4006 enum ndr_err_code ndr_err;\
4007 enum winreg_Type w_type;\
4008 uint32_t w_size;\
4009 uint32_t w_length;\
4010 uint8_t *w_data;\
4011 torture_assert(tctx,\
4012 test_winreg_QueryValue(tctx, winreg_handle, &key_handle, wname,\
4013 &w_type, &w_size, &w_length, &w_data),\
4014 "failed to query winreg");\
4015 torture_assert_int_equal(tctx, w_type, REG_BINARY, "unexpected type");\
4016 blob = data_blob(w_data, w_size);\
4017 ndr_err = ndr_pull_struct_blob(&blob, tctx, lp_iconv_convenience(tctx->lp_ctx), &dm,\
4018 (ndr_pull_flags_fn_t)ndr_pull_spoolss_DeviceMode);\
4019 torture_assert_ndr_success(tctx, ndr_err, "failed to unmarshall dm");\
4020 torture_assert(tctx, test_devicemode_equal(tctx, &dm, iname),\
4021 "dm unequal");\
4022 } while(0);
4024 #define test_sd(key, wname, iname) \
4025 do {\
4026 DATA_BLOB blob;\
4027 struct security_descriptor sd;\
4028 enum ndr_err_code ndr_err;\
4029 enum winreg_Type w_type;\
4030 uint32_t w_size;\
4031 uint32_t w_length;\
4032 uint8_t *w_data;\
4033 torture_assert(tctx,\
4034 test_winreg_QueryValue(tctx, winreg_handle, &key_handle, wname,\
4035 &w_type, &w_size, &w_length, &w_data),\
4036 "failed to query winreg");\
4037 torture_assert_int_equal(tctx, w_type, REG_BINARY, "unexpected type");\
4038 blob = data_blob(w_data, w_size);\
4039 ndr_err = ndr_pull_struct_blob(&blob, tctx, lp_iconv_convenience(tctx->lp_ctx), &sd,\
4040 (ndr_pull_flags_fn_t)ndr_pull_security_descriptor);\
4041 torture_assert_ndr_success(tctx, ndr_err, "failed to unmarshall sd");\
4042 torture_assert(tctx, test_security_descriptor_equal(tctx, &sd, iname),\
4043 "sd unequal");\
4044 } while(0);
4047 if (!test_winreg_symbolic_link(tctx, winreg_handle, hive_handle,
4048 TOP_LEVEL_CONTROL_PRINTERS_KEY,
4049 "\\Registry\\Machine\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Print\\Printers"))
4051 torture_warning(tctx, "failed to check for winreg symlink");
4055 for (i=0; i < ARRAY_SIZE(keys); i++) {
4057 const char *printer_key;
4058 struct policy_handle key_handle;
4060 printer_key = talloc_asprintf(tctx, "%s\\%s",
4061 keys[i], printer_name);
4063 torture_assert(tctx,
4064 test_winreg_OpenKey(tctx, winreg_handle, hive_handle, printer_key, &key_handle), "");
4066 test_sz(keys[i], "Name", printername);
4067 test_sz(keys[i], "Share Name", sharename);
4068 test_sz(keys[i], "Port", info.info2.portname);
4069 test_sz(keys[i], "Printer Driver", info.info2.drivername);
4070 test_sz(keys[i], "Description", info.info2.comment);
4071 test_sz(keys[i], "Location", info.info2.location);
4072 test_sz(keys[i], "Separator File", info.info2.sepfile);
4073 test_sz(keys[i], "Print Processor", info.info2.printprocessor);
4074 test_sz(keys[i], "Datatype", info.info2.datatype);
4075 test_sz(keys[i], "Parameters", info.info2.parameters);
4076 /* winreg: 0, spoolss not */
4077 /* test_dword(keys[i], "Attributes", info.info2.attributes); */
4078 test_dword(keys[i], "Priority", info.info2.priority);
4079 test_dword(keys[i], "Default Priority", info.info2.defaultpriority);
4080 /* winreg: 60, spoolss: 0 */
4081 /* test_dword(keys[i], "StartTime", info.info2.starttime); */
4082 /* test_dword(keys[i], "UntilTime", info.info2.untiltime); */
4083 /* winreg != spoolss */
4084 /* test_dword(keys[i], "Status", info.info2.status); */
4085 test_dm(keys[i], "Default DevMode", info.info2.devmode);
4086 test_sd(keys[i], "Security", info.info2.secdesc);
4088 torture_assert(tctx,
4089 test_winreg_CloseKey(tctx, winreg_handle, &key_handle), "");
4092 #undef test_sz
4093 #undef test_dword
4094 #undef test_dm
4095 #undef test_sd
4097 torture_comment(tctx, "Printer Info and winreg consistency test succeeded\n\n");
4099 return true;
4102 static bool test_SetPrinterData(struct torture_context *tctx,
4103 struct dcerpc_binding_handle *b,
4104 struct policy_handle *handle,
4105 const char *value_name,
4106 enum winreg_Type type,
4107 uint8_t *data,
4108 uint32_t offered)
4110 struct spoolss_SetPrinterData r;
4112 r.in.handle = handle;
4113 r.in.value_name = value_name;
4114 r.in.type = type;
4115 r.in.data = data;
4116 r.in.offered = offered;
4118 torture_comment(tctx, "Testing SetPrinterData(%s)\n",
4119 r.in.value_name);
4121 torture_assert_ntstatus_ok(tctx,
4122 dcerpc_spoolss_SetPrinterData_r(b, tctx, &r),
4123 "SetPrinterData failed");
4124 torture_assert_werr_ok(tctx, r.out.result,
4125 "SetPrinterData failed");
4127 return true;
4130 static bool test_SetPrinterData_matrix(struct torture_context *tctx,
4131 struct dcerpc_binding_handle *b,
4132 struct policy_handle *handle,
4133 const char *printer_name,
4134 struct dcerpc_binding_handle *winreg_handle,
4135 struct policy_handle *hive_handle)
4137 const char *values[] = {
4138 "spootyfoot",
4139 "spooty\\foot",
4140 #if 0
4141 /* FIXME: not working with s3 atm. */
4142 "spooty,foot",
4143 "spooty,fo,ot",
4144 #endif
4145 "spooty foot",
4146 #if 0
4147 /* FIXME: not working with s3 atm. */
4148 "spooty\\fo,ot",
4149 "spooty,fo\\ot"
4150 #endif
4152 int i;
4154 for (i=0; i < ARRAY_SIZE(values); i++) {
4156 enum winreg_Type type;
4157 DATA_BLOB blob;
4158 uint8_t *data;
4159 uint32_t needed;
4161 torture_assert(tctx,
4162 reg_string_to_val(tctx, lp_iconv_convenience(tctx->lp_ctx),
4163 "REG_SZ", "dog", &type, &blob), "");
4165 torture_assert(tctx,
4166 test_SetPrinterData(tctx, b, handle, values[i], REG_SZ, blob.data, blob.length),
4167 "SetPrinterData failed");
4169 torture_assert(tctx,
4170 test_GetPrinterData(tctx, b, handle, values[i], &type, &data, &needed),
4171 "GetPrinterData failed");
4173 torture_assert_int_equal(tctx, type, REG_SZ, "type mismatch");
4174 torture_assert_int_equal(tctx, needed, blob.length, "size mismatch");
4175 torture_assert_mem_equal(tctx, data, blob.data, blob.length, "buffer mismatch");
4177 if (winreg_handle && hive_handle) {
4179 enum winreg_Type w_type;
4180 uint32_t w_size;
4181 uint32_t w_length;
4182 uint8_t *w_data;
4184 torture_assert(tctx,
4185 test_winreg_query_printerdata(tctx, winreg_handle, hive_handle,
4186 printer_name, "PrinterDriverData", values[i],
4187 &w_type, &w_size, &w_length, &w_data), "");
4189 torture_assert_int_equal(tctx, w_type, REG_SZ, "winreg type mismatch");
4190 torture_assert_int_equal(tctx, w_size, blob.length, "winreg size mismatch");
4191 torture_assert_int_equal(tctx, w_length, blob.length, "winreg length mismatch");
4192 torture_assert_mem_equal(tctx, w_data, blob.data, blob.length, "winreg buffer mismatch");
4195 torture_assert(tctx,
4196 test_DeletePrinterData(tctx, b, handle, values[i]),
4197 "DeletePrinterData failed");
4200 return true;
4204 static bool test_EnumPrinterKey(struct torture_context *tctx,
4205 struct dcerpc_binding_handle *b,
4206 struct policy_handle *handle,
4207 const char *key_name,
4208 const char ***array);
4210 static bool test_SetPrinterDataEx(struct torture_context *tctx,
4211 struct dcerpc_binding_handle *b,
4212 struct policy_handle *handle,
4213 const char *key_name,
4214 const char *value_name,
4215 enum winreg_Type type,
4216 uint8_t *data,
4217 uint32_t offered)
4219 NTSTATUS status;
4220 struct spoolss_SetPrinterDataEx r;
4222 r.in.handle = handle;
4223 r.in.key_name = key_name;
4224 r.in.value_name = value_name;
4225 r.in.type = type;
4226 r.in.data = data;
4227 r.in.offered = offered;
4229 torture_comment(tctx, "Testing SetPrinterDataEx(%s - %s) type: %s, offered: 0x%08x\n",
4230 r.in.key_name, r.in.value_name, str_regtype(r.in.type), r.in.offered);
4232 status = dcerpc_spoolss_SetPrinterDataEx_r(b, tctx, &r);
4234 torture_assert_ntstatus_ok(tctx, status, "SetPrinterDataEx failed");
4235 torture_assert_werr_ok(tctx, r.out.result, "SetPrinterDataEx failed");
4237 return true;
4240 static bool test_SetPrinterDataEx_matrix(struct torture_context *tctx,
4241 struct dcerpc_pipe *p,
4242 struct policy_handle *handle,
4243 const char *printername,
4244 struct dcerpc_binding_handle *winreg_handle,
4245 struct policy_handle *hive_handle)
4247 struct dcerpc_binding_handle *b = p->binding_handle;
4248 const char *value_name = "dog";
4249 const char *keys[] = {
4250 "torturedataex",
4251 "torture data ex",
4252 #if 0
4253 /* FIXME: not working with s3 atm. */
4254 "torturedataex_with_subkey\\subkey",
4255 "torturedataex_with_subkey\\subkey:0",
4256 "torturedataex_with_subkey\\subkey:1",
4257 "torturedataex_with_subkey\\subkey\\subsubkey",
4258 "torturedataex_with_subkey\\subkey\\subsubkey:0",
4259 "torturedataex_with_subkey\\subkey\\subsubkey:1",
4260 #endif
4261 "torture,data",
4262 #if 0
4263 /* FIXME: not working with s3 atm. */
4265 "torture,data,ex",
4266 "torture,data\\ex",
4267 "torture\\data,ex"
4268 #endif
4270 enum winreg_Type types[] = {
4271 REG_SZ,
4272 REG_MULTI_SZ,
4273 REG_DWORD,
4274 REG_BINARY
4276 const char *str = "abcdefghijklmnopqrstuvwxzy";
4277 int i, t, s;
4280 for (i=0; i < ARRAY_SIZE(keys); i++) {
4281 for (t=0; t < ARRAY_SIZE(types); t++) {
4282 for (s=0; s < strlen(str); s++) {
4284 char *c;
4285 const char *key;
4286 enum winreg_Type type;
4287 const char *string = talloc_strndup(tctx, str, s);
4288 DATA_BLOB blob = data_blob_string_const(string);
4289 const char **subkeys;
4290 DATA_BLOB data;
4291 uint8_t *data_out;
4292 uint32_t needed, offered = 0;
4293 uint32_t ecount;
4294 struct spoolss_PrinterEnumValues *einfo;
4296 if (types[t] == REG_DWORD) {
4297 s = 0xffff;
4300 if (torture_setting_bool(tctx, "samba3", false)) {
4301 if ((types[t] == REG_MULTI_SZ) && s == 0) {
4302 torture_warning(tctx, "samba3 does not handle 4 byte emtpy REG_MULTI_SZ buffers");
4303 continue;
4307 switch (types[t]) {
4308 case REG_BINARY:
4309 data = blob;
4310 offered = blob.length;
4311 break;
4312 case REG_DWORD:
4313 data = data_blob_talloc(tctx, NULL, 4);
4314 SIVAL(data.data, 0, 0x12345678);
4315 offered = 4;
4316 break;
4317 case REG_SZ:
4318 torture_assert(tctx,
4319 reg_string_to_val(tctx, lp_iconv_convenience(tctx->lp_ctx),
4320 "REG_SZ", string, &type, &data), "");
4321 offered = data.length;
4322 /*strlen_m_term(data.string)*2;*/
4323 break;
4324 case REG_MULTI_SZ:
4325 torture_assert(tctx,
4326 reg_string_to_val(tctx, lp_iconv_convenience(tctx->lp_ctx),
4327 "REG_SZ", string, &type, &data), "");
4328 torture_assert(tctx, data_blob_realloc(tctx, &data, data.length + 2), "");
4329 memset(&data.data[data.length - 2], '\0', 2);
4330 offered = data.length;
4331 break;
4332 default:
4333 torture_fail(tctx, talloc_asprintf(tctx, "type %d untested\n", types[t]));
4336 torture_assert(tctx,
4337 test_SetPrinterDataEx(tctx, b, handle, keys[i], value_name, types[t], data.data, offered),
4338 "failed to call SetPrinterDataEx");
4340 torture_assert(tctx,
4341 test_GetPrinterDataEx(tctx, p, handle, keys[i], value_name, &type, &data_out, &needed),
4342 "failed to call GetPrinterDataEx");
4344 torture_assert(tctx,
4345 test_EnumPrinterDataEx(tctx, b, handle, keys[i], &ecount, &einfo),
4346 "failed to call EnumPrinterDataEx");
4348 torture_assert_int_equal(tctx, types[t], type, "type mismatch");
4349 torture_assert_int_equal(tctx, needed, offered, "size mismatch");
4350 torture_assert_mem_equal(tctx, data_out, data.data, offered, "buffer mismatch");
4352 torture_assert_int_equal(tctx, ecount, 1, "unexpected enum count");
4353 torture_assert_str_equal(tctx, einfo[0].value_name, value_name, "value_name mismatch");
4354 torture_assert_int_equal(tctx, einfo[0].value_name_len, strlen_m_term(value_name)*2, "unexpected value_name_len");
4355 torture_assert_int_equal(tctx, einfo[0].type, types[t], "type mismatch");
4356 torture_assert_int_equal(tctx, einfo[0].data_length, offered, "size mismatch");
4357 if (einfo[0].data_length > 0) {
4358 torture_assert_mem_equal(tctx, einfo[0].data->data, data.data, offered, "buffer mismatch");
4361 if (winreg_handle && hive_handle) {
4362 enum winreg_Type w_type;
4363 uint32_t w_size;
4364 uint32_t w_length;
4365 uint8_t *w_data;
4367 torture_assert(tctx,
4368 test_winreg_query_printerdata(tctx, winreg_handle, hive_handle,
4369 printername, keys[i], value_name,
4370 &w_type, &w_size, &w_length, &w_data), "");
4372 torture_assert_int_equal(tctx, w_type, types[t], "winreg type mismatch");
4373 torture_assert_int_equal(tctx, w_size, offered, "winreg size mismatch");
4374 torture_assert_int_equal(tctx, w_length, offered, "winreg length mismatch");
4375 torture_assert_mem_equal(tctx, w_data, data.data, offered, "winreg buffer mismatch");
4378 key = talloc_strdup(tctx, keys[i]);
4380 if (!test_DeletePrinterDataEx(tctx, b, handle, keys[i], value_name)) {
4381 return false;
4384 c = strchr(key, '\\');
4385 if (c) {
4386 int k;
4388 /* we have subkeys */
4390 *c = 0;
4392 if (!test_EnumPrinterKey(tctx, b, handle, key, &subkeys)) {
4393 return false;
4396 for (k=0; subkeys && subkeys[k]; k++) {
4398 const char *current_key = talloc_asprintf(tctx, "%s\\%s", key, subkeys[k]);
4400 if (!test_DeletePrinterKey(tctx, b, handle, current_key)) {
4401 return false;
4405 if (!test_DeletePrinterKey(tctx, b, handle, key)) {
4406 return false;
4409 } else {
4410 if (!test_DeletePrinterKey(tctx, b, handle, key)) {
4411 return false;
4418 return true;
4421 static bool test_PrinterData_winreg(struct torture_context *tctx,
4422 struct dcerpc_pipe *p,
4423 struct policy_handle *handle,
4424 const char *printer_name)
4426 struct dcerpc_binding_handle *b = p->binding_handle;
4427 struct dcerpc_pipe *p2;
4428 bool ret = true;
4429 struct policy_handle hive_handle;
4430 struct dcerpc_binding_handle *b2;
4432 torture_assert_ntstatus_ok(tctx,
4433 torture_rpc_connection(tctx, &p2, &ndr_table_winreg),
4434 "could not open winreg pipe");
4435 b2 = p2->binding_handle;
4437 torture_assert(tctx, test_winreg_OpenHKLM(tctx, b2, &hive_handle), "");
4439 ret &= test_SetPrinterData_matrix(tctx, b, handle, printer_name, b2, &hive_handle);
4440 ret &= test_SetPrinterDataEx_matrix(tctx, p, handle, printer_name, b2, &hive_handle);
4442 test_winreg_CloseKey(tctx, b2, &hive_handle);
4444 talloc_free(p2);
4446 return ret;
4449 static bool test_Forms_winreg(struct torture_context *tctx,
4450 struct dcerpc_binding_handle *b,
4451 struct policy_handle *handle,
4452 bool print_server,
4453 const char *printer_name)
4455 struct dcerpc_pipe *p2;
4456 bool ret = true;
4457 struct policy_handle hive_handle;
4458 struct dcerpc_binding_handle *b2;
4460 torture_assert_ntstatus_ok(tctx,
4461 torture_rpc_connection(tctx, &p2, &ndr_table_winreg),
4462 "could not open winreg pipe");
4463 b2 = p2->binding_handle;
4465 torture_assert(tctx, test_winreg_OpenHKLM(tctx, b2, &hive_handle), "");
4467 ret = test_Forms(tctx, b, handle, print_server, printer_name, b2, &hive_handle);
4469 test_winreg_CloseKey(tctx, b2, &hive_handle);
4471 talloc_free(p2);
4473 return ret;
4476 static bool test_PrinterInfo_winreg(struct torture_context *tctx,
4477 struct dcerpc_pipe *p,
4478 struct policy_handle *handle,
4479 const char *printer_name)
4481 struct dcerpc_binding_handle *b = p->binding_handle;
4482 struct dcerpc_pipe *p2;
4483 bool ret = true;
4484 struct policy_handle hive_handle;
4485 struct dcerpc_binding_handle *b2;
4487 torture_assert_ntstatus_ok(tctx,
4488 torture_rpc_connection(tctx, &p2, &ndr_table_winreg),
4489 "could not open winreg pipe");
4490 b2 = p2->binding_handle;
4492 torture_assert(tctx, test_winreg_OpenHKLM(tctx, b2, &hive_handle), "");
4494 ret = test_GetPrinterInfo_winreg(tctx, b, handle, printer_name, b2, &hive_handle);
4496 test_winreg_CloseKey(tctx, b2, &hive_handle);
4498 talloc_free(p2);
4500 return ret;
4503 static bool test_GetChangeID_PrinterData(struct torture_context *tctx,
4504 struct dcerpc_binding_handle *b,
4505 struct policy_handle *handle,
4506 uint32_t *change_id)
4508 enum winreg_Type type;
4509 uint8_t *data;
4510 uint32_t needed;
4512 torture_assert(tctx,
4513 test_GetPrinterData(tctx, b, handle, "ChangeID", &type, &data, &needed),
4514 "failed to call GetPrinterData");
4516 torture_assert(tctx, type == REG_DWORD, "unexpected type");
4517 torture_assert_int_equal(tctx, needed, 4, "unexpected size");
4519 *change_id = IVAL(data, 0);
4521 return true;
4524 static bool test_GetChangeID_PrinterDataEx(struct torture_context *tctx,
4525 struct dcerpc_pipe *p,
4526 struct policy_handle *handle,
4527 uint32_t *change_id)
4529 enum winreg_Type type;
4530 uint8_t *data;
4531 uint32_t needed;
4533 torture_assert(tctx,
4534 test_GetPrinterDataEx(tctx, p, handle, "PrinterDriverData", "ChangeID", &type, &data, &needed),
4535 "failed to call GetPrinterData");
4537 torture_assert(tctx, type == REG_DWORD, "unexpected type");
4538 torture_assert_int_equal(tctx, needed, 4, "unexpected size");
4540 *change_id = IVAL(data, 0);
4542 return true;
4545 static bool test_GetChangeID_PrinterInfo(struct torture_context *tctx,
4546 struct dcerpc_binding_handle *b,
4547 struct policy_handle *handle,
4548 uint32_t *change_id)
4550 union spoolss_PrinterInfo info;
4552 torture_assert(tctx, test_GetPrinter_level(tctx, b, handle, 0, &info),
4553 "failed to query Printer level 0");
4555 *change_id = info.info0.change_id;
4557 return true;
4560 static bool test_ChangeID(struct torture_context *tctx,
4561 struct dcerpc_pipe *p,
4562 struct policy_handle *handle)
4564 uint32_t change_id, change_id_ex, change_id_info;
4565 uint32_t change_id2, change_id_ex2, change_id_info2;
4566 union spoolss_PrinterInfo info;
4567 const char *comment;
4568 struct dcerpc_binding_handle *b = p->binding_handle;
4570 torture_comment(tctx, "Testing ChangeID: id change test #1\n");
4572 torture_assert(tctx, test_GetChangeID_PrinterData(tctx, b, handle, &change_id),
4573 "failed to query for ChangeID");
4574 torture_assert(tctx, test_GetChangeID_PrinterDataEx(tctx, p, handle, &change_id_ex),
4575 "failed to query for ChangeID");
4576 torture_assert(tctx, test_GetChangeID_PrinterInfo(tctx, b, handle, &change_id_info),
4577 "failed to query for ChangeID");
4579 torture_assert_int_equal(tctx, change_id, change_id_ex,
4580 "change_ids should all be equal");
4581 torture_assert_int_equal(tctx, change_id_ex, change_id_info,
4582 "change_ids should all be equal");
4585 torture_comment(tctx, "Testing ChangeID: id change test #2\n");
4587 torture_assert(tctx, test_GetChangeID_PrinterData(tctx, b, handle, &change_id),
4588 "failed to query for ChangeID");
4589 torture_assert(tctx, test_GetPrinter_level(tctx, b, handle, 2, &info),
4590 "failed to query Printer level 2");
4591 torture_assert(tctx, test_GetChangeID_PrinterDataEx(tctx, p, handle, &change_id_ex),
4592 "failed to query for ChangeID");
4593 torture_assert(tctx, test_GetChangeID_PrinterInfo(tctx, b, handle, &change_id_info),
4594 "failed to query for ChangeID");
4595 torture_assert_int_equal(tctx, change_id, change_id_ex,
4596 "change_id should not have changed");
4597 torture_assert_int_equal(tctx, change_id_ex, change_id_info,
4598 "change_id should not have changed");
4601 torture_comment(tctx, "Testing ChangeID: id change test #3\n");
4603 torture_assert(tctx, test_GetChangeID_PrinterData(tctx, b, handle, &change_id),
4604 "failed to query for ChangeID");
4605 torture_assert(tctx, test_GetChangeID_PrinterDataEx(tctx, p, handle, &change_id_ex),
4606 "failed to query for ChangeID");
4607 torture_assert(tctx, test_GetChangeID_PrinterInfo(tctx, b, handle, &change_id_info),
4608 "failed to query for ChangeID");
4609 torture_assert(tctx, test_GetPrinter_level(tctx, b, handle, 2, &info),
4610 "failed to query Printer level 2");
4611 comment = talloc_strdup(tctx, info.info2.comment);
4614 struct spoolss_SetPrinterInfoCtr info_ctr;
4615 struct spoolss_DevmodeContainer devmode_ctr;
4616 struct sec_desc_buf secdesc_ctr;
4617 union spoolss_SetPrinterInfo sinfo;
4619 ZERO_STRUCT(info_ctr);
4620 ZERO_STRUCT(devmode_ctr);
4621 ZERO_STRUCT(secdesc_ctr);
4624 torture_assert(tctx, PrinterInfo_to_SetPrinterInfo(tctx, &info, 2, &sinfo), "");
4625 sinfo.info2->comment = "torture_comment";
4627 info_ctr.level = 2;
4628 info_ctr.info = sinfo;
4630 torture_assert(tctx, test_SetPrinter(tctx, b, handle, &info_ctr, &devmode_ctr, &secdesc_ctr, 0),
4631 "failed to call SetPrinter");
4633 sinfo.info2->comment = comment;
4635 torture_assert(tctx, test_SetPrinter(tctx, b, handle, &info_ctr, &devmode_ctr, &secdesc_ctr, 0),
4636 "failed to call SetPrinter");
4640 torture_assert(tctx, test_GetChangeID_PrinterData(tctx, b, handle, &change_id2),
4641 "failed to query for ChangeID");
4642 torture_assert(tctx, test_GetChangeID_PrinterDataEx(tctx, p, handle, &change_id_ex2),
4643 "failed to query for ChangeID");
4644 torture_assert(tctx, test_GetChangeID_PrinterInfo(tctx, b, handle, &change_id_info2),
4645 "failed to query for ChangeID");
4647 torture_assert_int_equal(tctx, change_id2, change_id_ex2,
4648 "change_ids should all be equal");
4649 torture_assert_int_equal(tctx, change_id_ex2, change_id_info2,
4650 "change_ids should all be equal");
4652 torture_assert(tctx, (change_id < change_id2),
4653 talloc_asprintf(tctx, "change_id %d needs to be larger than change_id %d",
4654 change_id2, change_id));
4655 torture_assert(tctx, (change_id_ex < change_id_ex2),
4656 talloc_asprintf(tctx, "change_id %d needs to be larger than change_id %d",
4657 change_id_ex2, change_id_ex));
4658 torture_assert(tctx, (change_id_info < change_id_info2),
4659 talloc_asprintf(tctx, "change_id %d needs to be larger than change_id %d",
4660 change_id_info2, change_id_info));
4662 torture_comment(tctx, "ChangeID tests succeeded\n\n");
4664 return true;
4667 static bool test_SecondaryClosePrinter(struct torture_context *tctx,
4668 struct dcerpc_pipe *p,
4669 struct policy_handle *handle)
4671 NTSTATUS status;
4672 struct dcerpc_binding *b;
4673 struct dcerpc_pipe *p2;
4674 struct spoolss_ClosePrinter cp;
4676 /* only makes sense on SMB */
4677 if (p->conn->transport.transport != NCACN_NP) {
4678 return true;
4681 torture_comment(tctx, "Testing close on secondary pipe\n");
4683 status = dcerpc_parse_binding(tctx, p->conn->binding_string, &b);
4684 torture_assert_ntstatus_ok(tctx, status, "Failed to parse dcerpc binding");
4686 status = dcerpc_secondary_connection(p, &p2, b);
4687 torture_assert_ntstatus_ok(tctx, status, "Failed to create secondary connection");
4689 status = dcerpc_bind_auth_none(p2, &ndr_table_spoolss);
4690 torture_assert_ntstatus_ok(tctx, status, "Failed to create bind on secondary connection");
4692 cp.in.handle = handle;
4693 cp.out.handle = handle;
4695 status = dcerpc_spoolss_ClosePrinter_r(p2->binding_handle, tctx, &cp);
4696 torture_assert_ntstatus_equal(tctx, status, NT_STATUS_NET_WRITE_FAULT,
4697 "ERROR: Allowed close on secondary connection");
4699 torture_assert_int_equal(tctx, p2->last_fault_code, DCERPC_FAULT_CONTEXT_MISMATCH,
4700 "Unexpected fault code");
4702 talloc_free(p2);
4704 return true;
4707 static bool test_OpenPrinter_badname(struct torture_context *tctx,
4708 struct dcerpc_binding_handle *b, const char *name)
4710 NTSTATUS status;
4711 struct spoolss_OpenPrinter op;
4712 struct spoolss_OpenPrinterEx opEx;
4713 struct policy_handle handle;
4714 bool ret = true;
4716 op.in.printername = name;
4717 op.in.datatype = NULL;
4718 op.in.devmode_ctr.devmode= NULL;
4719 op.in.access_mask = 0;
4720 op.out.handle = &handle;
4722 torture_comment(tctx, "Testing OpenPrinter(%s) with bad name\n", op.in.printername);
4724 status = dcerpc_spoolss_OpenPrinter_r(b, tctx, &op);
4725 torture_assert_ntstatus_ok(tctx, status, "OpenPrinter failed");
4726 torture_assert_werr_equal(tctx, op.out.result, WERR_INVALID_PRINTER_NAME,
4727 "unexpected result");
4729 if (W_ERROR_IS_OK(op.out.result)) {
4730 ret &=test_ClosePrinter(tctx, b, &handle);
4733 opEx.in.printername = name;
4734 opEx.in.datatype = NULL;
4735 opEx.in.devmode_ctr.devmode = NULL;
4736 opEx.in.access_mask = 0;
4737 opEx.in.level = 1;
4738 opEx.in.userlevel.level1 = NULL;
4739 opEx.out.handle = &handle;
4741 torture_comment(tctx, "Testing OpenPrinterEx(%s) with bad name\n", opEx.in.printername);
4743 status = dcerpc_spoolss_OpenPrinterEx_r(b, tctx, &opEx);
4744 torture_assert_ntstatus_ok(tctx, status, "OpenPrinterEx failed");
4745 torture_assert_werr_equal(tctx, opEx.out.result, WERR_INVALID_PARAM,
4746 "unexpected result");
4748 if (W_ERROR_IS_OK(opEx.out.result)) {
4749 ret &=test_ClosePrinter(tctx, b, &handle);
4752 return ret;
4755 static bool test_OpenPrinter_badname_list(struct torture_context *tctx,
4756 struct dcerpc_binding_handle *b,
4757 const char *server_name)
4759 const char *badnames[] = {
4760 "__INVALID_PRINTER__",
4761 "\\\\__INVALID_HOST__",
4763 "\\\\\\",
4764 "\\\\\\__INVALID_PRINTER__"
4766 const char *badname;
4767 int i;
4769 for (i=0; i < ARRAY_SIZE(badnames); i++) {
4770 torture_assert(tctx,
4771 test_OpenPrinter_badname(tctx, b, badnames[i]),
4772 "");
4775 badname = talloc_asprintf(tctx, "\\\\%s\\", server_name);
4776 torture_assert(tctx,
4777 test_OpenPrinter_badname(tctx, b, badname),
4778 "");
4780 badname = talloc_asprintf(tctx, "\\\\%s\\__INVALID_PRINTER__", server_name);
4781 torture_assert(tctx,
4782 test_OpenPrinter_badname(tctx, b, badname),
4783 "");
4785 return true;
4788 static bool test_OpenPrinter(struct torture_context *tctx,
4789 struct dcerpc_pipe *p,
4790 const char *name,
4791 const char *environment)
4793 NTSTATUS status;
4794 struct spoolss_OpenPrinter r;
4795 struct policy_handle handle;
4796 bool ret = true;
4797 struct dcerpc_binding_handle *b = p->binding_handle;
4799 r.in.printername = talloc_asprintf(tctx, "\\\\%s\\%s", dcerpc_server_name(p), name);
4800 r.in.datatype = NULL;
4801 r.in.devmode_ctr.devmode= NULL;
4802 r.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
4803 r.out.handle = &handle;
4805 torture_comment(tctx, "Testing OpenPrinter(%s)\n", r.in.printername);
4807 status = dcerpc_spoolss_OpenPrinter_r(b, tctx, &r);
4809 torture_assert_ntstatus_ok(tctx, status, "OpenPrinter failed");
4811 torture_assert_werr_ok(tctx, r.out.result, "OpenPrinter failed");
4813 if (!test_GetPrinter(tctx, b, &handle, environment)) {
4814 ret = false;
4817 if (!torture_setting_bool(tctx, "samba3", false)) {
4818 if (!test_SecondaryClosePrinter(tctx, p, &handle)) {
4819 ret = false;
4823 if (!test_ClosePrinter(tctx, b, &handle)) {
4824 ret = false;
4827 return ret;
4830 static bool call_OpenPrinterEx(struct torture_context *tctx,
4831 struct dcerpc_pipe *p,
4832 const char *name,
4833 struct spoolss_DeviceMode *devmode,
4834 struct policy_handle *handle)
4836 struct spoolss_OpenPrinterEx r;
4837 struct spoolss_UserLevel1 userlevel1;
4838 NTSTATUS status;
4839 struct dcerpc_binding_handle *b = p->binding_handle;
4841 if (name && name[0]) {
4842 r.in.printername = talloc_asprintf(tctx, "\\\\%s\\%s",
4843 dcerpc_server_name(p), name);
4844 } else {
4845 r.in.printername = talloc_asprintf(tctx, "\\\\%s",
4846 dcerpc_server_name(p));
4849 r.in.datatype = NULL;
4850 r.in.devmode_ctr.devmode= devmode;
4851 r.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
4852 r.in.level = 1;
4853 r.in.userlevel.level1 = &userlevel1;
4854 r.out.handle = handle;
4856 userlevel1.size = 1234;
4857 userlevel1.client = "hello";
4858 userlevel1.user = "spottyfoot!";
4859 userlevel1.build = 1;
4860 userlevel1.major = 2;
4861 userlevel1.minor = 3;
4862 userlevel1.processor = 4;
4864 torture_comment(tctx, "Testing OpenPrinterEx(%s)\n", r.in.printername);
4866 status = dcerpc_spoolss_OpenPrinterEx_r(b, tctx, &r);
4868 torture_assert_ntstatus_ok(tctx, status, "OpenPrinterEx failed");
4870 torture_assert_werr_ok(tctx, r.out.result, "OpenPrinterEx failed");
4872 return true;
4875 static bool test_printer_rename(struct torture_context *tctx,
4876 struct dcerpc_pipe *p,
4877 struct policy_handle *handle,
4878 const char *name)
4880 bool ret = true;
4881 union spoolss_PrinterInfo info;
4882 union spoolss_SetPrinterInfo sinfo;
4883 struct spoolss_SetPrinterInfoCtr info_ctr;
4884 struct spoolss_DevmodeContainer devmode_ctr;
4885 struct sec_desc_buf secdesc_ctr;
4886 const char *printer_name;
4887 const char *printer_name_orig;
4888 const char *printer_name_new = "SAMBA smbtorture Test Printer (Copy 2)";
4889 struct policy_handle new_handle;
4890 const char *q;
4891 struct dcerpc_binding_handle *b = p->binding_handle;
4893 ZERO_STRUCT(devmode_ctr);
4894 ZERO_STRUCT(secdesc_ctr);
4896 torture_comment(tctx, "Testing Printer rename operations\n");
4898 torture_assert(tctx,
4899 test_GetPrinter_level(tctx, b, handle, 2, &info),
4900 "failed to call GetPrinter level 2");
4902 printer_name_orig = talloc_strdup(tctx, info.info2.printername);
4904 q = strrchr(info.info2.printername, '\\');
4905 if (q) {
4906 torture_warning(tctx,
4907 "server returns printername %s incl. servername although we did not set servername", info.info2.printername);
4910 torture_assert(tctx,
4911 PrinterInfo_to_SetPrinterInfo(tctx, &info, 2, &sinfo), "");
4913 sinfo.info2->printername = printer_name_new;
4915 info_ctr.level = 2;
4916 info_ctr.info = sinfo;
4918 torture_assert(tctx,
4919 test_SetPrinter(tctx, b, handle, &info_ctr, &devmode_ctr, &secdesc_ctr, 0),
4920 "failed to call SetPrinter level 2");
4922 torture_assert(tctx,
4923 test_GetPrinter_level(tctx, b, handle, 2, &info),
4924 "failed to call GetPrinter level 2");
4926 printer_name = talloc_strdup(tctx, info.info2.printername);
4928 q = strrchr(info.info2.printername, '\\');
4929 if (q) {
4930 torture_warning(tctx,
4931 "server returns printername %s incl. servername although we did not set servername", info.info2.printername);
4932 q++;
4933 printer_name = q;
4936 torture_assert_str_equal(tctx, printer_name, printer_name_new,
4937 "new printer name was not set");
4939 /* samba currently cannot fully rename printers */
4940 if (!torture_setting_bool(tctx, "samba3", false)) {
4941 torture_assert(tctx,
4942 test_OpenPrinter_badname(tctx, b, printer_name_orig),
4943 "still can open printer with oldname after rename");
4944 } else {
4945 torture_warning(tctx, "*not* checking for open with oldname after rename for samba3");
4948 torture_assert(tctx,
4949 call_OpenPrinterEx(tctx, p, printer_name_new, NULL, &new_handle),
4950 "failed to open printer with new name");
4952 torture_assert(tctx,
4953 test_GetPrinter_level(tctx, b, &new_handle, 2, &info),
4954 "failed to call GetPrinter level 2");
4956 /* FIXME: we openend with servername! */
4957 printer_name = talloc_asprintf(tctx, "\\\\%s\\%s",
4958 dcerpc_server_name(p), printer_name_new);
4960 torture_assert_str_equal(tctx, info.info2.printername, printer_name,
4961 "new printer name was not set");
4963 torture_assert(tctx,
4964 test_ClosePrinter(tctx, b, &new_handle),
4965 "failed to close printer");
4967 torture_comment(tctx, "Printer rename operations test succeeded\n\n");
4969 return ret;
4973 static bool test_OpenPrinterEx(struct torture_context *tctx,
4974 struct dcerpc_pipe *p,
4975 const char *name,
4976 const char *environment)
4978 struct policy_handle handle;
4979 bool ret = true;
4980 struct dcerpc_binding_handle *b = p->binding_handle;
4982 if (!call_OpenPrinterEx(tctx, p, name, NULL, &handle)) {
4983 return false;
4986 if (!test_PrinterInfo_SD(tctx, b, &handle)) {
4987 ret = false;
4990 if (!test_GetPrinter(tctx, b, &handle, environment)) {
4991 ret = false;
4994 if (!test_EnumForms_all(tctx, b, &handle, false)) {
4995 ret = false;
4998 if (!test_Forms(tctx, b, &handle, false, name, NULL, NULL)) {
4999 ret = false;
5002 if (!test_Forms_winreg(tctx, b, &handle, false, name)) {
5003 ret = false;
5006 if (!test_EnumPrinterData_all(tctx, p, &handle)) {
5007 ret = false;
5010 if (!test_EnumPrinterDataEx(tctx, b, &handle, "PrinterDriverData", NULL, NULL)) {
5011 ret = false;
5014 if (!test_EnumPrinterData_consistency(tctx, p, &handle)) {
5015 ret = false;
5018 if (!test_printer_keys(tctx, b, &handle)) {
5019 ret = false;
5022 if (!test_PausePrinter(tctx, b, &handle)) {
5023 ret = false;
5026 if (!test_DoPrintTest(tctx, b, &handle)) {
5027 ret = false;
5030 if (!test_ResumePrinter(tctx, b, &handle)) {
5031 ret = false;
5034 if (!test_SetPrinterData_matrix(tctx, b, &handle, name, NULL, NULL)) {
5035 ret = false;
5038 if (!test_SetPrinterDataEx_matrix(tctx, p, &handle, name, NULL, NULL)) {
5039 ret = false;
5042 if (!torture_setting_bool(tctx, "samba3", false)) {
5043 if (!test_SecondaryClosePrinter(tctx, p, &handle)) {
5044 ret = false;
5048 if (!test_ClosePrinter(tctx, b, &handle)) {
5049 ret = false;
5052 return ret;
5055 static bool test_EnumPrinters_old(struct torture_context *tctx,
5056 struct dcerpc_pipe *p,
5057 const char *environment)
5059 struct spoolss_EnumPrinters r;
5060 NTSTATUS status;
5061 uint16_t levels[] = {1, 2, 4, 5};
5062 int i;
5063 bool ret = true;
5064 struct dcerpc_binding_handle *b = p->binding_handle;
5066 for (i=0;i<ARRAY_SIZE(levels);i++) {
5067 union spoolss_PrinterInfo *info;
5068 int j;
5069 uint32_t needed;
5070 uint32_t count;
5072 r.in.flags = PRINTER_ENUM_LOCAL;
5073 r.in.server = "";
5074 r.in.level = levels[i];
5075 r.in.buffer = NULL;
5076 r.in.offered = 0;
5077 r.out.needed = &needed;
5078 r.out.count = &count;
5079 r.out.info = &info;
5081 torture_comment(tctx, "Testing EnumPrinters level %u\n", r.in.level);
5083 status = dcerpc_spoolss_EnumPrinters_r(b, tctx, &r);
5084 torture_assert_ntstatus_ok(tctx, status, "EnumPrinters failed");
5086 if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
5087 DATA_BLOB blob = data_blob_talloc_zero(tctx, needed);
5088 r.in.buffer = &blob;
5089 r.in.offered = needed;
5090 status = dcerpc_spoolss_EnumPrinters_r(b, tctx, &r);
5093 torture_assert_ntstatus_ok(tctx, status, "EnumPrinters failed");
5095 torture_assert_werr_ok(tctx, r.out.result, "EnumPrinters failed");
5097 CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumPrinters, info, r.in.level, count, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
5099 if (!info) {
5100 torture_comment(tctx, "No printers returned\n");
5101 return true;
5104 for (j=0;j<count;j++) {
5105 if (r.in.level == 1) {
5106 char *unc = talloc_strdup(tctx, info[j].info1.name);
5107 char *slash, *name;
5108 name = unc;
5109 if (unc[0] == '\\' && unc[1] == '\\') {
5110 unc +=2;
5112 slash = strchr(unc, '\\');
5113 if (slash) {
5114 slash++;
5115 name = slash;
5117 if (!test_OpenPrinter(tctx, p, name, environment)) {
5118 ret = false;
5120 if (!test_OpenPrinterEx(tctx, p, name, environment)) {
5121 ret = false;
5127 return ret;
5130 static bool test_GetPrinterDriver(struct torture_context *tctx,
5131 struct dcerpc_binding_handle *b,
5132 struct policy_handle *handle,
5133 const char *driver_name)
5135 struct spoolss_GetPrinterDriver r;
5136 uint32_t needed;
5138 r.in.handle = handle;
5139 r.in.architecture = "W32X86";
5140 r.in.level = 1;
5141 r.in.buffer = NULL;
5142 r.in.offered = 0;
5143 r.out.needed = &needed;
5145 torture_comment(tctx, "Testing GetPrinterDriver level %d\n", r.in.level);
5147 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_GetPrinterDriver_r(b, tctx, &r),
5148 "failed to call GetPrinterDriver");
5149 if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
5150 DATA_BLOB blob = data_blob_talloc_zero(tctx, needed);
5151 r.in.buffer = &blob;
5152 r.in.offered = needed;
5153 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_GetPrinterDriver_r(b, tctx, &r),
5154 "failed to call GetPrinterDriver");
5157 torture_assert_werr_ok(tctx, r.out.result,
5158 "failed to call GetPrinterDriver");
5160 CHECK_NEEDED_SIZE_LEVEL(spoolss_DriverInfo, r.out.info, r.in.level, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
5162 return true;
5165 static bool test_GetPrinterDriver2(struct torture_context *tctx,
5166 struct dcerpc_binding_handle *b,
5167 struct policy_handle *handle,
5168 const char *driver_name,
5169 const char *architecture)
5171 struct spoolss_GetPrinterDriver2 r;
5172 uint16_t levels[] = {1, 2, 3, 4, 5, 6, 8, 101 };
5173 uint32_t needed;
5174 uint32_t server_major_version;
5175 uint32_t server_minor_version;
5176 int i;
5178 r.in.handle = handle;
5179 r.in.architecture = architecture;
5180 r.in.client_major_version = 3;
5181 r.in.client_minor_version = 0;
5182 r.out.needed = &needed;
5183 r.out.server_major_version = &server_major_version;
5184 r.out.server_minor_version = &server_minor_version;
5186 for (i=0;i<ARRAY_SIZE(levels);i++) {
5188 r.in.buffer = NULL;
5189 r.in.offered = 0;
5190 r.in.level = levels[i];
5192 torture_comment(tctx, "Testing GetPrinterDriver2(%s) level %d\n",
5193 driver_name, r.in.level);
5195 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_GetPrinterDriver2_r(b, tctx, &r),
5196 "failed to call GetPrinterDriver2");
5197 if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
5198 DATA_BLOB blob = data_blob_talloc_zero(tctx, needed);
5199 r.in.buffer = &blob;
5200 r.in.offered = needed;
5201 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_GetPrinterDriver2_r(b, tctx, &r),
5202 "failed to call GetPrinterDriver2");
5205 if (W_ERROR_EQUAL(r.out.result, WERR_INVALID_LEVEL)) {
5206 switch (r.in.level) {
5207 case 101:
5208 case 8:
5209 continue;
5210 default:
5211 break;
5215 torture_assert_werr_ok(tctx, r.out.result,
5216 "failed to call GetPrinterDriver2");
5218 CHECK_NEEDED_SIZE_LEVEL(spoolss_DriverInfo, r.out.info, r.in.level, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
5221 return true;
5224 static bool test_EnumPrinterDrivers_old(struct torture_context *tctx,
5225 struct dcerpc_pipe *p,
5226 const char *environment)
5228 struct spoolss_EnumPrinterDrivers r;
5229 NTSTATUS status;
5230 uint16_t levels[] = {1, 2, 3, 4, 5, 6};
5231 int i;
5232 struct dcerpc_binding_handle *b = p->binding_handle;
5234 for (i=0;i<ARRAY_SIZE(levels);i++) {
5236 uint32_t needed;
5237 uint32_t count;
5238 union spoolss_DriverInfo *info;
5240 r.in.server = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
5241 r.in.environment = environment;
5242 r.in.level = levels[i];
5243 r.in.buffer = NULL;
5244 r.in.offered = 0;
5245 r.out.needed = &needed;
5246 r.out.count = &count;
5247 r.out.info = &info;
5249 torture_comment(tctx, "Testing EnumPrinterDrivers level %u\n", r.in.level);
5251 status = dcerpc_spoolss_EnumPrinterDrivers_r(b, tctx, &r);
5253 torture_assert_ntstatus_ok(tctx, status, "EnumPrinterDrivers failed");
5255 if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
5256 DATA_BLOB blob = data_blob_talloc_zero(tctx, needed);
5257 r.in.buffer = &blob;
5258 r.in.offered = needed;
5259 status = dcerpc_spoolss_EnumPrinterDrivers_r(b, tctx, &r);
5262 torture_assert_ntstatus_ok(tctx, status, "EnumPrinterDrivers failed");
5264 torture_assert_werr_ok(tctx, r.out.result, "EnumPrinterDrivers failed");
5266 if (!info) {
5267 torture_comment(tctx, "No printer drivers returned\n");
5268 break;
5271 CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumPrinterDrivers, info, r.in.level, count, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
5274 return true;
5277 static bool test_DeletePrinter(struct torture_context *tctx,
5278 struct dcerpc_binding_handle *b,
5279 struct policy_handle *handle)
5281 struct spoolss_DeletePrinter r;
5283 torture_comment(tctx, "Testing DeletePrinter\n");
5285 r.in.handle = handle;
5287 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_DeletePrinter_r(b, tctx, &r),
5288 "failed to delete printer");
5289 torture_assert_werr_ok(tctx, r.out.result,
5290 "failed to delete printer");
5292 return true;
5295 static bool test_EnumPrinters_findname(struct torture_context *tctx,
5296 struct dcerpc_binding_handle *b,
5297 uint32_t flags,
5298 uint32_t level,
5299 const char *name,
5300 bool *found)
5302 struct spoolss_EnumPrinters e;
5303 uint32_t count;
5304 union spoolss_PrinterInfo *info;
5305 uint32_t needed;
5306 int i;
5308 *found = false;
5310 e.in.flags = flags;
5311 e.in.server = NULL;
5312 e.in.level = level;
5313 e.in.buffer = NULL;
5314 e.in.offered = 0;
5315 e.out.count = &count;
5316 e.out.info = &info;
5317 e.out.needed = &needed;
5319 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_EnumPrinters_r(b, tctx, &e),
5320 "failed to enum printers");
5322 if (W_ERROR_EQUAL(e.out.result, WERR_INSUFFICIENT_BUFFER)) {
5323 DATA_BLOB blob = data_blob_talloc_zero(tctx, needed);
5324 e.in.buffer = &blob;
5325 e.in.offered = needed;
5327 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_EnumPrinters_r(b, tctx, &e),
5328 "failed to enum printers");
5331 torture_assert_werr_ok(tctx, e.out.result,
5332 "failed to enum printers");
5334 for (i=0; i < count; i++) {
5336 const char *current = NULL;
5337 const char *q;
5339 switch (level) {
5340 case 1:
5341 current = info[i].info1.name;
5342 break;
5345 if (strequal(current, name)) {
5346 *found = true;
5347 break;
5350 q = strrchr(current, '\\');
5351 if (q) {
5352 if (!e.in.server) {
5353 torture_warning(tctx,
5354 "server returns printername %s incl. servername although we did not set servername", current);
5356 q++;
5357 if (strequal(q, name)) {
5358 *found = true;
5359 break;
5364 return true;
5367 static bool test_AddPrinter_wellknown(struct torture_context *tctx,
5368 struct dcerpc_pipe *p,
5369 const char *printername,
5370 bool ex)
5372 WERROR result;
5373 struct spoolss_AddPrinter r;
5374 struct spoolss_AddPrinterEx rex;
5375 struct spoolss_SetPrinterInfoCtr info_ctr;
5376 struct spoolss_SetPrinterInfo1 info1;
5377 struct spoolss_DevmodeContainer devmode_ctr;
5378 struct sec_desc_buf secdesc_ctr;
5379 struct spoolss_UserLevelCtr userlevel_ctr;
5380 struct policy_handle handle;
5381 bool found = false;
5382 struct dcerpc_binding_handle *b = p->binding_handle;
5384 ZERO_STRUCT(devmode_ctr);
5385 ZERO_STRUCT(secdesc_ctr);
5386 ZERO_STRUCT(userlevel_ctr);
5387 ZERO_STRUCT(info1);
5389 torture_comment(tctx, "Testing AddPrinter%s level 1\n", ex ? "Ex":"");
5391 /* try to add printer to wellknown printer list (level 1) */
5393 userlevel_ctr.level = 1;
5395 info_ctr.info.info1 = &info1;
5396 info_ctr.level = 1;
5398 rex.in.server = NULL;
5399 rex.in.info_ctr = &info_ctr;
5400 rex.in.devmode_ctr = &devmode_ctr;
5401 rex.in.secdesc_ctr = &secdesc_ctr;
5402 rex.in.userlevel_ctr = &userlevel_ctr;
5403 rex.out.handle = &handle;
5405 r.in.server = NULL;
5406 r.in.info_ctr = &info_ctr;
5407 r.in.devmode_ctr = &devmode_ctr;
5408 r.in.secdesc_ctr = &secdesc_ctr;
5409 r.out.handle = &handle;
5411 torture_assert_ntstatus_ok(tctx, ex ? dcerpc_spoolss_AddPrinterEx_r(b, tctx, &rex) :
5412 dcerpc_spoolss_AddPrinter_r(b, tctx, &r),
5413 "failed to add printer");
5414 result = ex ? rex.out.result : r.out.result;
5415 torture_assert_werr_equal(tctx, result, WERR_INVALID_PRINTER_NAME,
5416 "unexpected result code");
5418 info1.name = printername;
5419 info1.flags = PRINTER_ATTRIBUTE_SHARED;
5421 torture_assert_ntstatus_ok(tctx, ex ? dcerpc_spoolss_AddPrinterEx_r(b, tctx, &rex) :
5422 dcerpc_spoolss_AddPrinter_r(b, tctx, &r),
5423 "failed to add printer");
5424 result = ex ? rex.out.result : r.out.result;
5425 torture_assert_werr_equal(tctx, result, WERR_PRINTER_ALREADY_EXISTS,
5426 "unexpected result code");
5428 /* bizarre protocol, WERR_PRINTER_ALREADY_EXISTS means success here,
5429 better do a real check to see the printer is really there */
5431 torture_assert(tctx, test_EnumPrinters_findname(tctx, b,
5432 PRINTER_ENUM_NETWORK, 1,
5433 printername,
5434 &found),
5435 "failed to enum printers");
5437 torture_assert(tctx, found, "failed to find newly added printer");
5439 info1.flags = 0;
5441 torture_assert_ntstatus_ok(tctx, ex ? dcerpc_spoolss_AddPrinterEx_r(b, tctx, &rex) :
5442 dcerpc_spoolss_AddPrinter_r(b, tctx, &r),
5443 "failed to add printer");
5444 result = ex ? rex.out.result : r.out.result;
5445 torture_assert_werr_equal(tctx, result, WERR_PRINTER_ALREADY_EXISTS,
5446 "unexpected result code");
5448 /* bizarre protocol, WERR_PRINTER_ALREADY_EXISTS means success here,
5449 better do a real check to see the printer has really been removed
5450 from the well known printer list */
5452 found = false;
5454 torture_assert(tctx, test_EnumPrinters_findname(tctx, b,
5455 PRINTER_ENUM_NETWORK, 1,
5456 printername,
5457 &found),
5458 "failed to enum printers");
5459 #if 0
5460 torture_assert(tctx, !found, "printer still in well known printer list");
5461 #endif
5462 return true;
5465 static bool test_AddPrinter_normal(struct torture_context *tctx,
5466 struct dcerpc_pipe *p,
5467 struct policy_handle *handle_p,
5468 const char *printername,
5469 const char *drivername,
5470 const char *portname,
5471 bool ex)
5473 WERROR result;
5474 struct spoolss_AddPrinter r;
5475 struct spoolss_AddPrinterEx rex;
5476 struct spoolss_SetPrinterInfoCtr info_ctr;
5477 struct spoolss_SetPrinterInfo2 info2;
5478 struct spoolss_DevmodeContainer devmode_ctr;
5479 struct sec_desc_buf secdesc_ctr;
5480 struct spoolss_UserLevelCtr userlevel_ctr;
5481 struct policy_handle handle;
5482 bool found = false;
5483 bool existing_printer_deleted = false;
5484 struct dcerpc_binding_handle *b = p->binding_handle;
5486 ZERO_STRUCT(devmode_ctr);
5487 ZERO_STRUCT(secdesc_ctr);
5488 ZERO_STRUCT(userlevel_ctr);
5490 torture_comment(tctx, "Testing AddPrinter%s level 2\n", ex ? "Ex":"");
5492 userlevel_ctr.level = 1;
5494 rex.in.server = NULL;
5495 rex.in.info_ctr = &info_ctr;
5496 rex.in.devmode_ctr = &devmode_ctr;
5497 rex.in.secdesc_ctr = &secdesc_ctr;
5498 rex.in.userlevel_ctr = &userlevel_ctr;
5499 rex.out.handle = &handle;
5501 r.in.server = NULL;
5502 r.in.info_ctr = &info_ctr;
5503 r.in.devmode_ctr = &devmode_ctr;
5504 r.in.secdesc_ctr = &secdesc_ctr;
5505 r.out.handle = &handle;
5507 again:
5509 /* try to add printer to printer list (level 2) */
5511 ZERO_STRUCT(info2);
5513 info_ctr.info.info2 = &info2;
5514 info_ctr.level = 2;
5516 torture_assert_ntstatus_ok(tctx, ex ? dcerpc_spoolss_AddPrinterEx_r(b, tctx, &rex) :
5517 dcerpc_spoolss_AddPrinter_r(b, tctx, &r),
5518 "failed to add printer");
5519 result = ex ? rex.out.result : r.out.result;
5520 torture_assert_werr_equal(tctx, result, WERR_INVALID_PRINTER_NAME,
5521 "unexpected result code");
5523 info2.printername = printername;
5525 torture_assert_ntstatus_ok(tctx, ex ? dcerpc_spoolss_AddPrinterEx_r(b, tctx, &rex) :
5526 dcerpc_spoolss_AddPrinter_r(b, tctx, &r),
5527 "failed to add printer");
5528 result = ex ? rex.out.result : r.out.result;
5530 if (W_ERROR_EQUAL(result, WERR_PRINTER_ALREADY_EXISTS)) {
5531 struct policy_handle printer_handle;
5533 if (existing_printer_deleted) {
5534 torture_fail(tctx, "already deleted printer still existing?");
5537 torture_assert(tctx, call_OpenPrinterEx(tctx, p, printername, NULL, &printer_handle),
5538 "failed to open printer handle");
5540 torture_assert(tctx, test_DeletePrinter(tctx, b, &printer_handle),
5541 "failed to delete printer");
5543 torture_assert(tctx, test_ClosePrinter(tctx, b, &printer_handle),
5544 "failed to close server handle");
5546 existing_printer_deleted = true;
5548 goto again;
5551 torture_assert_werr_equal(tctx, result, WERR_UNKNOWN_PORT,
5552 "unexpected result code");
5554 info2.portname = portname;
5556 torture_assert_ntstatus_ok(tctx, ex ? dcerpc_spoolss_AddPrinterEx_r(b, tctx, &rex) :
5557 dcerpc_spoolss_AddPrinter_r(b, tctx, &r),
5558 "failed to add printer");
5559 result = ex ? rex.out.result : r.out.result;
5560 torture_assert_werr_equal(tctx, result, WERR_UNKNOWN_PRINTER_DRIVER,
5561 "unexpected result code");
5563 info2.drivername = drivername;
5565 torture_assert_ntstatus_ok(tctx, ex ? dcerpc_spoolss_AddPrinterEx_r(b, tctx, &rex) :
5566 dcerpc_spoolss_AddPrinter_r(b, tctx, &r),
5567 "failed to add printer");
5568 result = ex ? rex.out.result : r.out.result;
5570 /* w2k8r2 allows to add printer w/o defining printprocessor */
5572 if (!W_ERROR_IS_OK(result)) {
5573 torture_assert_werr_equal(tctx, result, WERR_UNKNOWN_PRINTPROCESSOR,
5574 "unexpected result code");
5576 info2.printprocessor = "winprint";
5578 torture_assert_ntstatus_ok(tctx, ex ? dcerpc_spoolss_AddPrinterEx_r(b, tctx, &rex) :
5579 dcerpc_spoolss_AddPrinter_r(b, tctx, &r),
5580 "failed to add printer");
5581 result = ex ? rex.out.result : r.out.result;
5582 torture_assert_werr_ok(tctx, result,
5583 "failed to add printer");
5586 *handle_p = handle;
5588 /* we are paranoid, really check if the printer is there now */
5590 torture_assert(tctx, test_EnumPrinters_findname(tctx, b,
5591 PRINTER_ENUM_LOCAL, 1,
5592 printername,
5593 &found),
5594 "failed to enum printers");
5595 torture_assert(tctx, found, "failed to find newly added printer");
5597 torture_assert_ntstatus_ok(tctx, ex ? dcerpc_spoolss_AddPrinterEx_r(b, tctx, &rex) :
5598 dcerpc_spoolss_AddPrinter_r(b, tctx, &r),
5599 "failed to add printer");
5600 result = ex ? rex.out.result : r.out.result;
5601 torture_assert_werr_equal(tctx, result, WERR_PRINTER_ALREADY_EXISTS,
5602 "unexpected result code");
5604 return true;
5607 static bool test_AddPrinterEx(struct torture_context *tctx,
5608 struct dcerpc_pipe *p,
5609 struct policy_handle *handle_p,
5610 const char *printername,
5611 const char *drivername,
5612 const char *portname)
5614 bool ret = true;
5616 if (!torture_setting_bool(tctx, "samba3", false)) {
5617 if (!test_AddPrinter_wellknown(tctx, p, TORTURE_WELLKNOWN_PRINTER_EX, true)) {
5618 torture_comment(tctx, "failed to add printer to well known list\n");
5619 ret = false;
5623 if (!test_AddPrinter_normal(tctx, p, handle_p,
5624 printername, drivername, portname,
5625 true)) {
5626 torture_comment(tctx, "failed to add printer to printer list\n");
5627 ret = false;
5630 return ret;
5633 static bool test_AddPrinter(struct torture_context *tctx,
5634 struct dcerpc_pipe *p,
5635 struct policy_handle *handle_p,
5636 const char *printername,
5637 const char *drivername,
5638 const char *portname)
5640 bool ret = true;
5642 if (!torture_setting_bool(tctx, "samba3", false)) {
5643 if (!test_AddPrinter_wellknown(tctx, p, TORTURE_WELLKNOWN_PRINTER, false)) {
5644 torture_comment(tctx, "failed to add printer to well known list\n");
5645 ret = false;
5649 if (!test_AddPrinter_normal(tctx, p, handle_p,
5650 printername, drivername, portname,
5651 false)) {
5652 torture_comment(tctx, "failed to add printer to printer list\n");
5653 ret = false;
5656 return ret;
5659 static bool test_printer_info(struct torture_context *tctx,
5660 struct dcerpc_binding_handle *b,
5661 struct policy_handle *handle)
5663 bool ret = true;
5665 if (torture_setting_bool(tctx, "samba3", false)) {
5666 torture_skip(tctx, "skipping printer info cross tests against samba 3");
5669 if (!test_PrinterInfo(tctx, b, handle)) {
5670 ret = false;
5673 if (!test_SetPrinter_errors(tctx, b, handle)) {
5674 ret = false;
5677 return ret;
5680 static bool test_EnumPrinterKey(struct torture_context *tctx,
5681 struct dcerpc_binding_handle *b,
5682 struct policy_handle *handle,
5683 const char *key_name,
5684 const char ***array)
5686 struct spoolss_EnumPrinterKey r;
5687 uint32_t needed = 0;
5688 union spoolss_KeyNames key_buffer;
5689 int32_t offered[] = { 0, 1, 2, 3, 4, 5, -1, -2, -3, -4, -5, 256, 512, 1024, 2048 };
5690 uint32_t _ndr_size;
5691 int i;
5693 r.in.handle = handle;
5694 r.in.key_name = key_name;
5695 r.out.key_buffer = &key_buffer;
5696 r.out.needed = &needed;
5697 r.out._ndr_size = &_ndr_size;
5699 for (i=0; i < ARRAY_SIZE(offered); i++) {
5701 if (offered[i] < 0 && needed) {
5702 if (needed <= 4) {
5703 continue;
5705 r.in.offered = needed + offered[i];
5706 } else {
5707 r.in.offered = offered[i];
5710 ZERO_STRUCT(key_buffer);
5712 torture_comment(tctx, "Testing EnumPrinterKey(%s) with %d offered\n", r.in.key_name, r.in.offered);
5714 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_EnumPrinterKey_r(b, tctx, &r),
5715 "failed to call EnumPrinterKey");
5716 if (W_ERROR_EQUAL(r.out.result, WERR_MORE_DATA)) {
5718 torture_assert(tctx, (_ndr_size == r.in.offered/2),
5719 talloc_asprintf(tctx, "EnumPrinterKey size mismatch, _ndr_size %d (expected %d)",
5720 _ndr_size, r.in.offered/2));
5722 r.in.offered = needed;
5723 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_EnumPrinterKey_r(b, tctx, &r),
5724 "failed to call EnumPrinterKey");
5727 if (offered[i] > 0) {
5728 torture_assert_werr_ok(tctx, r.out.result,
5729 "failed to call EnumPrinterKey");
5732 torture_assert(tctx, (_ndr_size == r.in.offered/2),
5733 talloc_asprintf(tctx, "EnumPrinterKey size mismatch, _ndr_size %d (expected %d)",
5734 _ndr_size, r.in.offered/2));
5736 torture_assert(tctx, (*r.out.needed <= r.in.offered),
5737 talloc_asprintf(tctx, "EnumPrinterKey size mismatch: needed %d is not <= offered %d", *r.out.needed, r.in.offered));
5739 torture_assert(tctx, (*r.out.needed <= _ndr_size * 2),
5740 talloc_asprintf(tctx, "EnumPrinterKey size mismatch: needed %d is not <= _ndr_size %d * 2", *r.out.needed, _ndr_size));
5742 if (key_buffer.string_array) {
5743 uint32_t calc_needed = 0;
5744 int s;
5745 for (s=0; key_buffer.string_array[s]; s++) {
5746 calc_needed += strlen_m_term(key_buffer.string_array[s])*2;
5748 if (!key_buffer.string_array[0]) {
5749 calc_needed += 2;
5751 calc_needed += 2;
5753 torture_assert_int_equal(tctx, *r.out.needed, calc_needed,
5754 "EnumPrinterKey unexpected size");
5758 if (array) {
5759 *array = key_buffer.string_array;
5762 return true;
5765 bool test_printer_keys(struct torture_context *tctx,
5766 struct dcerpc_binding_handle *b,
5767 struct policy_handle *handle)
5769 const char **key_array = NULL;
5770 int i;
5772 torture_comment(tctx, "Testing Printer Keys\n");
5774 torture_assert(tctx, test_EnumPrinterKey(tctx, b, handle, "", &key_array),
5775 "failed to call test_EnumPrinterKey");
5777 for (i=0; key_array && key_array[i]; i++) {
5778 torture_assert(tctx, test_EnumPrinterKey(tctx, b, handle, key_array[i], NULL),
5779 "failed to call test_EnumPrinterKey");
5781 for (i=0; key_array && key_array[i]; i++) {
5782 torture_assert(tctx, test_EnumPrinterDataEx(tctx, b, handle, key_array[i], NULL, NULL),
5783 "failed to call test_EnumPrinterDataEx");
5786 torture_comment(tctx, "Printer Keys test succeeded\n\n");
5788 return true;
5791 static bool test_one_printer(struct torture_context *tctx,
5792 struct dcerpc_pipe *p,
5793 struct policy_handle *handle,
5794 const char *name)
5796 bool ret = true;
5797 struct dcerpc_binding_handle *b = p->binding_handle;
5799 if (!test_PausePrinter(tctx, b, handle)) {
5800 ret = false;
5803 if (!test_DoPrintTest(tctx, b, handle)) {
5804 ret = false;
5807 if (!test_ResumePrinter(tctx, b, handle)) {
5808 ret = false;
5811 if (!test_printer_info(tctx, b, handle)) {
5812 ret = false;
5815 if (!test_PrinterInfo_SD(tctx, b, handle)) {
5816 ret = false;
5819 if (!test_PrinterInfo_DevMode(tctx, p, handle, name)) {
5820 ret = false;
5823 if (!test_PrinterInfo_winreg(tctx, p, handle, name)) {
5824 ret = false;
5827 if (!test_ChangeID(tctx, p, handle)) {
5828 ret = false;
5831 if (!test_printer_keys(tctx, b, handle)) {
5832 ret = false;
5835 if (!test_EnumPrinterData_consistency(tctx, p, handle)) {
5836 ret = false;
5839 if (!test_SetPrinterDataEx_matrix(tctx, p, handle, name, NULL, NULL)) {
5840 ret = false;
5843 if (!test_PrinterData_winreg(tctx, p, handle, name)) {
5844 ret = false;
5847 if (!test_printer_rename(tctx, p, handle, name)) {
5848 ret = false;
5851 return ret;
5854 static bool test_printer(struct torture_context *tctx,
5855 struct dcerpc_pipe *p)
5857 bool ret = true;
5858 struct policy_handle handle[2];
5859 bool found = false;
5860 const char *drivername = "Microsoft XPS Document Writer";
5861 const char *portname = "LPT1:";
5862 struct dcerpc_binding_handle *b = p->binding_handle;
5864 /* test printer created via AddPrinter */
5866 if (!test_AddPrinter(tctx, p, &handle[0], TORTURE_PRINTER, drivername, portname)) {
5867 return false;
5870 if (!test_one_printer(tctx, p, &handle[0], TORTURE_PRINTER)) {
5871 ret = false;
5874 if (!test_DeletePrinter(tctx, b, &handle[0])) {
5875 ret = false;
5878 if (!test_EnumPrinters_findname(tctx, b, PRINTER_ENUM_LOCAL, 1,
5879 TORTURE_PRINTER, &found)) {
5880 ret = false;
5883 torture_assert(tctx, !found, "deleted printer still there");
5885 /* test printer created via AddPrinterEx */
5887 if (!test_AddPrinterEx(tctx, p, &handle[1], TORTURE_PRINTER_EX, drivername, portname)) {
5888 return false;
5891 if (!test_one_printer(tctx, p, &handle[1], TORTURE_PRINTER_EX)) {
5892 ret = false;
5895 if (!test_DeletePrinter(tctx, b, &handle[1])) {
5896 ret = false;
5899 if (!test_EnumPrinters_findname(tctx, b, PRINTER_ENUM_LOCAL, 1,
5900 TORTURE_PRINTER_EX, &found)) {
5901 ret = false;
5904 torture_assert(tctx, !found, "deleted printer still there");
5906 return ret;
5909 static bool test_architecture_buffer(struct torture_context *tctx,
5910 struct dcerpc_pipe *p)
5912 struct spoolss_OpenPrinterEx r;
5913 struct spoolss_UserLevel1 u1;
5914 struct policy_handle handle;
5915 uint32_t architectures[] = {
5916 PROCESSOR_ARCHITECTURE_INTEL,
5917 PROCESSOR_ARCHITECTURE_IA64,
5918 PROCESSOR_ARCHITECTURE_AMD64
5920 uint32_t needed[3];
5921 int i;
5922 struct dcerpc_binding_handle *b = p->binding_handle;
5924 for (i=0; i < ARRAY_SIZE(architectures); i++) {
5926 torture_comment(tctx, "Testing OpenPrinterEx with architecture %d\n", architectures[i]);
5928 u1.size = 0;
5929 u1.client = NULL;
5930 u1.user = NULL;
5931 u1.build = 0;
5932 u1.major = 3;
5933 u1.minor = 0;
5934 u1.processor = architectures[i];
5936 r.in.printername = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
5937 r.in.datatype = NULL;
5938 r.in.devmode_ctr.devmode= NULL;
5939 r.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
5940 r.in.level = 1;
5941 r.in.userlevel.level1 = &u1;
5942 r.out.handle = &handle;
5944 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_OpenPrinterEx_r(b, tctx, &r), "");
5945 torture_assert_werr_ok(tctx, r.out.result, "");
5948 struct spoolss_EnumPrinters e;
5949 uint32_t count;
5950 union spoolss_PrinterInfo *info;
5952 e.in.flags = PRINTER_ENUM_LOCAL;
5953 e.in.server = NULL;
5954 e.in.level = 2;
5955 e.in.buffer = NULL;
5956 e.in.offered = 0;
5957 e.out.count = &count;
5958 e.out.info = &info;
5959 e.out.needed = &needed[i];
5961 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_EnumPrinters_r(b, tctx, &e), "");
5962 #if 0
5963 torture_comment(tctx, "needed was %d\n", needed[i]);
5964 #endif
5967 torture_assert(tctx, test_ClosePrinter(tctx, b, &handle), "");
5970 for (i=1; i < ARRAY_SIZE(architectures); i++) {
5971 if (needed[i-1] != needed[i]) {
5972 torture_fail(tctx,
5973 talloc_asprintf(tctx, "needed size %d for architecture %d != needed size %d for architecture %d\n",
5974 needed[i-1], architectures[i-1], needed[i], architectures[i]));
5978 return true;
5981 bool torture_rpc_spoolss(struct torture_context *torture)
5983 NTSTATUS status;
5984 struct dcerpc_pipe *p;
5985 struct dcerpc_binding_handle *b;
5986 bool ret = true;
5987 struct test_spoolss_context *ctx;
5988 const char *environment = SPOOLSS_ARCHITECTURE_NT_X86;
5990 status = torture_rpc_connection(torture, &p, &ndr_table_spoolss);
5991 if (!NT_STATUS_IS_OK(status)) {
5992 return false;
5994 b = p->binding_handle;
5996 ctx = talloc_zero(torture, struct test_spoolss_context);
5998 ret &= test_OpenPrinter_server(torture, p, &ctx->server_handle);
5999 ret &= test_GetPrinterData_list(torture, p, &ctx->server_handle, &environment);
6000 ret &= test_EnumForms_all(torture, b, &ctx->server_handle, true);
6001 ret &= test_Forms(torture, b, &ctx->server_handle, true, NULL, NULL, NULL);
6002 ret &= test_Forms_winreg(torture, b, &ctx->server_handle, true, NULL);
6003 ret &= test_EnumPorts(torture, b, ctx);
6004 ret &= test_GetPrinterDriverDirectory(torture, p, environment);
6005 ret &= test_GetPrintProcessorDirectory(torture, p, environment);
6006 ret &= test_EnumPrinterDrivers(torture, p, ctx, environment);
6007 ret &= test_EnumPrinterDrivers(torture, p, ctx, SPOOLSS_ARCHITECTURE_ALL);
6008 ret &= test_EnumMonitors(torture, b, ctx);
6009 ret &= test_EnumPrintProcessors(torture, b, ctx, environment);
6010 ret &= test_EnumPrintProcDataTypes(torture, b);
6011 ret &= test_EnumPrinters(torture, b, ctx);
6012 ret &= test_OpenPrinter_badname_list(torture, b, dcerpc_server_name(p));
6014 ret &= test_AddPort(torture, p);
6015 ret &= test_EnumPorts_old(torture, p);
6016 ret &= test_EnumPrinters_old(torture, p, environment);
6017 ret &= test_EnumPrinterDrivers_old(torture, p, environment);
6018 ret &= test_architecture_buffer(torture, p);
6020 return ret;
6023 struct torture_suite *torture_rpc_spoolss_printer(TALLOC_CTX *mem_ctx)
6025 struct torture_suite *suite = torture_suite_create(mem_ctx, "SPOOLSS-PRINTER");
6027 struct torture_rpc_tcase *tcase = torture_suite_add_rpc_iface_tcase(suite,
6028 "printer", &ndr_table_spoolss);
6030 torture_rpc_tcase_add_test(tcase, "printer", test_printer);
6032 return suite;