s4-smbtorture: add spoolss EnumPrinterData vs EnumPrinterDataEx consistency test.
[Samba/nascimento.git] / source4 / torture / rpc / spoolss.c
blob65b964ad1698dcacb900cf90367635ccc1c5a7ae
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_PRINTER_KEY "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Print\\Printers"
43 struct test_spoolss_context {
44 /* print server handle */
45 struct policy_handle server_handle;
47 /* for EnumPorts */
48 uint32_t port_count[3];
49 union spoolss_PortInfo *ports[3];
51 /* for EnumPrinterDrivers */
52 uint32_t driver_count[8];
53 union spoolss_DriverInfo *drivers[8];
55 /* for EnumMonitors */
56 uint32_t monitor_count[3];
57 union spoolss_MonitorInfo *monitors[3];
59 /* for EnumPrintProcessors */
60 uint32_t print_processor_count[2];
61 union spoolss_PrintProcessorInfo *print_processors[2];
63 /* for EnumPrinters */
64 uint32_t printer_count[6];
65 union spoolss_PrinterInfo *printers[6];
68 #define COMPARE_STRING(tctx, c,r,e) \
69 torture_assert_str_equal(tctx, c.e, r.e, "invalid value")
71 /* not every compiler supports __typeof__() */
72 #if (__GNUC__ >= 3)
73 #define _CHECK_FIELD_SIZE(c,r,e,type) do {\
74 if (sizeof(__typeof__(c.e)) != sizeof(type)) { \
75 torture_fail(tctx, #c "." #e "field is not " #type "\n"); \
77 if (sizeof(__typeof__(r.e)) != sizeof(type)) { \
78 torture_fail(tctx, #r "." #e "field is not " #type "\n"); \
80 } while(0)
81 #else
82 #define _CHECK_FIELD_SIZE(c,r,e,type) do {} while(0)
83 #endif
85 #define COMPARE_UINT32(tctx, c, r, e) do {\
86 _CHECK_FIELD_SIZE(c, r, e, uint32_t); \
87 torture_assert_int_equal(tctx, c.e, r.e, "invalid value"); \
88 } while(0)
90 #define COMPARE_UINT64(tctx, c, r, e) do {\
91 _CHECK_FIELD_SIZE(c, r, e, uint64_t); \
92 torture_assert_int_equal(tctx, c.e, r.e, "invalid value"); \
93 } while(0)
96 #define COMPARE_NTTIME(tctx, c, r, e) do {\
97 _CHECK_FIELD_SIZE(c, r, e, NTTIME); \
98 torture_assert_int_equal(tctx, c.e, r.e, "invalid value"); \
99 } while(0)
101 #define COMPARE_STRING_ARRAY(tctx, c,r,e) do {\
102 int __i; \
103 if (!c.e && !r.e) { \
104 break; \
106 if (c.e && !r.e) { \
107 torture_fail(tctx, #r "." #e " field is NULL and " #c "." #e " is not\n"); \
109 if (!c.e && r.e) { \
110 torture_fail(tctx, #c "." #e " field is NULL and " #r "." #e " is not\n"); \
112 for (__i=0;c.e[__i] != NULL; __i++) { \
113 torture_assert_str_equal(tctx, c.e[__i], r.e[__i], "invalid value"); \
115 } while(0)
117 #define CHECK_ALIGN(size, n) do {\
118 if (size % n) {\
119 torture_warning(tctx, "%d is *NOT* %d byte aligned, should be %d",\
120 size, n, size + n - (size % n));\
122 } while(0)
124 #define DO_ROUND(size, n) (((size)+((n)-1)) & ~((n)-1))
126 #define CHECK_NEEDED_SIZE_ENUM_LEVEL(fn, info, level, count, ic, needed, align) do { \
127 if (torture_setting_bool(tctx, "spoolss_check_size", false)) {\
128 uint32_t size = ndr_size_##fn##_info(tctx, ic, level, count, info);\
129 uint32_t round_size = DO_ROUND(size, align);\
130 if (round_size != needed) {\
131 torture_warning(tctx, __location__": "#fn" level %d (count: %d) got unexpected needed size: %d, we calculated: %d", level, count, needed, round_size);\
132 CHECK_ALIGN(size, align);\
135 } while(0)
137 #define CHECK_NEEDED_SIZE_ENUM(fn, info, count, ic, needed, align) do { \
138 if (torture_setting_bool(tctx, "spoolss_check_size", false)) {\
139 uint32_t size = ndr_size_##fn##_info(tctx, ic, count, info);\
140 uint32_t round_size = DO_ROUND(size, align);\
141 if (round_size != needed) {\
142 torture_warning(tctx, __location__": "#fn" (count: %d) got unexpected needed size: %d, we calculated: %d", count, needed, round_size);\
143 CHECK_ALIGN(size, align);\
146 } while(0)
148 #define CHECK_NEEDED_SIZE_LEVEL(fn, info, level, ic, needed, align) do { \
149 if (torture_setting_bool(tctx, "spoolss_check_size", false)) {\
150 uint32_t size = ndr_size_##fn(info, level, ic, 0);\
151 uint32_t round_size = DO_ROUND(size, align);\
152 if (round_size != needed) {\
153 torture_warning(tctx, __location__": "#fn" level %d got unexpected needed size: %d, we calculated: %d", level, needed, round_size);\
154 CHECK_ALIGN(size, align);\
157 } while(0)
159 static bool test_OpenPrinter_server(struct torture_context *tctx,
160 struct dcerpc_pipe *p,
161 struct policy_handle *server_handle)
163 NTSTATUS status;
164 struct spoolss_OpenPrinter op;
166 op.in.printername = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
167 op.in.datatype = NULL;
168 op.in.devmode_ctr.devmode= NULL;
169 op.in.access_mask = 0;
170 op.out.handle = server_handle;
172 torture_comment(tctx, "Testing OpenPrinter(%s)\n", op.in.printername);
174 status = dcerpc_spoolss_OpenPrinter(p, tctx, &op);
175 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_OpenPrinter failed");
176 torture_assert_werr_ok(tctx, op.out.result, "dcerpc_spoolss_OpenPrinter failed");
178 return true;
181 static bool test_EnumPorts(struct torture_context *tctx,
182 struct dcerpc_pipe *p,
183 struct test_spoolss_context *ctx)
185 NTSTATUS status;
186 struct spoolss_EnumPorts r;
187 uint16_t levels[] = { 1, 2 };
188 int i, j;
190 for (i=0;i<ARRAY_SIZE(levels);i++) {
191 int level = levels[i];
192 DATA_BLOB blob;
193 uint32_t needed;
194 uint32_t count;
195 union spoolss_PortInfo *info;
197 r.in.servername = "";
198 r.in.level = level;
199 r.in.buffer = NULL;
200 r.in.offered = 0;
201 r.out.needed = &needed;
202 r.out.count = &count;
203 r.out.info = &info;
205 torture_comment(tctx, "Testing EnumPorts level %u\n", r.in.level);
207 status = dcerpc_spoolss_EnumPorts(p, ctx, &r);
208 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EnumPorts failed");
209 if (W_ERROR_IS_OK(r.out.result)) {
210 /* TODO: do some more checks here */
211 continue;
213 torture_assert_werr_equal(tctx, r.out.result, WERR_INSUFFICIENT_BUFFER,
214 "EnumPorts unexpected return code");
216 blob = data_blob_talloc(ctx, NULL, needed);
217 data_blob_clear(&blob);
218 r.in.buffer = &blob;
219 r.in.offered = needed;
221 status = dcerpc_spoolss_EnumPorts(p, ctx, &r);
222 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EnumPorts failed");
224 torture_assert_werr_ok(tctx, r.out.result, "EnumPorts failed");
226 torture_assert(tctx, info, "EnumPorts returned no info");
228 CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumPorts, info, r.in.level, count, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
230 ctx->port_count[level] = count;
231 ctx->ports[level] = info;
234 for (i=1;i<ARRAY_SIZE(levels);i++) {
235 int level = levels[i];
236 int old_level = levels[i-1];
237 torture_assert_int_equal(tctx, ctx->port_count[level], ctx->port_count[old_level],
238 "EnumPorts invalid value");
240 /* if the array sizes are not the same we would maybe segfault in the following code */
242 for (i=0;i<ARRAY_SIZE(levels);i++) {
243 int level = levels[i];
244 for (j=0;j<ctx->port_count[level];j++) {
245 union spoolss_PortInfo *cur = &ctx->ports[level][j];
246 union spoolss_PortInfo *ref = &ctx->ports[2][j];
247 switch (level) {
248 case 1:
249 COMPARE_STRING(tctx, cur->info1, ref->info2, port_name);
250 break;
251 case 2:
252 /* level 2 is our reference, and it makes no sense to compare it to itself */
253 break;
258 return true;
261 static bool test_GetPrintProcessorDirectory(struct torture_context *tctx,
262 struct dcerpc_pipe *p,
263 struct test_spoolss_context *ctx,
264 const char *environment)
266 NTSTATUS status;
267 struct spoolss_GetPrintProcessorDirectory r;
268 struct {
269 uint16_t level;
270 const char *server;
271 } levels[] = {{
272 .level = 1,
273 .server = NULL
275 .level = 1,
276 .server = ""
278 .level = 78,
279 .server = ""
281 .level = 1,
282 .server = talloc_asprintf(ctx, "\\\\%s", dcerpc_server_name(p))
284 .level = 1024,
285 .server = talloc_asprintf(ctx, "\\\\%s", dcerpc_server_name(p))
288 int i;
289 uint32_t needed;
291 for (i=0;i<ARRAY_SIZE(levels);i++) {
292 int level = levels[i].level;
293 DATA_BLOB blob;
295 r.in.server = levels[i].server;
296 r.in.environment = environment;
297 r.in.level = level;
298 r.in.buffer = NULL;
299 r.in.offered = 0;
300 r.out.needed = &needed;
302 torture_comment(tctx, "Testing GetPrintProcessorDirectory level %u\n", r.in.level);
304 status = dcerpc_spoolss_GetPrintProcessorDirectory(p, ctx, &r);
305 torture_assert_ntstatus_ok(tctx, status,
306 "dcerpc_spoolss_GetPrintProcessorDirectory failed");
307 torture_assert_werr_equal(tctx, r.out.result, WERR_INSUFFICIENT_BUFFER,
308 "GetPrintProcessorDirectory unexpected return code");
310 blob = data_blob_talloc(ctx, NULL, needed);
311 data_blob_clear(&blob);
312 r.in.buffer = &blob;
313 r.in.offered = needed;
315 status = dcerpc_spoolss_GetPrintProcessorDirectory(p, ctx, &r);
316 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_GetPrintProcessorDirectory failed");
318 torture_assert_werr_ok(tctx, r.out.result, "GetPrintProcessorDirectory failed");
320 CHECK_NEEDED_SIZE_LEVEL(spoolss_PrintProcessorDirectoryInfo, r.out.info, r.in.level, lp_iconv_convenience(tctx->lp_ctx), needed, 2);
323 return true;
327 static bool test_GetPrinterDriverDirectory(struct torture_context *tctx,
328 struct dcerpc_pipe *p,
329 struct test_spoolss_context *ctx,
330 const char *environment)
332 NTSTATUS status;
333 struct spoolss_GetPrinterDriverDirectory r;
334 struct {
335 uint16_t level;
336 const char *server;
337 } levels[] = {{
338 .level = 1,
339 .server = NULL
341 .level = 1,
342 .server = ""
344 .level = 78,
345 .server = ""
347 .level = 1,
348 .server = talloc_asprintf(ctx, "\\\\%s", dcerpc_server_name(p))
350 .level = 1024,
351 .server = talloc_asprintf(ctx, "\\\\%s", dcerpc_server_name(p))
354 int i;
355 uint32_t needed;
357 for (i=0;i<ARRAY_SIZE(levels);i++) {
358 int level = levels[i].level;
359 DATA_BLOB blob;
361 r.in.server = levels[i].server;
362 r.in.environment = environment;
363 r.in.level = level;
364 r.in.buffer = NULL;
365 r.in.offered = 0;
366 r.out.needed = &needed;
368 torture_comment(tctx, "Testing GetPrinterDriverDirectory level %u\n", r.in.level);
370 status = dcerpc_spoolss_GetPrinterDriverDirectory(p, ctx, &r);
371 torture_assert_ntstatus_ok(tctx, status,
372 "dcerpc_spoolss_GetPrinterDriverDirectory failed");
373 torture_assert_werr_equal(tctx, r.out.result, WERR_INSUFFICIENT_BUFFER,
374 "GetPrinterDriverDirectory unexpected return code");
376 blob = data_blob_talloc(ctx, NULL, needed);
377 data_blob_clear(&blob);
378 r.in.buffer = &blob;
379 r.in.offered = needed;
381 status = dcerpc_spoolss_GetPrinterDriverDirectory(p, ctx, &r);
382 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_GetPrinterDriverDirectory failed");
384 torture_assert_werr_ok(tctx, r.out.result, "GetPrinterDriverDirectory failed");
386 CHECK_NEEDED_SIZE_LEVEL(spoolss_DriverDirectoryInfo, r.out.info, r.in.level, lp_iconv_convenience(tctx->lp_ctx), needed, 2);
389 return true;
392 static bool test_EnumPrinterDrivers(struct torture_context *tctx,
393 struct dcerpc_pipe *p,
394 struct test_spoolss_context *ctx,
395 const char *architecture)
397 NTSTATUS status;
398 struct spoolss_EnumPrinterDrivers r;
399 uint16_t levels[] = { 1, 2, 3, 4, 5, 6, 8 };
400 int i, j;
402 for (i=0;i<ARRAY_SIZE(levels);i++) {
403 int level = levels[i];
404 DATA_BLOB blob;
405 uint32_t needed;
406 uint32_t count;
407 union spoolss_DriverInfo *info;
409 /* FIXME: gd, come back and fix "" as server, and handle
410 * priority of returned error codes in torture test and samba 3
411 * server */
413 r.in.server = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
414 r.in.environment = architecture;
415 r.in.level = level;
416 r.in.buffer = NULL;
417 r.in.offered = 0;
418 r.out.needed = &needed;
419 r.out.count = &count;
420 r.out.info = &info;
422 torture_comment(tctx, "Testing EnumPrinterDrivers level %u (%s)\n", r.in.level, r.in.environment);
424 status = dcerpc_spoolss_EnumPrinterDrivers(p, ctx, &r);
425 torture_assert_ntstatus_ok(tctx, status,
426 "dcerpc_spoolss_EnumPrinterDrivers failed");
427 if (W_ERROR_IS_OK(r.out.result)) {
428 /* TODO: do some more checks here */
429 continue;
431 if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
432 blob = data_blob_talloc(ctx, NULL, needed);
433 data_blob_clear(&blob);
434 r.in.buffer = &blob;
435 r.in.offered = needed;
437 status = dcerpc_spoolss_EnumPrinterDrivers(p, ctx, &r);
438 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EnumPrinterDrivers failed");
441 torture_assert_werr_ok(tctx, r.out.result, "EnumPrinterDrivers failed");
443 CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumPrinterDrivers, info, r.in.level, count, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
445 ctx->driver_count[level] = count;
446 ctx->drivers[level] = info;
449 for (i=1;i<ARRAY_SIZE(levels);i++) {
450 int level = levels[i];
451 int old_level = levels[i-1];
453 torture_assert_int_equal(tctx, ctx->driver_count[level], ctx->driver_count[old_level],
454 "EnumPrinterDrivers invalid value");
457 for (i=0;i<ARRAY_SIZE(levels);i++) {
458 int level = levels[i];
460 for (j=0;j<ctx->driver_count[level];j++) {
461 union spoolss_DriverInfo *cur = &ctx->drivers[level][j];
462 union spoolss_DriverInfo *ref = &ctx->drivers[8][j];
464 switch (level) {
465 case 1:
466 COMPARE_STRING(tctx, cur->info1, ref->info8, driver_name);
467 break;
468 case 2:
469 COMPARE_UINT32(tctx, cur->info2, ref->info8, version);
470 COMPARE_STRING(tctx, cur->info2, ref->info8, driver_name);
471 COMPARE_STRING(tctx, cur->info2, ref->info8, architecture);
472 COMPARE_STRING(tctx, cur->info2, ref->info8, driver_path);
473 COMPARE_STRING(tctx, cur->info2, ref->info8, data_file);
474 COMPARE_STRING(tctx, cur->info2, ref->info8, config_file);
475 break;
476 case 3:
477 COMPARE_UINT32(tctx, cur->info3, ref->info8, version);
478 COMPARE_STRING(tctx, cur->info3, ref->info8, driver_name);
479 COMPARE_STRING(tctx, cur->info3, ref->info8, architecture);
480 COMPARE_STRING(tctx, cur->info3, ref->info8, driver_path);
481 COMPARE_STRING(tctx, cur->info3, ref->info8, data_file);
482 COMPARE_STRING(tctx, cur->info3, ref->info8, config_file);
483 COMPARE_STRING(tctx, cur->info3, ref->info8, help_file);
484 COMPARE_STRING_ARRAY(tctx, cur->info3, ref->info8, dependent_files);
485 COMPARE_STRING(tctx, cur->info3, ref->info8, monitor_name);
486 COMPARE_STRING(tctx, cur->info3, ref->info8, default_datatype);
487 break;
488 case 4:
489 COMPARE_UINT32(tctx, cur->info4, ref->info8, version);
490 COMPARE_STRING(tctx, cur->info4, ref->info8, driver_name);
491 COMPARE_STRING(tctx, cur->info4, ref->info8, architecture);
492 COMPARE_STRING(tctx, cur->info4, ref->info8, driver_path);
493 COMPARE_STRING(tctx, cur->info4, ref->info8, data_file);
494 COMPARE_STRING(tctx, cur->info4, ref->info8, config_file);
495 COMPARE_STRING(tctx, cur->info4, ref->info8, help_file);
496 COMPARE_STRING_ARRAY(tctx, cur->info4, ref->info8, dependent_files);
497 COMPARE_STRING(tctx, cur->info4, ref->info8, monitor_name);
498 COMPARE_STRING(tctx, cur->info4, ref->info8, default_datatype);
499 COMPARE_STRING_ARRAY(tctx, cur->info4, ref->info8, previous_names);
500 break;
501 case 5:
502 COMPARE_UINT32(tctx, cur->info5, ref->info8, version);
503 COMPARE_STRING(tctx, cur->info5, ref->info8, driver_name);
504 COMPARE_STRING(tctx, cur->info5, ref->info8, architecture);
505 COMPARE_STRING(tctx, cur->info5, ref->info8, driver_path);
506 COMPARE_STRING(tctx, cur->info5, ref->info8, data_file);
507 COMPARE_STRING(tctx, cur->info5, ref->info8, config_file);
508 /*COMPARE_UINT32(tctx, cur->info5, ref->info8, driver_attributes);*/
509 /*COMPARE_UINT32(tctx, cur->info5, ref->info8, config_version);*/
510 /*TODO: ! COMPARE_UINT32(tctx, cur->info5, ref->info8, driver_version); */
511 break;
512 case 6:
513 COMPARE_UINT32(tctx, cur->info6, ref->info8, version);
514 COMPARE_STRING(tctx, cur->info6, ref->info8, driver_name);
515 COMPARE_STRING(tctx, cur->info6, ref->info8, architecture);
516 COMPARE_STRING(tctx, cur->info6, ref->info8, driver_path);
517 COMPARE_STRING(tctx, cur->info6, ref->info8, data_file);
518 COMPARE_STRING(tctx, cur->info6, ref->info8, config_file);
519 COMPARE_STRING(tctx, cur->info6, ref->info8, help_file);
520 COMPARE_STRING_ARRAY(tctx, cur->info6, ref->info8, dependent_files);
521 COMPARE_STRING(tctx, cur->info6, ref->info8, monitor_name);
522 COMPARE_STRING(tctx, cur->info6, ref->info8, default_datatype);
523 COMPARE_STRING_ARRAY(tctx, cur->info6, ref->info8, previous_names);
524 COMPARE_NTTIME(tctx, cur->info6, ref->info8, driver_date);
525 COMPARE_UINT64(tctx, cur->info6, ref->info8, driver_version);
526 COMPARE_STRING(tctx, cur->info6, ref->info8, manufacturer_name);
527 COMPARE_STRING(tctx, cur->info6, ref->info8, manufacturer_url);
528 COMPARE_STRING(tctx, cur->info6, ref->info8, hardware_id);
529 COMPARE_STRING(tctx, cur->info6, ref->info8, provider);
530 break;
531 case 8:
532 /* level 8 is our reference, and it makes no sense to compare it to itself */
533 break;
538 return true;
541 static bool test_EnumMonitors(struct torture_context *tctx,
542 struct dcerpc_pipe *p,
543 struct test_spoolss_context *ctx)
545 NTSTATUS status;
546 struct spoolss_EnumMonitors r;
547 uint16_t levels[] = { 1, 2 };
548 int i, j;
550 for (i=0;i<ARRAY_SIZE(levels);i++) {
551 int level = levels[i];
552 DATA_BLOB blob;
553 uint32_t needed;
554 uint32_t count;
555 union spoolss_MonitorInfo *info;
557 r.in.servername = "";
558 r.in.level = level;
559 r.in.buffer = NULL;
560 r.in.offered = 0;
561 r.out.needed = &needed;
562 r.out.count = &count;
563 r.out.info = &info;
565 torture_comment(tctx, "Testing EnumMonitors level %u\n", r.in.level);
567 status = dcerpc_spoolss_EnumMonitors(p, ctx, &r);
568 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EnumMonitors failed");
569 if (W_ERROR_IS_OK(r.out.result)) {
570 /* TODO: do some more checks here */
571 continue;
573 torture_assert_werr_equal(tctx, r.out.result, WERR_INSUFFICIENT_BUFFER,
574 "EnumMonitors failed");
576 blob = data_blob_talloc(ctx, NULL, needed);
577 data_blob_clear(&blob);
578 r.in.buffer = &blob;
579 r.in.offered = needed;
581 status = dcerpc_spoolss_EnumMonitors(p, ctx, &r);
582 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EnumMonitors failed");
584 torture_assert_werr_ok(tctx, r.out.result, "EnumMonitors failed");
586 CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumMonitors, info, r.in.level, count, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
588 ctx->monitor_count[level] = count;
589 ctx->monitors[level] = info;
592 for (i=1;i<ARRAY_SIZE(levels);i++) {
593 int level = levels[i];
594 int old_level = levels[i-1];
595 torture_assert_int_equal(tctx, ctx->monitor_count[level], ctx->monitor_count[old_level],
596 "EnumMonitors invalid value");
599 for (i=0;i<ARRAY_SIZE(levels);i++) {
600 int level = levels[i];
601 for (j=0;j<ctx->monitor_count[level];j++) {
602 union spoolss_MonitorInfo *cur = &ctx->monitors[level][j];
603 union spoolss_MonitorInfo *ref = &ctx->monitors[2][j];
604 switch (level) {
605 case 1:
606 COMPARE_STRING(tctx, cur->info1, ref->info2, monitor_name);
607 break;
608 case 2:
609 /* level 2 is our reference, and it makes no sense to compare it to itself */
610 break;
615 return true;
618 static bool test_EnumPrintProcessors(struct torture_context *tctx,
619 struct dcerpc_pipe *p,
620 struct test_spoolss_context *ctx,
621 const char *environment)
623 NTSTATUS status;
624 struct spoolss_EnumPrintProcessors r;
625 uint16_t levels[] = { 1 };
626 int i, j;
628 for (i=0;i<ARRAY_SIZE(levels);i++) {
629 int level = levels[i];
630 DATA_BLOB blob;
631 uint32_t needed;
632 uint32_t count;
633 union spoolss_PrintProcessorInfo *info;
635 r.in.servername = "";
636 r.in.environment = environment;
637 r.in.level = level;
638 r.in.buffer = NULL;
639 r.in.offered = 0;
640 r.out.needed = &needed;
641 r.out.count = &count;
642 r.out.info = &info;
644 torture_comment(tctx, "Testing EnumPrintProcessors level %u\n", r.in.level);
646 status = dcerpc_spoolss_EnumPrintProcessors(p, ctx, &r);
647 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EnumPrintProcessors failed");
648 if (W_ERROR_IS_OK(r.out.result)) {
649 /* TODO: do some more checks here */
650 continue;
652 torture_assert_werr_equal(tctx, r.out.result, WERR_INSUFFICIENT_BUFFER,
653 "EnumPrintProcessors unexpected return code");
655 blob = data_blob_talloc(ctx, NULL, needed);
656 data_blob_clear(&blob);
657 r.in.buffer = &blob;
658 r.in.offered = needed;
660 status = dcerpc_spoolss_EnumPrintProcessors(p, ctx, &r);
661 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EnumPrintProcessors failed");
663 torture_assert_werr_ok(tctx, r.out.result, "EnumPrintProcessors failed");
665 CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumPrintProcessors, info, r.in.level, count, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
667 ctx->print_processor_count[level] = count;
668 ctx->print_processors[level] = info;
671 for (i=1;i<ARRAY_SIZE(levels);i++) {
672 int level = levels[i];
673 int old_level = levels[i-1];
674 torture_assert_int_equal(tctx, ctx->print_processor_count[level], ctx->print_processor_count[old_level],
675 "EnumPrintProcessors failed");
678 for (i=0;i<ARRAY_SIZE(levels);i++) {
679 int level = levels[i];
680 for (j=0;j<ctx->print_processor_count[level];j++) {
681 #if 0
682 union spoolss_PrintProcessorInfo *cur = &ctx->print_processors[level][j];
683 union spoolss_PrintProcessorInfo *ref = &ctx->print_processors[1][j];
684 #endif
685 switch (level) {
686 case 1:
687 /* level 1 is our reference, and it makes no sense to compare it to itself */
688 break;
693 return true;
696 static bool test_EnumPrintProcDataTypes(struct torture_context *tctx,
697 struct dcerpc_pipe *p,
698 struct test_spoolss_context *ctx)
700 NTSTATUS status;
701 struct spoolss_EnumPrintProcDataTypes r;
702 uint16_t levels[] = { 1 };
703 int i;
705 for (i=0;i<ARRAY_SIZE(levels);i++) {
706 int level = levels[i];
707 DATA_BLOB blob;
708 uint32_t needed;
709 uint32_t count;
710 union spoolss_PrintProcDataTypesInfo *info;
712 r.in.servername = "";
713 r.in.print_processor_name = "winprint";
714 r.in.level = level;
715 r.in.buffer = NULL;
716 r.in.offered = 0;
717 r.out.needed = &needed;
718 r.out.count = &count;
719 r.out.info = &info;
721 torture_comment(tctx, "Testing EnumPrintProcDataTypes level %u\n", r.in.level);
723 status = dcerpc_spoolss_EnumPrintProcDataTypes(p, ctx, &r);
724 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EnumPrintProcDataType failed");
725 if (W_ERROR_IS_OK(r.out.result)) {
726 /* TODO: do some more checks here */
727 continue;
729 torture_assert_werr_equal(tctx, r.out.result, WERR_INSUFFICIENT_BUFFER,
730 "EnumPrintProcDataTypes unexpected return code");
732 blob = data_blob_talloc(ctx, NULL, needed);
733 data_blob_clear(&blob);
734 r.in.buffer = &blob;
735 r.in.offered = needed;
737 status = dcerpc_spoolss_EnumPrintProcDataTypes(p, ctx, &r);
738 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EnumPrintProcDataTypes failed");
740 torture_assert_werr_ok(tctx, r.out.result, "EnumPrintProcDataTypes failed");
742 CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumPrintProcDataTypes, info, r.in.level, count, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
746 return true;
750 static bool test_EnumPrinters(struct torture_context *tctx,
751 struct dcerpc_pipe *p,
752 struct test_spoolss_context *ctx)
754 struct spoolss_EnumPrinters r;
755 NTSTATUS status;
756 uint16_t levels[] = { 0, 1, 2, 4, 5 };
757 int i, j;
759 for (i=0;i<ARRAY_SIZE(levels);i++) {
760 int level = levels[i];
761 DATA_BLOB blob;
762 uint32_t needed;
763 uint32_t count;
764 union spoolss_PrinterInfo *info;
766 r.in.flags = PRINTER_ENUM_LOCAL;
767 r.in.server = "";
768 r.in.level = level;
769 r.in.buffer = NULL;
770 r.in.offered = 0;
771 r.out.needed = &needed;
772 r.out.count = &count;
773 r.out.info = &info;
775 torture_comment(tctx, "Testing EnumPrinters level %u\n", r.in.level);
777 status = dcerpc_spoolss_EnumPrinters(p, ctx, &r);
778 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EnumPrinters failed");
779 if (W_ERROR_IS_OK(r.out.result)) {
780 /* TODO: do some more checks here */
781 continue;
783 torture_assert_werr_equal(tctx, r.out.result, WERR_INSUFFICIENT_BUFFER,
784 "EnumPrinters unexpected return code");
786 blob = data_blob_talloc(ctx, NULL, needed);
787 data_blob_clear(&blob);
788 r.in.buffer = &blob;
789 r.in.offered = needed;
791 status = dcerpc_spoolss_EnumPrinters(p, ctx, &r);
792 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EnumPrinters failed");
794 torture_assert_werr_ok(tctx, r.out.result, "EnumPrinters failed");
796 CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumPrinters, info, r.in.level, count, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
798 ctx->printer_count[level] = count;
799 ctx->printers[level] = info;
802 for (i=1;i<ARRAY_SIZE(levels);i++) {
803 int level = levels[i];
804 int old_level = levels[i-1];
805 torture_assert_int_equal(tctx, ctx->printer_count[level], ctx->printer_count[old_level],
806 "EnumPrinters invalid value");
809 for (i=0;i<ARRAY_SIZE(levels);i++) {
810 int level = levels[i];
811 for (j=0;j<ctx->printer_count[level];j++) {
812 union spoolss_PrinterInfo *cur = &ctx->printers[level][j];
813 union spoolss_PrinterInfo *ref = &ctx->printers[2][j];
814 switch (level) {
815 case 0:
816 COMPARE_STRING(tctx, cur->info0, ref->info2, printername);
817 COMPARE_STRING(tctx, cur->info0, ref->info2, servername);
818 COMPARE_UINT32(tctx, cur->info0, ref->info2, cjobs);
819 /*COMPARE_UINT32(tctx, cur->info0, ref->info2, total_jobs);
820 COMPARE_UINT32(tctx, cur->info0, ref->info2, total_bytes);
821 COMPARE_SPOOLSS_TIME(cur->info0, ref->info2, spoolss_Time time);
822 COMPARE_UINT32(tctx, cur->info0, ref->info2, global_counter);
823 COMPARE_UINT32(tctx, cur->info0, ref->info2, total_pages);
824 COMPARE_UINT32(tctx, cur->info0, ref->info2, version);
825 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown10);
826 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown11);
827 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown12);
828 COMPARE_UINT32(tctx, cur->info0, ref->info2, session_counter);
829 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown14);
830 COMPARE_UINT32(tctx, cur->info0, ref->info2, printer_errors);
831 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown16);
832 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown17);
833 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown18);
834 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown19);
835 COMPARE_UINT32(tctx, cur->info0, ref->info2, change_id);
836 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown21);*/
837 COMPARE_UINT32(tctx, cur->info0, ref->info2, status);
838 /*COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown23);
839 COMPARE_UINT32(tctx, cur->info0, ref->info2, c_setprinter);
840 COMPARE_UINT16(cur->info0, ref->info2, unknown25);
841 COMPARE_UINT16(cur->info0, ref->info2, unknown26);
842 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown27);
843 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown28);
844 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown29);*/
845 break;
846 case 1:
847 /*COMPARE_UINT32(tctx, cur->info1, ref->info2, flags);*/
848 /*COMPARE_STRING(tctx, cur->info1, ref->info2, name);*/
849 /*COMPARE_STRING(tctx, cur->info1, ref->info2, description);*/
850 COMPARE_STRING(tctx, cur->info1, ref->info2, comment);
851 break;
852 case 2:
853 /* level 2 is our reference, and it makes no sense to compare it to itself */
854 break;
855 case 4:
856 COMPARE_STRING(tctx, cur->info4, ref->info2, printername);
857 COMPARE_STRING(tctx, cur->info4, ref->info2, servername);
858 COMPARE_UINT32(tctx, cur->info4, ref->info2, attributes);
859 break;
860 case 5:
861 COMPARE_STRING(tctx, cur->info5, ref->info2, printername);
862 COMPARE_STRING(tctx, cur->info5, ref->info2, portname);
863 COMPARE_UINT32(tctx, cur->info5, ref->info2, attributes);
864 /*COMPARE_UINT32(tctx, cur->info5, ref->info2, device_not_selected_timeout);
865 COMPARE_UINT32(tctx, cur->info5, ref->info2, transmission_retry_timeout);*/
866 break;
871 /* TODO:
872 * - verify that the port of a printer was in the list returned by EnumPorts
875 return true;
878 static bool test_GetPrinterDriver2(struct torture_context *tctx,
879 struct dcerpc_pipe *p,
880 struct policy_handle *handle,
881 const char *driver_name,
882 const char *environment);
884 bool test_GetPrinter_level(struct torture_context *tctx,
885 struct dcerpc_pipe *p,
886 struct policy_handle *handle,
887 uint32_t level,
888 union spoolss_PrinterInfo *info)
890 struct spoolss_GetPrinter r;
891 uint32_t needed;
893 r.in.handle = handle;
894 r.in.level = level;
895 r.in.buffer = NULL;
896 r.in.offered = 0;
897 r.out.needed = &needed;
899 torture_comment(tctx, "Testing GetPrinter level %u\n", r.in.level);
901 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_GetPrinter(p, tctx, &r),
902 "GetPrinter failed");
904 if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
905 DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed);
906 data_blob_clear(&blob);
907 r.in.buffer = &blob;
908 r.in.offered = needed;
910 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_GetPrinter(p, tctx, &r),
911 "GetPrinter failed");
914 torture_assert_werr_ok(tctx, r.out.result, "GetPrinter failed");
916 CHECK_NEEDED_SIZE_LEVEL(spoolss_PrinterInfo, r.out.info, r.in.level, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
918 if (info && r.out.info) {
919 *info = *r.out.info;
922 return true;
926 static bool test_GetPrinter(struct torture_context *tctx,
927 struct dcerpc_pipe *p,
928 struct policy_handle *handle,
929 const char *environment)
931 uint32_t levels[] = {0, 1, 2, 3, 4, 5, 6, 7, 8};
932 int i;
934 for (i=0;i<ARRAY_SIZE(levels);i++) {
936 union spoolss_PrinterInfo info;
938 ZERO_STRUCT(info);
940 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, levels[i], &info),
941 "failed to call GetPrinter");
943 if ((levels[i] == 2) && info.info2.drivername && strlen(info.info2.drivername)) {
944 torture_assert(tctx,
945 test_GetPrinterDriver2(tctx, p, handle, info.info2.drivername, environment),
946 "failed to call test_GetPrinterDriver2");
950 return true;
953 static bool test_SetPrinter(struct torture_context *tctx,
954 struct dcerpc_pipe *p,
955 struct policy_handle *handle,
956 struct spoolss_SetPrinterInfoCtr *info_ctr,
957 struct spoolss_DevmodeContainer *devmode_ctr,
958 struct sec_desc_buf *secdesc_ctr,
959 enum spoolss_PrinterControl command)
961 struct spoolss_SetPrinter r;
963 r.in.handle = handle;
964 r.in.info_ctr = info_ctr;
965 r.in.devmode_ctr = devmode_ctr;
966 r.in.secdesc_ctr = secdesc_ctr;
967 r.in.command = command;
969 torture_comment(tctx, "Testing SetPrinter level %d\n", r.in.info_ctr->level);
971 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_SetPrinter(p, tctx, &r),
972 "failed to call SetPrinter");
973 torture_assert_werr_ok(tctx, r.out.result,
974 "failed to call SetPrinter");
976 return true;
979 static bool test_SetPrinter_errors(struct torture_context *tctx,
980 struct dcerpc_pipe *p,
981 struct policy_handle *handle)
983 struct spoolss_SetPrinter r;
984 uint16_t levels[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
985 int i;
987 struct spoolss_SetPrinterInfoCtr info_ctr;
988 struct spoolss_DevmodeContainer devmode_ctr;
989 struct sec_desc_buf secdesc_ctr;
991 info_ctr.level = 0;
992 info_ctr.info.info0 = NULL;
994 ZERO_STRUCT(devmode_ctr);
995 ZERO_STRUCT(secdesc_ctr);
997 r.in.handle = handle;
998 r.in.info_ctr = &info_ctr;
999 r.in.devmode_ctr = &devmode_ctr;
1000 r.in.secdesc_ctr = &secdesc_ctr;
1001 r.in.command = 0;
1003 torture_comment(tctx, "Testing SetPrinter all zero\n");
1005 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_SetPrinter(p, tctx, &r),
1006 "failed to call SetPrinter");
1007 torture_assert_werr_equal(tctx, r.out.result, WERR_INVALID_PARAM,
1008 "failed to call SetPrinter");
1010 again:
1011 for (i=0; i < ARRAY_SIZE(levels); i++) {
1013 struct spoolss_SetPrinterInfo0 info0;
1014 struct spoolss_SetPrinterInfo1 info1;
1015 struct spoolss_SetPrinterInfo2 info2;
1016 struct spoolss_SetPrinterInfo3 info3;
1017 struct spoolss_SetPrinterInfo4 info4;
1018 struct spoolss_SetPrinterInfo5 info5;
1019 struct spoolss_SetPrinterInfo6 info6;
1020 struct spoolss_SetPrinterInfo7 info7;
1021 struct spoolss_SetPrinterInfo8 info8;
1022 struct spoolss_SetPrinterInfo9 info9;
1025 info_ctr.level = levels[i];
1026 switch (levels[i]) {
1027 case 0:
1028 ZERO_STRUCT(info0);
1029 info_ctr.info.info0 = &info0;
1030 break;
1031 case 1:
1032 ZERO_STRUCT(info1);
1033 info_ctr.info.info1 = &info1;
1034 break;
1035 case 2:
1036 ZERO_STRUCT(info2);
1037 info_ctr.info.info2 = &info2;
1038 break;
1039 case 3:
1040 ZERO_STRUCT(info3);
1041 info_ctr.info.info3 = &info3;
1042 break;
1043 case 4:
1044 ZERO_STRUCT(info4);
1045 info_ctr.info.info4 = &info4;
1046 break;
1047 case 5:
1048 ZERO_STRUCT(info5);
1049 info_ctr.info.info5 = &info5;
1050 break;
1051 case 6:
1052 ZERO_STRUCT(info6);
1053 info_ctr.info.info6 = &info6;
1054 break;
1055 case 7:
1056 ZERO_STRUCT(info7);
1057 info_ctr.info.info7 = &info7;
1058 break;
1059 case 8:
1060 ZERO_STRUCT(info8);
1061 info_ctr.info.info8 = &info8;
1062 break;
1063 case 9:
1064 ZERO_STRUCT(info9);
1065 info_ctr.info.info9 = &info9;
1066 break;
1069 torture_comment(tctx, "Testing SetPrinter level %d, command %d\n",
1070 info_ctr.level, r.in.command);
1072 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_SetPrinter(p, tctx, &r),
1073 "failed to call SetPrinter");
1075 switch (r.in.command) {
1076 case SPOOLSS_PRINTER_CONTROL_UNPAUSE: /* 0 */
1077 /* is ignored for all levels other then 0 */
1078 if (info_ctr.level > 0) {
1079 /* ignored then */
1080 break;
1082 case SPOOLSS_PRINTER_CONTROL_PAUSE: /* 1 */
1083 case SPOOLSS_PRINTER_CONTROL_RESUME: /* 2 */
1084 case SPOOLSS_PRINTER_CONTROL_PURGE: /* 3 */
1085 if (info_ctr.level > 0) {
1086 /* is invalid for all levels other then 0 */
1087 torture_assert_werr_equal(tctx, r.out.result, WERR_INVALID_PRINTER_COMMAND,
1088 "unexpected error code returned");
1089 continue;
1090 } else {
1091 torture_assert_werr_ok(tctx, r.out.result,
1092 "failed to call SetPrinter with non 0 command");
1093 continue;
1095 break;
1097 case SPOOLSS_PRINTER_CONTROL_SET_STATUS: /* 4 */
1098 /* FIXME: gd needs further investigation */
1099 default:
1100 torture_assert_werr_equal(tctx, r.out.result, WERR_INVALID_PRINTER_COMMAND,
1101 "unexpected error code returned");
1102 continue;
1105 switch (info_ctr.level) {
1106 case 1:
1107 torture_assert_werr_equal(tctx, r.out.result, WERR_UNKNOWN_LEVEL,
1108 "unexpected error code returned");
1109 break;
1110 case 2:
1111 torture_assert_werr_equal(tctx, r.out.result, WERR_UNKNOWN_PRINTER_DRIVER,
1112 "unexpected error code returned");
1113 break;
1114 case 3:
1115 case 4:
1116 case 5:
1117 case 7:
1118 torture_assert_werr_equal(tctx, r.out.result, WERR_INVALID_PARAM,
1119 "unexpected error code returned");
1120 break;
1121 case 9:
1122 torture_assert_werr_equal(tctx, r.out.result, WERR_NOT_SUPPORTED,
1123 "unexpected error code returned");
1124 break;
1125 default:
1126 torture_assert_werr_ok(tctx, r.out.result,
1127 "failed to call SetPrinter");
1128 break;
1132 if (r.in.command < 5) {
1133 r.in.command++;
1134 goto again;
1137 return true;
1140 static void clear_info2(struct spoolss_SetPrinterInfoCtr *r)
1142 if ((r->level == 2) && (r->info.info2)) {
1143 r->info.info2->secdesc_ptr = 0;
1144 r->info.info2->devmode_ptr = 0;
1148 static bool test_PrinterInfo(struct torture_context *tctx,
1149 struct dcerpc_pipe *p,
1150 struct policy_handle *handle)
1152 NTSTATUS status;
1153 struct spoolss_SetPrinter s;
1154 struct spoolss_GetPrinter q;
1155 struct spoolss_GetPrinter q0;
1156 struct spoolss_SetPrinterInfoCtr info_ctr;
1157 union spoolss_PrinterInfo info;
1158 struct spoolss_DevmodeContainer devmode_ctr;
1159 struct sec_desc_buf secdesc_ctr;
1160 uint32_t needed;
1161 bool ret = true;
1162 int i;
1164 uint32_t status_list[] = {
1165 /* these do not stick
1166 PRINTER_STATUS_PAUSED,
1167 PRINTER_STATUS_ERROR,
1168 PRINTER_STATUS_PENDING_DELETION, */
1169 PRINTER_STATUS_PAPER_JAM,
1170 PRINTER_STATUS_PAPER_OUT,
1171 PRINTER_STATUS_MANUAL_FEED,
1172 PRINTER_STATUS_PAPER_PROBLEM,
1173 PRINTER_STATUS_OFFLINE,
1174 PRINTER_STATUS_IO_ACTIVE,
1175 PRINTER_STATUS_BUSY,
1176 PRINTER_STATUS_PRINTING,
1177 PRINTER_STATUS_OUTPUT_BIN_FULL,
1178 PRINTER_STATUS_NOT_AVAILABLE,
1179 PRINTER_STATUS_WAITING,
1180 PRINTER_STATUS_PROCESSING,
1181 PRINTER_STATUS_INITIALIZING,
1182 PRINTER_STATUS_WARMING_UP,
1183 PRINTER_STATUS_TONER_LOW,
1184 PRINTER_STATUS_NO_TONER,
1185 PRINTER_STATUS_PAGE_PUNT,
1186 PRINTER_STATUS_USER_INTERVENTION,
1187 PRINTER_STATUS_OUT_OF_MEMORY,
1188 PRINTER_STATUS_DOOR_OPEN,
1189 PRINTER_STATUS_SERVER_UNKNOWN,
1190 PRINTER_STATUS_POWER_SAVE,
1191 /* these do not stick
1192 0x02000000,
1193 0x04000000,
1194 0x08000000,
1195 0x10000000,
1196 0x20000000,
1197 0x40000000,
1198 0x80000000 */
1200 uint32_t default_attribute = PRINTER_ATTRIBUTE_LOCAL;
1201 uint32_t attribute_list[] = {
1202 PRINTER_ATTRIBUTE_QUEUED,
1203 /* fails with WERR_INVALID_DATATYPE:
1204 PRINTER_ATTRIBUTE_DIRECT, */
1205 /* does not stick
1206 PRINTER_ATTRIBUTE_DEFAULT, */
1207 PRINTER_ATTRIBUTE_SHARED,
1208 /* does not stick
1209 PRINTER_ATTRIBUTE_NETWORK, */
1210 PRINTER_ATTRIBUTE_HIDDEN,
1211 PRINTER_ATTRIBUTE_LOCAL,
1212 PRINTER_ATTRIBUTE_ENABLE_DEVQ,
1213 PRINTER_ATTRIBUTE_KEEPPRINTEDJOBS,
1214 PRINTER_ATTRIBUTE_DO_COMPLETE_FIRST,
1215 PRINTER_ATTRIBUTE_WORK_OFFLINE,
1216 /* does not stick
1217 PRINTER_ATTRIBUTE_ENABLE_BIDI, */
1218 /* fails with WERR_INVALID_DATATYPE:
1219 PRINTER_ATTRIBUTE_RAW_ONLY, */
1220 /* these do not stick
1221 PRINTER_ATTRIBUTE_PUBLISHED,
1222 PRINTER_ATTRIBUTE_FAX,
1223 PRINTER_ATTRIBUTE_TS,
1224 0x00010000,
1225 0x00020000,
1226 0x00040000,
1227 0x00080000,
1228 0x00100000,
1229 0x00200000,
1230 0x00400000,
1231 0x00800000,
1232 0x01000000,
1233 0x02000000,
1234 0x04000000,
1235 0x08000000,
1236 0x10000000,
1237 0x20000000,
1238 0x40000000,
1239 0x80000000 */
1242 ZERO_STRUCT(devmode_ctr);
1243 ZERO_STRUCT(secdesc_ctr);
1245 s.in.handle = handle;
1246 s.in.command = 0;
1247 s.in.info_ctr = &info_ctr;
1248 s.in.devmode_ctr = &devmode_ctr;
1249 s.in.secdesc_ctr = &secdesc_ctr;
1251 q.in.handle = handle;
1252 q.out.info = &info;
1253 q0 = q;
1255 #define TESTGETCALL(call, r) \
1256 r.in.buffer = NULL; \
1257 r.in.offered = 0;\
1258 r.out.needed = &needed; \
1259 status = dcerpc_spoolss_ ##call(p, tctx, &r); \
1260 if (!NT_STATUS_IS_OK(status)) { \
1261 torture_comment(tctx, #call " level %u failed - %s (%s)\n", \
1262 r.in.level, nt_errstr(status), __location__); \
1263 ret = false; \
1264 break; \
1266 if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {\
1267 DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed); \
1268 data_blob_clear(&blob); \
1269 r.in.buffer = &blob; \
1270 r.in.offered = needed; \
1272 status = dcerpc_spoolss_ ##call(p, tctx, &r); \
1273 if (!NT_STATUS_IS_OK(status)) { \
1274 torture_comment(tctx, #call " level %u failed - %s (%s)\n", \
1275 r.in.level, nt_errstr(status), __location__); \
1276 ret = false; \
1277 break; \
1279 if (!W_ERROR_IS_OK(r.out.result)) { \
1280 torture_comment(tctx, #call " level %u failed - %s (%s)\n", \
1281 r.in.level, win_errstr(r.out.result), __location__); \
1282 ret = false; \
1283 break; \
1287 #define TESTSETCALL_EXP(call, r, err) \
1288 clear_info2(&info_ctr);\
1289 status = dcerpc_spoolss_ ##call(p, tctx, &r); \
1290 if (!NT_STATUS_IS_OK(status)) { \
1291 torture_comment(tctx, #call " level %u failed - %s (%s)\n", \
1292 r.in.info_ctr->level, nt_errstr(status), __location__); \
1293 ret = false; \
1294 break; \
1296 if (!W_ERROR_IS_OK(err)) { \
1297 if (!W_ERROR_EQUAL(err, r.out.result)) { \
1298 torture_comment(tctx, #call " level %u failed - %s, expected %s (%s)\n", \
1299 r.in.info_ctr->level, win_errstr(r.out.result), win_errstr(err), __location__); \
1300 ret = false; \
1302 break; \
1304 if (!W_ERROR_IS_OK(r.out.result)) { \
1305 torture_comment(tctx, #call " level %u failed - %s (%s)\n", \
1306 r.in.info_ctr->level, win_errstr(r.out.result), __location__); \
1307 ret = false; \
1308 break; \
1311 #define TESTSETCALL(call, r) \
1312 TESTSETCALL_EXP(call, r, WERR_OK)
1314 #define STRING_EQUAL(s1, s2, field) \
1315 if ((s1 && !s2) || (s2 && !s1) || strcmp(s1, s2)) { \
1316 torture_comment(tctx, "Failed to set %s to '%s' (%s)\n", \
1317 #field, s2, __location__); \
1318 ret = false; \
1319 break; \
1322 #define MEM_EQUAL(s1, s2, length, field) \
1323 if ((s1 && !s2) || (s2 && !s1) || memcmp(s1, s2, length)) { \
1324 torture_comment(tctx, "Failed to set %s to '%s' (%s)\n", \
1325 #field, (const char *)s2, __location__); \
1326 ret = false; \
1327 break; \
1330 #define INT_EQUAL(i1, i2, field) \
1331 if (i1 != i2) { \
1332 torture_comment(tctx, "Failed to set %s to 0x%llx - got 0x%llx (%s)\n", \
1333 #field, (unsigned long long)i2, (unsigned long long)i1, __location__); \
1334 ret = false; \
1335 break; \
1338 #define SD_EQUAL(sd1, sd2, field) \
1339 if (!security_descriptor_equal(sd1, sd2)) { \
1340 torture_comment(tctx, "Failed to set %s (%s)\n", \
1341 #field, __location__); \
1342 ret = false; \
1343 break; \
1346 #define TEST_PRINTERINFO_STRING_EXP_ERR(lvl1, field1, lvl2, field2, value, err) do { \
1347 torture_comment(tctx, "field test %d/%s vs %d/%s\n", lvl1, #field1, lvl2, #field2); \
1348 q.in.level = lvl1; \
1349 TESTGETCALL(GetPrinter, q) \
1350 info_ctr.level = lvl1; \
1351 info_ctr.info.info ## lvl1 = (struct spoolss_SetPrinterInfo ## lvl1 *)&q.out.info->info ## lvl1; \
1352 info_ctr.info.info ## lvl1->field1 = value;\
1353 TESTSETCALL_EXP(SetPrinter, s, err) \
1354 info_ctr.info.info ## lvl1->field1 = ""; \
1355 TESTGETCALL(GetPrinter, q) \
1356 info_ctr.info.info ## lvl1->field1 = value; \
1357 STRING_EQUAL(info_ctr.info.info ## lvl1->field1, value, field1); \
1358 q.in.level = lvl2; \
1359 TESTGETCALL(GetPrinter, q) \
1360 info_ctr.info.info ## lvl2 = (struct spoolss_SetPrinterInfo ## lvl2 *)&q.out.info->info ## lvl2; \
1361 STRING_EQUAL(info_ctr.info.info ## lvl2->field2, value, field2); \
1362 } while (0)
1364 #define TEST_PRINTERINFO_STRING(lvl1, field1, lvl2, field2, value) do { \
1365 TEST_PRINTERINFO_STRING_EXP_ERR(lvl1, field1, lvl2, field2, value, WERR_OK); \
1366 } while (0);
1368 #define TEST_PRINTERINFO_INT_EXP(lvl1, field1, lvl2, field2, value, exp_value) do { \
1369 torture_comment(tctx, "field test %d/%s vs %d/%s\n", lvl1, #field1, lvl2, #field2); \
1370 q.in.level = lvl1; \
1371 TESTGETCALL(GetPrinter, q) \
1372 info_ctr.level = lvl1; \
1373 info_ctr.info.info ## lvl1 = (struct spoolss_SetPrinterInfo ## lvl1 *)&q.out.info->info ## lvl1; \
1374 info_ctr.info.info ## lvl1->field1 = value; \
1375 TESTSETCALL(SetPrinter, s) \
1376 info_ctr.info.info ## lvl1->field1 = 0; \
1377 TESTGETCALL(GetPrinter, q) \
1378 info_ctr.info.info ## lvl1 = (struct spoolss_SetPrinterInfo ## lvl1 *)&q.out.info->info ## lvl1; \
1379 INT_EQUAL(info_ctr.info.info ## lvl1->field1, exp_value, field1); \
1380 q.in.level = lvl2; \
1381 TESTGETCALL(GetPrinter, q) \
1382 info_ctr.info.info ## lvl2 = (struct spoolss_SetPrinterInfo ## lvl2 *)&q.out.info->info ## lvl2; \
1383 INT_EQUAL(info_ctr.info.info ## lvl2->field2, exp_value, field1); \
1384 } while (0)
1386 #define TEST_PRINTERINFO_INT(lvl1, field1, lvl2, field2, value) do { \
1387 TEST_PRINTERINFO_INT_EXP(lvl1, field1, lvl2, field2, value, value); \
1388 } while (0)
1390 q0.in.level = 0;
1391 do { TESTGETCALL(GetPrinter, q0) } while (0);
1393 TEST_PRINTERINFO_STRING(2, comment, 1, comment, "xx2-1 comment");
1394 TEST_PRINTERINFO_STRING(2, comment, 2, comment, "xx2-2 comment");
1396 /* level 0 printername does not stick */
1397 /* TEST_PRINTERINFO_STRING(2, printername, 0, printername, "xx2-0 printer"); */
1398 TEST_PRINTERINFO_STRING(2, printername, 1, name, "xx2-1 printer");
1399 TEST_PRINTERINFO_STRING(2, printername, 2, printername, "xx2-2 printer");
1400 TEST_PRINTERINFO_STRING(2, printername, 4, printername, "xx2-4 printer");
1401 TEST_PRINTERINFO_STRING(2, printername, 5, printername, "xx2-5 printer");
1402 /* TEST_PRINTERINFO_STRING(4, printername, 0, printername, "xx4-0 printer"); */
1403 TEST_PRINTERINFO_STRING(4, printername, 1, name, "xx4-1 printer");
1404 TEST_PRINTERINFO_STRING(4, printername, 2, printername, "xx4-2 printer");
1405 TEST_PRINTERINFO_STRING(4, printername, 4, printername, "xx4-4 printer");
1406 TEST_PRINTERINFO_STRING(4, printername, 5, printername, "xx4-5 printer");
1407 /* TEST_PRINTERINFO_STRING(5, printername, 0, printername, "xx5-0 printer"); */
1408 TEST_PRINTERINFO_STRING(5, printername, 1, name, "xx5-1 printer");
1409 TEST_PRINTERINFO_STRING(5, printername, 2, printername, "xx5-2 printer");
1410 TEST_PRINTERINFO_STRING(5, printername, 4, printername, "xx5-4 printer");
1411 TEST_PRINTERINFO_STRING(5, printername, 5, printername, "xx5-5 printer");
1413 /* servername can be set but does not stick
1414 TEST_PRINTERINFO_STRING(2, servername, 0, servername, "xx2-0 servername");
1415 TEST_PRINTERINFO_STRING(2, servername, 2, servername, "xx2-2 servername");
1416 TEST_PRINTERINFO_STRING(2, servername, 4, servername, "xx2-4 servername");
1419 /* passing an invalid port will result in WERR_UNKNOWN_PORT */
1420 TEST_PRINTERINFO_STRING_EXP_ERR(2, portname, 2, portname, "xx2-2 portname", WERR_UNKNOWN_PORT);
1421 TEST_PRINTERINFO_STRING_EXP_ERR(2, portname, 5, portname, "xx2-5 portname", WERR_UNKNOWN_PORT);
1422 TEST_PRINTERINFO_STRING_EXP_ERR(5, portname, 2, portname, "xx5-2 portname", WERR_UNKNOWN_PORT);
1423 TEST_PRINTERINFO_STRING_EXP_ERR(5, portname, 5, portname, "xx5-5 portname", WERR_UNKNOWN_PORT);
1425 TEST_PRINTERINFO_STRING(2, sharename, 2, sharename, "xx2-2 sharename");
1426 /* passing an invalid driver will result in WERR_UNKNOWN_PRINTER_DRIVER */
1427 TEST_PRINTERINFO_STRING_EXP_ERR(2, drivername, 2, drivername, "xx2-2 drivername", WERR_UNKNOWN_PRINTER_DRIVER);
1428 TEST_PRINTERINFO_STRING(2, location, 2, location, "xx2-2 location");
1429 /* passing an invalid sepfile will result in WERR_INVALID_SEPARATOR_FILE */
1430 TEST_PRINTERINFO_STRING_EXP_ERR(2, sepfile, 2, sepfile, "xx2-2 sepfile", WERR_INVALID_SEPARATOR_FILE);
1431 /* passing an invalid printprocessor will result in WERR_UNKNOWN_PRINTPROCESSOR */
1432 TEST_PRINTERINFO_STRING_EXP_ERR(2, printprocessor, 2, printprocessor, "xx2-2 printprocessor", WERR_UNKNOWN_PRINTPROCESSOR);
1433 TEST_PRINTERINFO_STRING(2, datatype, 2, datatype, "xx2-2 datatype");
1434 TEST_PRINTERINFO_STRING(2, parameters, 2, parameters, "xx2-2 parameters");
1436 for (i=0; i < ARRAY_SIZE(attribute_list); i++) {
1437 /* TEST_PRINTERINFO_INT_EXP(2, attributes, 1, flags,
1438 attribute_list[i],
1439 (attribute_list[i] | default_attribute)
1440 ); */
1441 TEST_PRINTERINFO_INT_EXP(2, attributes, 2, attributes,
1442 attribute_list[i],
1443 (attribute_list[i] | default_attribute)
1445 TEST_PRINTERINFO_INT_EXP(2, attributes, 4, attributes,
1446 attribute_list[i],
1447 (attribute_list[i] | default_attribute)
1449 TEST_PRINTERINFO_INT_EXP(2, attributes, 5, attributes,
1450 attribute_list[i],
1451 (attribute_list[i] | default_attribute)
1453 /* TEST_PRINTERINFO_INT_EXP(4, attributes, 1, flags,
1454 attribute_list[i],
1455 (attribute_list[i] | default_attribute)
1456 ); */
1457 TEST_PRINTERINFO_INT_EXP(4, attributes, 2, attributes,
1458 attribute_list[i],
1459 (attribute_list[i] | default_attribute)
1461 TEST_PRINTERINFO_INT_EXP(4, attributes, 4, attributes,
1462 attribute_list[i],
1463 (attribute_list[i] | default_attribute)
1465 TEST_PRINTERINFO_INT_EXP(4, attributes, 5, attributes,
1466 attribute_list[i],
1467 (attribute_list[i] | default_attribute)
1469 /* TEST_PRINTERINFO_INT_EXP(5, attributes, 1, flags,
1470 attribute_list[i],
1471 (attribute_list[i] | default_attribute)
1472 ); */
1473 TEST_PRINTERINFO_INT_EXP(5, attributes, 2, attributes,
1474 attribute_list[i],
1475 (attribute_list[i] | default_attribute)
1477 TEST_PRINTERINFO_INT_EXP(5, attributes, 4, attributes,
1478 attribute_list[i],
1479 (attribute_list[i] | default_attribute)
1481 TEST_PRINTERINFO_INT_EXP(5, attributes, 5, attributes,
1482 attribute_list[i],
1483 (attribute_list[i] | default_attribute)
1487 for (i=0; i < ARRAY_SIZE(status_list); i++) {
1488 /* level 2 sets do not stick
1489 TEST_PRINTERINFO_INT(2, status, 0, status, status_list[i]);
1490 TEST_PRINTERINFO_INT(2, status, 2, status, status_list[i]);
1491 TEST_PRINTERINFO_INT(2, status, 6, status, status_list[i]); */
1492 TEST_PRINTERINFO_INT(6, status, 0, status, status_list[i]);
1493 TEST_PRINTERINFO_INT(6, status, 2, status, status_list[i]);
1494 TEST_PRINTERINFO_INT(6, status, 6, status, status_list[i]);
1497 /* priorities need to be between 0 and 99
1498 passing an invalid priority will result in WERR_INVALID_PRIORITY */
1499 TEST_PRINTERINFO_INT(2, priority, 2, priority, 0);
1500 TEST_PRINTERINFO_INT(2, priority, 2, priority, 1);
1501 TEST_PRINTERINFO_INT(2, priority, 2, priority, 99);
1502 /* TEST_PRINTERINFO_INT(2, priority, 2, priority, 100); */
1503 TEST_PRINTERINFO_INT(2, defaultpriority,2, defaultpriority, 0);
1504 TEST_PRINTERINFO_INT(2, defaultpriority,2, defaultpriority, 1);
1505 TEST_PRINTERINFO_INT(2, defaultpriority,2, defaultpriority, 99);
1506 /* TEST_PRINTERINFO_INT(2, defaultpriority,2, defaultpriority, 100); */
1508 TEST_PRINTERINFO_INT(2, starttime, 2, starttime, __LINE__);
1509 TEST_PRINTERINFO_INT(2, untiltime, 2, untiltime, __LINE__);
1511 /* does not stick
1512 TEST_PRINTERINFO_INT(2, cjobs, 2, cjobs, __LINE__);
1513 TEST_PRINTERINFO_INT(2, averageppm, 2, averageppm, __LINE__); */
1515 /* does not stick
1516 TEST_PRINTERINFO_INT(5, device_not_selected_timeout, 5, device_not_selected_timeout, __LINE__);
1517 TEST_PRINTERINFO_INT(5, transmission_retry_timeout, 5, transmission_retry_timeout, __LINE__); */
1519 /* FIXME: gd also test devmode and secdesc behavior */
1522 /* verify composition of level 1 description field */
1523 const char *description;
1524 const char *tmp;
1526 q0.in.level = 1;
1527 do { TESTGETCALL(GetPrinter, q0) } while (0);
1529 description = talloc_strdup(tctx, q0.out.info->info1.description);
1531 q0.in.level = 2;
1532 do { TESTGETCALL(GetPrinter, q0) } while (0);
1534 tmp = talloc_asprintf(tctx, "%s,%s,%s",
1535 q0.out.info->info2.printername,
1536 q0.out.info->info2.drivername,
1537 q0.out.info->info2.location);
1539 do { STRING_EQUAL(description, tmp, "description")} while (0);
1542 return ret;
1545 #define torture_assert_sid_equal(torture_ctx,got,expected,cmt)\
1546 do { struct dom_sid *__got = (got), *__expected = (expected); \
1547 if (!dom_sid_equal(__got, __expected)) { \
1548 torture_result(torture_ctx, TORTURE_FAIL, \
1549 __location__": "#got" was %s, expected %s: %s", \
1550 dom_sid_string(torture_ctx, __got), dom_sid_string(torture_ctx, __expected), cmt); \
1551 return false; \
1553 } while(0)
1555 static bool test_security_descriptor_equal(struct torture_context *tctx,
1556 const struct security_descriptor *sd1,
1557 const struct security_descriptor *sd2)
1559 if (sd1 == sd2) {
1560 return true;
1563 if (!sd1 || !sd2) {
1564 torture_comment(tctx, "%s\n", __location__);
1565 return false;
1568 torture_assert_int_equal(tctx, sd1->revision, sd2->revision, "revision mismatch");
1569 torture_assert_int_equal(tctx, sd1->type, sd2->type, "type mismatch");
1571 torture_assert_sid_equal(tctx, sd1->owner_sid, sd2->owner_sid, "owner mismatch");
1572 torture_assert_sid_equal(tctx, sd1->group_sid, sd2->group_sid, "group mismatch");
1574 if (!security_acl_equal(sd1->sacl, sd2->sacl)) {
1575 torture_comment(tctx, "%s: sacl mismatch\n", __location__);
1576 NDR_PRINT_DEBUG(security_acl, sd1->sacl);
1577 NDR_PRINT_DEBUG(security_acl, sd2->sacl);
1578 return false;
1580 if (!security_acl_equal(sd1->dacl, sd2->dacl)) {
1581 torture_comment(tctx, "%s: dacl mismatch\n", __location__);
1582 NDR_PRINT_DEBUG(security_acl, sd1->dacl);
1583 NDR_PRINT_DEBUG(security_acl, sd2->dacl);
1584 return false;
1587 return true;
1590 static bool test_sd_set_level(struct torture_context *tctx,
1591 struct dcerpc_pipe *p,
1592 struct policy_handle *handle,
1593 uint32_t level,
1594 struct security_descriptor *sd)
1596 struct spoolss_SetPrinterInfoCtr info_ctr;
1597 struct spoolss_DevmodeContainer devmode_ctr;
1598 struct sec_desc_buf secdesc_ctr;
1600 ZERO_STRUCT(devmode_ctr);
1601 ZERO_STRUCT(secdesc_ctr);
1603 switch (level) {
1604 case 2: {
1605 union spoolss_PrinterInfo info;
1606 struct spoolss_SetPrinterInfo2 info2;
1607 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 2, &info), "");
1609 info2.servername = info.info2.servername;
1610 info2.printername = info.info2.printername;
1611 info2.sharename = info.info2.sharename;
1612 info2.portname = info.info2.portname;
1613 info2.drivername = info.info2.drivername;
1614 info2.comment = info.info2.comment;
1615 info2.location = info.info2.location;
1616 info2.devmode_ptr = 0;
1617 info2.sepfile = info.info2.sepfile;
1618 info2.printprocessor = info.info2.printprocessor;
1619 info2.datatype = info.info2.datatype;
1620 info2.parameters = info.info2.parameters;
1621 info2.secdesc_ptr = 0;
1622 info2.attributes = info.info2.attributes;
1623 info2.priority = info.info2.priority;
1624 info2.defaultpriority = info.info2.defaultpriority;
1625 info2.starttime = info.info2.starttime;
1626 info2.untiltime = info.info2.untiltime;
1627 info2.status = info.info2.status;
1628 info2.cjobs = info.info2.cjobs;
1629 info2.averageppm = info.info2.averageppm;
1631 info_ctr.level = 2;
1632 info_ctr.info.info2 = &info2;
1634 break;
1636 case 3: {
1637 struct spoolss_SetPrinterInfo3 info3;
1639 info3.sec_desc_ptr = 0;
1641 info_ctr.level = 3;
1642 info_ctr.info.info3 = &info3;
1644 break;
1646 default:
1647 return false;
1650 secdesc_ctr.sd = sd;
1652 torture_assert(tctx,
1653 test_SetPrinter(tctx, p, handle, &info_ctr, &devmode_ctr, &secdesc_ctr, 0), "");
1655 return true;
1658 static bool test_PrinterInfo_SDs(struct torture_context *tctx,
1659 struct dcerpc_pipe *p,
1660 struct policy_handle *handle)
1662 union spoolss_PrinterInfo info;
1663 struct security_descriptor *sd1, *sd2;
1664 int i;
1666 /* just compare level 2 and level 3 */
1668 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 2, &info), "");
1670 sd1 = info.info2.secdesc;
1672 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 3, &info), "");
1674 sd2 = info.info3.secdesc;
1676 torture_assert(tctx, test_security_descriptor_equal(tctx, sd1, sd2),
1677 "SD level 2 != SD level 3");
1680 /* query level 2, set level 2, query level 2 */
1682 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 2, &info), "");
1684 sd1 = info.info2.secdesc;
1686 torture_assert(tctx, test_sd_set_level(tctx, p, handle, 2, sd1), "");
1688 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 2, &info), "");
1690 sd2 = info.info2.secdesc;
1691 if (sd1->type & SEC_DESC_DACL_DEFAULTED) {
1692 torture_comment(tctx, "removing SEC_DESC_DACL_DEFAULTED\n");
1693 sd1->type &= ~SEC_DESC_DACL_DEFAULTED;
1696 torture_assert(tctx, test_security_descriptor_equal(tctx, sd1, sd2),
1697 "SD level 2 != SD level 2 after SD has been set via level 2");
1700 /* query level 2, set level 3, query level 2 */
1702 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 2, &info), "");
1704 sd1 = info.info2.secdesc;
1706 torture_assert(tctx, test_sd_set_level(tctx, p, handle, 3, sd1), "");
1708 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 2, &info), "");
1710 sd2 = info.info2.secdesc;
1712 torture_assert(tctx, test_security_descriptor_equal(tctx, sd1, sd2),
1713 "SD level 2 != SD level 2 after SD has been set via level 3");
1715 /* set modified sd level 3, query level 2 */
1717 for (i=0; i < 93; i++) {
1718 struct security_ace a;
1719 const char *sid_string = talloc_asprintf(tctx, "S-1-5-32-9999%i", i);
1720 a.type = SEC_ACE_TYPE_ACCESS_ALLOWED;
1721 a.flags = 0;
1722 a.size = 0; /* autogenerated */
1723 a.access_mask = 0;
1724 a.trustee = *dom_sid_parse_talloc(tctx, sid_string);
1725 torture_assert_ntstatus_ok(tctx, security_descriptor_dacl_add(sd1, &a), "");
1728 torture_assert(tctx, test_sd_set_level(tctx, p, handle, 3, sd1), "");
1730 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 2, &info), "");
1731 sd2 = info.info2.secdesc;
1733 if (sd1->type & SEC_DESC_DACL_DEFAULTED) {
1734 torture_comment(tctx, "removing SEC_DESC_DACL_DEFAULTED\n");
1735 sd1->type &= ~SEC_DESC_DACL_DEFAULTED;
1738 torture_assert(tctx, test_security_descriptor_equal(tctx, sd1, sd2),
1739 "modified SD level 2 != SD level 2 after SD has been set via level 3");
1742 return true;
1746 * wrapper call that saves original sd, runs tests, and restores sd
1749 static bool test_PrinterInfo_SD(struct torture_context *tctx,
1750 struct dcerpc_pipe *p,
1751 struct policy_handle *handle)
1753 union spoolss_PrinterInfo info;
1754 struct security_descriptor *sd;
1755 bool ret = true;
1757 torture_comment(tctx, "\nTesting Printer Security Descriptors\n");
1759 /* save original sd */
1761 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 2, &info),
1762 "failed to get initial security descriptor");
1764 sd = security_descriptor_copy(tctx, info.info2.secdesc);
1766 /* run tests */
1768 ret = test_PrinterInfo_SDs(tctx, p, handle);
1770 /* restore original sd */
1772 torture_assert(tctx, test_sd_set_level(tctx, p, handle, 3, sd),
1773 "failed to restore initial security descriptor");
1775 torture_comment(tctx, "Printer Security Descriptors test %s\n",
1776 ret ? "succeeded" : "failed");
1779 return ret;
1782 static bool test_devmode_set_level(struct torture_context *tctx,
1783 struct dcerpc_pipe *p,
1784 struct policy_handle *handle,
1785 uint32_t level,
1786 struct spoolss_DeviceMode *devmode)
1788 struct spoolss_SetPrinterInfoCtr info_ctr;
1789 struct spoolss_DevmodeContainer devmode_ctr;
1790 struct sec_desc_buf secdesc_ctr;
1792 ZERO_STRUCT(devmode_ctr);
1793 ZERO_STRUCT(secdesc_ctr);
1795 switch (level) {
1796 case 2: {
1797 union spoolss_PrinterInfo info;
1798 struct spoolss_SetPrinterInfo2 info2;
1799 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 2, &info), "");
1801 info2.servername = info.info2.servername;
1802 info2.printername = info.info2.printername;
1803 info2.sharename = info.info2.sharename;
1804 info2.portname = info.info2.portname;
1805 info2.drivername = info.info2.drivername;
1806 info2.comment = info.info2.comment;
1807 info2.location = info.info2.location;
1808 info2.devmode_ptr = 0;
1809 info2.sepfile = info.info2.sepfile;
1810 info2.printprocessor = info.info2.printprocessor;
1811 info2.datatype = info.info2.datatype;
1812 info2.parameters = info.info2.parameters;
1813 info2.secdesc_ptr = 0;
1814 info2.attributes = info.info2.attributes;
1815 info2.priority = info.info2.priority;
1816 info2.defaultpriority = info.info2.defaultpriority;
1817 info2.starttime = info.info2.starttime;
1818 info2.untiltime = info.info2.untiltime;
1819 info2.status = info.info2.status;
1820 info2.cjobs = info.info2.cjobs;
1821 info2.averageppm = info.info2.averageppm;
1823 info_ctr.level = 2;
1824 info_ctr.info.info2 = &info2;
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, p, 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_pipe *p,
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 *)&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_pipe *p,
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;
2019 /* simply compare level8 and level2 devmode */
2021 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 8, &info), "");
2023 devmode = info.info8.devmode;
2025 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 2, &info), "");
2027 devmode2 = info.info2.devmode;
2029 torture_assert(tctx, test_devicemode_equal(tctx, devmode, devmode2),
2030 "DM level 8 != DM level 2");
2033 /* set devicemode level 8 and see if it persists */
2035 devmode->copies = 93;
2036 devmode->formname = talloc_strdup(tctx, "Legal");
2038 torture_assert(tctx, test_devmode_set_level(tctx, p, handle, 8, devmode), "");
2040 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 8, &info), "");
2042 devmode2 = info.info8.devmode;
2044 torture_assert(tctx, test_devicemode_equal(tctx, devmode, devmode2),
2045 "modified DM level 8 != DM level 8 after DM has been set via level 8");
2047 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 2, &info), "");
2049 devmode2 = info.info2.devmode;
2051 torture_assert(tctx, test_devicemode_equal(tctx, devmode, devmode2),
2052 "modified DM level 8 != DM level 2");
2055 /* set devicemode level 2 and see if it persists */
2057 devmode->copies = 39;
2058 devmode->formname = talloc_strdup(tctx, "Executive");
2060 torture_assert(tctx, test_devmode_set_level(tctx, p, handle, 2, devmode), "");
2062 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 8, &info), "");
2064 devmode2 = info.info8.devmode;
2066 torture_assert(tctx, test_devicemode_equal(tctx, devmode, devmode2),
2067 "modified DM level 8 != DM level 8 after DM has been set via level 2");
2069 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 2, &info), "");
2071 devmode2 = info.info2.devmode;
2073 torture_assert(tctx, test_devicemode_equal(tctx, devmode, devmode2),
2074 "modified DM level 8 != DM level 2");
2077 /* check every single bit in public part of devicemode */
2079 torture_assert(tctx, test_devicemode_full(tctx, p, handle),
2080 "failed to set every single devicemode component");
2083 /* change formname upon open and see if it persists in getprinter calls */
2085 devmode->formname = talloc_strdup(tctx, "A4");
2086 devmode->copies = 42;
2088 torture_assert(tctx, call_OpenPrinterEx(tctx, p, name, devmode, &handle_devmode),
2089 "failed to open printer handle");
2091 torture_assert(tctx, test_GetPrinter_level(tctx, p, &handle_devmode, 8, &info), "");
2093 devmode2 = info.info8.devmode;
2095 if (strequal(devmode->devicename, devmode2->devicename)) {
2096 torture_comment(tctx, "devicenames are the same\n");
2097 } else {
2098 torture_comment(tctx, "devicename passed in for open: %s\n", devmode->devicename);
2099 torture_comment(tctx, "devicename after level 8 get: %s\n", devmode2->devicename);
2102 if (strequal(devmode->formname, devmode2->formname)) {
2103 torture_warning(tctx, "formname are the same\n");
2104 } else {
2105 torture_comment(tctx, "formname passed in for open: %s\n", devmode->formname);
2106 torture_comment(tctx, "formname after level 8 get: %s\n", devmode2->formname);
2109 if (devmode->copies == devmode2->copies) {
2110 torture_warning(tctx, "copies are the same\n");
2111 } else {
2112 torture_comment(tctx, "copies passed in for open: %d\n", devmode->copies);
2113 torture_comment(tctx, "copies after level 8 get: %d\n", devmode2->copies);
2116 torture_assert(tctx, test_GetPrinter_level(tctx, p, &handle_devmode, 2, &info), "");
2118 devmode2 = info.info2.devmode;
2120 if (strequal(devmode->devicename, devmode2->devicename)) {
2121 torture_comment(tctx, "devicenames are the same\n");
2122 } else {
2123 torture_comment(tctx, "devicename passed in for open: %s\n", devmode->devicename);
2124 torture_comment(tctx, "devicename after level 2 get: %s\n", devmode2->devicename);
2127 if (strequal(devmode->formname, devmode2->formname)) {
2128 torture_warning(tctx, "formname is the same\n");
2129 } else {
2130 torture_comment(tctx, "formname passed in for open: %s\n", devmode->formname);
2131 torture_comment(tctx, "formname after level 2 get: %s\n", devmode2->formname);
2134 if (devmode->copies == devmode2->copies) {
2135 torture_warning(tctx, "copies are the same\n");
2136 } else {
2137 torture_comment(tctx, "copies passed in for open: %d\n", devmode->copies);
2138 torture_comment(tctx, "copies after level 2 get: %d\n", devmode2->copies);
2141 test_ClosePrinter(tctx, p, &handle_devmode);
2143 return true;
2147 * wrapper call that saves original devmode, runs tests, and restores devmode
2150 static bool test_PrinterInfo_DevMode(struct torture_context *tctx,
2151 struct dcerpc_pipe *p,
2152 struct policy_handle *handle,
2153 const char *name)
2155 union spoolss_PrinterInfo info;
2156 struct spoolss_DeviceMode *devmode;
2157 bool ret = true;
2159 torture_comment(tctx, "\nTesting Printer Devicemodes\n");
2161 /* save original devmode */
2163 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 8, &info),
2164 "failed to get initial global devicemode");
2166 devmode = info.info8.devmode;
2168 /* run tests */
2170 ret = test_PrinterInfo_DevModes(tctx, p, handle, name);
2172 /* restore original devmode */
2174 torture_assert(tctx, test_devmode_set_level(tctx, p, handle, 8, devmode),
2175 "failed to restore initial global device mode");
2177 torture_comment(tctx, "Printer Devicemodes test %s\n",
2178 ret ? "succeeded" : "failed");
2181 return ret;
2184 static bool test_ClosePrinter(struct torture_context *tctx,
2185 struct dcerpc_pipe *p,
2186 struct policy_handle *handle)
2188 NTSTATUS status;
2189 struct spoolss_ClosePrinter r;
2191 r.in.handle = handle;
2192 r.out.handle = handle;
2194 torture_comment(tctx, "Testing ClosePrinter\n");
2196 status = dcerpc_spoolss_ClosePrinter(p, tctx, &r);
2197 torture_assert_ntstatus_ok(tctx, status, "ClosePrinter failed");
2198 torture_assert_werr_ok(tctx, r.out.result, "ClosePrinter failed");
2200 return true;
2203 static bool test_GetForm(struct torture_context *tctx,
2204 struct dcerpc_pipe *p,
2205 struct policy_handle *handle,
2206 const char *form_name,
2207 uint32_t level)
2209 NTSTATUS status;
2210 struct spoolss_GetForm r;
2211 uint32_t needed;
2213 r.in.handle = handle;
2214 r.in.form_name = form_name;
2215 r.in.level = level;
2216 r.in.buffer = NULL;
2217 r.in.offered = 0;
2218 r.out.needed = &needed;
2220 torture_comment(tctx, "Testing GetForm level %d\n", r.in.level);
2222 status = dcerpc_spoolss_GetForm(p, tctx, &r);
2223 torture_assert_ntstatus_ok(tctx, status, "GetForm failed");
2225 if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
2226 DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed);
2227 data_blob_clear(&blob);
2228 r.in.buffer = &blob;
2229 r.in.offered = needed;
2230 status = dcerpc_spoolss_GetForm(p, tctx, &r);
2231 torture_assert_ntstatus_ok(tctx, status, "GetForm failed");
2233 torture_assert_werr_ok(tctx, r.out.result, "GetForm failed");
2235 torture_assert(tctx, r.out.info, "No form info returned");
2238 torture_assert_werr_ok(tctx, r.out.result, "GetForm failed");
2240 CHECK_NEEDED_SIZE_LEVEL(spoolss_FormInfo, r.out.info, r.in.level, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
2242 return true;
2245 static bool test_EnumForms(struct torture_context *tctx,
2246 struct dcerpc_pipe *p,
2247 struct policy_handle *handle, bool print_server)
2249 NTSTATUS status;
2250 struct spoolss_EnumForms r;
2251 bool ret = true;
2252 uint32_t needed;
2253 uint32_t count;
2254 uint32_t levels[] = { 1, 2 };
2255 int i;
2257 for (i=0; i<ARRAY_SIZE(levels); i++) {
2259 union spoolss_FormInfo *info;
2261 r.in.handle = handle;
2262 r.in.level = levels[i];
2263 r.in.buffer = NULL;
2264 r.in.offered = 0;
2265 r.out.needed = &needed;
2266 r.out.count = &count;
2267 r.out.info = &info;
2269 torture_comment(tctx, "Testing EnumForms level %d\n", levels[i]);
2271 status = dcerpc_spoolss_EnumForms(p, tctx, &r);
2272 torture_assert_ntstatus_ok(tctx, status, "EnumForms failed");
2274 if ((r.in.level == 2) && (W_ERROR_EQUAL(r.out.result, WERR_UNKNOWN_LEVEL))) {
2275 break;
2278 if (print_server && W_ERROR_EQUAL(r.out.result, WERR_BADFID))
2279 torture_fail(tctx, "EnumForms on the PrintServer isn't supported by test server (NT4)");
2281 if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
2282 int j;
2283 DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed);
2284 data_blob_clear(&blob);
2285 r.in.buffer = &blob;
2286 r.in.offered = needed;
2288 status = dcerpc_spoolss_EnumForms(p, tctx, &r);
2290 torture_assert(tctx, info, "No forms returned");
2292 for (j = 0; j < count; j++) {
2293 if (!print_server)
2294 ret &= test_GetForm(tctx, p, handle, info[j].info1.form_name, levels[i]);
2298 torture_assert_ntstatus_ok(tctx, status, "EnumForms failed");
2300 torture_assert_werr_ok(tctx, r.out.result, "EnumForms failed");
2302 CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumForms, info, r.in.level, count, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
2305 return true;
2308 static bool test_DeleteForm(struct torture_context *tctx,
2309 struct dcerpc_pipe *p,
2310 struct policy_handle *handle,
2311 const char *form_name)
2313 NTSTATUS status;
2314 struct spoolss_DeleteForm r;
2316 r.in.handle = handle;
2317 r.in.form_name = form_name;
2319 status = dcerpc_spoolss_DeleteForm(p, tctx, &r);
2321 torture_assert_ntstatus_ok(tctx, status, "DeleteForm failed");
2323 torture_assert_werr_ok(tctx, r.out.result, "DeleteForm failed");
2325 return true;
2328 static bool test_AddForm(struct torture_context *tctx,
2329 struct dcerpc_pipe *p,
2330 struct policy_handle *handle, bool print_server)
2332 struct spoolss_AddForm r;
2333 struct spoolss_AddFormInfo1 addform;
2334 const char *form_name = "testform3";
2335 NTSTATUS status;
2336 bool ret = true;
2338 r.in.handle = handle;
2339 r.in.level = 1;
2340 r.in.info.info1 = &addform;
2341 addform.flags = SPOOLSS_FORM_USER;
2342 addform.form_name = form_name;
2343 addform.size.width = 50;
2344 addform.size.height = 25;
2345 addform.area.left = 5;
2346 addform.area.top = 10;
2347 addform.area.right = 45;
2348 addform.area.bottom = 15;
2350 status = dcerpc_spoolss_AddForm(p, tctx, &r);
2352 torture_assert_ntstatus_ok(tctx, status, "AddForm failed");
2354 torture_assert_werr_ok(tctx, r.out.result, "AddForm failed");
2356 if (!print_server) ret &= test_GetForm(tctx, p, handle, form_name, 1);
2359 struct spoolss_SetForm sf;
2360 struct spoolss_AddFormInfo1 setform;
2362 sf.in.handle = handle;
2363 sf.in.form_name = form_name;
2364 sf.in.level = 1;
2365 sf.in.info.info1= &setform;
2366 setform.flags = addform.flags;
2367 setform.form_name = addform.form_name;
2368 setform.size = addform.size;
2369 setform.area = addform.area;
2371 setform.size.width = 1234;
2373 status = dcerpc_spoolss_SetForm(p, tctx, &sf);
2375 torture_assert_ntstatus_ok(tctx, status, "SetForm failed");
2377 torture_assert_werr_ok(tctx, r.out.result, "SetForm failed");
2380 if (!print_server) ret &= test_GetForm(tctx, p, handle, form_name, 1);
2383 struct spoolss_EnumForms e;
2384 union spoolss_FormInfo *info;
2385 uint32_t needed;
2386 uint32_t count;
2387 bool found = false;
2389 e.in.handle = handle;
2390 e.in.level = 1;
2391 e.in.buffer = NULL;
2392 e.in.offered = 0;
2393 e.out.needed = &needed;
2394 e.out.count = &count;
2395 e.out.info = &info;
2397 torture_comment(tctx, "Testing EnumForms level 1\n");
2399 status = dcerpc_spoolss_EnumForms(p, tctx, &e);
2400 torture_assert_ntstatus_ok(tctx, status, "EnumForms failed");
2402 if (print_server && W_ERROR_EQUAL(e.out.result, WERR_BADFID))
2403 torture_fail(tctx, "EnumForms on the PrintServer isn't supported by test server (NT4)");
2405 if (W_ERROR_EQUAL(e.out.result, WERR_INSUFFICIENT_BUFFER)) {
2406 int j;
2407 DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed);
2408 data_blob_clear(&blob);
2409 e.in.buffer = &blob;
2410 e.in.offered = needed;
2412 status = dcerpc_spoolss_EnumForms(p, tctx, &e);
2414 torture_assert(tctx, info, "No forms returned");
2416 for (j = 0; j < count; j++) {
2417 if (strequal(form_name, info[j].info1.form_name)) {
2418 found = true;
2419 break;
2423 torture_assert(tctx, found, "Newly added form not found in enum call");
2426 if (!test_DeleteForm(tctx, p, handle, form_name)) {
2427 ret = false;
2430 return ret;
2433 static bool test_EnumPorts_old(struct torture_context *tctx,
2434 struct dcerpc_pipe *p)
2436 NTSTATUS status;
2437 struct spoolss_EnumPorts r;
2438 uint32_t needed;
2439 uint32_t count;
2440 union spoolss_PortInfo *info;
2442 r.in.servername = talloc_asprintf(tctx, "\\\\%s",
2443 dcerpc_server_name(p));
2444 r.in.level = 2;
2445 r.in.buffer = NULL;
2446 r.in.offered = 0;
2447 r.out.needed = &needed;
2448 r.out.count = &count;
2449 r.out.info = &info;
2451 torture_comment(tctx, "Testing EnumPorts\n");
2453 status = dcerpc_spoolss_EnumPorts(p, tctx, &r);
2455 torture_assert_ntstatus_ok(tctx, status, "EnumPorts failed");
2457 if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
2458 DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed);
2459 data_blob_clear(&blob);
2460 r.in.buffer = &blob;
2461 r.in.offered = needed;
2463 status = dcerpc_spoolss_EnumPorts(p, tctx, &r);
2464 torture_assert_ntstatus_ok(tctx, status, "EnumPorts failed");
2465 torture_assert_werr_ok(tctx, r.out.result, "EnumPorts failed");
2467 torture_assert(tctx, info, "No ports returned");
2470 torture_assert_werr_ok(tctx, r.out.result, "EnumPorts failed");
2472 CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumPorts, info, 2, count, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
2474 return true;
2477 static bool test_AddPort(struct torture_context *tctx,
2478 struct dcerpc_pipe *p)
2480 NTSTATUS status;
2481 struct spoolss_AddPort r;
2483 r.in.server_name = talloc_asprintf(tctx, "\\\\%s",
2484 dcerpc_server_name(p));
2485 r.in.unknown = 0;
2486 r.in.monitor_name = "foo";
2488 torture_comment(tctx, "Testing AddPort\n");
2490 status = dcerpc_spoolss_AddPort(p, tctx, &r);
2492 torture_assert_ntstatus_ok(tctx, status, "AddPort failed");
2494 /* win2k3 returns WERR_NOT_SUPPORTED */
2496 #if 0
2498 if (!W_ERROR_IS_OK(r.out.result)) {
2499 printf("AddPort failed - %s\n", win_errstr(r.out.result));
2500 return false;
2503 #endif
2505 return true;
2508 static bool test_GetJob(struct torture_context *tctx,
2509 struct dcerpc_pipe *p,
2510 struct policy_handle *handle, uint32_t job_id)
2512 NTSTATUS status;
2513 struct spoolss_GetJob r;
2514 union spoolss_JobInfo info;
2515 uint32_t needed;
2516 uint32_t levels[] = {1, 2 /* 3, 4 */};
2517 uint32_t i;
2519 r.in.handle = handle;
2520 r.in.job_id = job_id;
2521 r.in.level = 0;
2522 r.in.buffer = NULL;
2523 r.in.offered = 0;
2524 r.out.needed = &needed;
2525 r.out.info = &info;
2527 torture_comment(tctx, "Testing GetJob level %d\n", r.in.level);
2529 status = dcerpc_spoolss_GetJob(p, tctx, &r);
2530 torture_assert_werr_equal(tctx, r.out.result, WERR_UNKNOWN_LEVEL, "Unexpected return code");
2532 for (i = 0; i < ARRAY_SIZE(levels); i++) {
2534 torture_comment(tctx, "Testing GetJob level %d\n", r.in.level);
2536 needed = 0;
2538 r.in.level = levels[i];
2539 r.in.offered = 0;
2540 r.in.buffer = NULL;
2542 status = dcerpc_spoolss_GetJob(p, tctx, &r);
2543 torture_assert_ntstatus_ok(tctx, status, "GetJob failed");
2545 if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
2546 DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed);
2547 data_blob_clear(&blob);
2548 r.in.buffer = &blob;
2549 r.in.offered = needed;
2551 status = dcerpc_spoolss_GetJob(p, tctx, &r);
2552 torture_assert_ntstatus_ok(tctx, status, "GetJob failed");
2555 torture_assert(tctx, r.out.info, "No job info returned");
2556 torture_assert_werr_ok(tctx, r.out.result, "GetJob failed");
2558 CHECK_NEEDED_SIZE_LEVEL(spoolss_JobInfo, r.out.info, r.in.level, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
2561 return true;
2564 static bool test_SetJob(struct torture_context *tctx,
2565 struct dcerpc_pipe *p,
2566 struct policy_handle *handle, uint32_t job_id,
2567 enum spoolss_JobControl command)
2569 NTSTATUS status;
2570 struct spoolss_SetJob r;
2572 r.in.handle = handle;
2573 r.in.job_id = job_id;
2574 r.in.ctr = NULL;
2575 r.in.command = command;
2577 switch (command) {
2578 case SPOOLSS_JOB_CONTROL_PAUSE:
2579 torture_comment(tctx, "Testing SetJob: SPOOLSS_JOB_CONTROL_PAUSE\n");
2580 break;
2581 case SPOOLSS_JOB_CONTROL_RESUME:
2582 torture_comment(tctx, "Testing SetJob: SPOOLSS_JOB_CONTROL_RESUME\n");
2583 break;
2584 case SPOOLSS_JOB_CONTROL_CANCEL:
2585 torture_comment(tctx, "Testing SetJob: SPOOLSS_JOB_CONTROL_CANCEL\n");
2586 break;
2587 case SPOOLSS_JOB_CONTROL_RESTART:
2588 torture_comment(tctx, "Testing SetJob: SPOOLSS_JOB_CONTROL_RESTART\n");
2589 break;
2590 case SPOOLSS_JOB_CONTROL_DELETE:
2591 torture_comment(tctx, "Testing SetJob: SPOOLSS_JOB_CONTROL_DELETE\n");
2592 break;
2593 case SPOOLSS_JOB_CONTROL_SEND_TO_PRINTER:
2594 torture_comment(tctx, "Testing SetJob: SPOOLSS_JOB_CONTROL_SEND_TO_PRINTER\n");
2595 break;
2596 case SPOOLSS_JOB_CONTROL_LAST_PAGE_EJECTED:
2597 torture_comment(tctx, "Testing SetJob: SPOOLSS_JOB_CONTROL_LAST_PAGE_EJECTED\n");
2598 break;
2599 case SPOOLSS_JOB_CONTROL_RETAIN:
2600 torture_comment(tctx, "Testing SetJob: SPOOLSS_JOB_CONTROL_RETAIN\n");
2601 break;
2602 case SPOOLSS_JOB_CONTROL_RELEASE:
2603 torture_comment(tctx, "Testing SetJob: SPOOLSS_JOB_CONTROL_RELEASE\n");
2604 break;
2605 default:
2606 torture_comment(tctx, "Testing SetJob\n");
2607 break;
2610 status = dcerpc_spoolss_SetJob(p, tctx, &r);
2611 torture_assert_ntstatus_ok(tctx, status, "SetJob failed");
2612 torture_assert_werr_ok(tctx, r.out.result, "SetJob failed");
2614 return true;
2617 static bool test_AddJob(struct torture_context *tctx,
2618 struct dcerpc_pipe *p,
2619 struct policy_handle *handle)
2621 NTSTATUS status;
2622 struct spoolss_AddJob r;
2623 uint32_t needed;
2625 r.in.level = 0;
2626 r.in.handle = handle;
2627 r.in.offered = 0;
2628 r.out.needed = &needed;
2629 r.in.buffer = r.out.buffer = NULL;
2631 torture_comment(tctx, "Testing AddJob\n");
2633 status = dcerpc_spoolss_AddJob(p, tctx, &r);
2634 torture_assert_werr_equal(tctx, r.out.result, WERR_UNKNOWN_LEVEL, "AddJob failed");
2636 r.in.level = 1;
2638 status = dcerpc_spoolss_AddJob(p, tctx, &r);
2639 torture_assert_werr_equal(tctx, r.out.result, WERR_INVALID_PARAM, "AddJob failed");
2641 return true;
2645 static bool test_EnumJobs(struct torture_context *tctx,
2646 struct dcerpc_pipe *p,
2647 struct policy_handle *handle)
2649 NTSTATUS status;
2650 struct spoolss_EnumJobs r;
2651 uint32_t needed;
2652 uint32_t count;
2653 union spoolss_JobInfo *info;
2655 r.in.handle = handle;
2656 r.in.firstjob = 0;
2657 r.in.numjobs = 0xffffffff;
2658 r.in.level = 1;
2659 r.in.buffer = NULL;
2660 r.in.offered = 0;
2661 r.out.needed = &needed;
2662 r.out.count = &count;
2663 r.out.info = &info;
2665 torture_comment(tctx, "Testing EnumJobs\n");
2667 status = dcerpc_spoolss_EnumJobs(p, tctx, &r);
2669 torture_assert_ntstatus_ok(tctx, status, "EnumJobs failed");
2671 if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
2672 int j;
2673 DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed);
2674 data_blob_clear(&blob);
2675 r.in.buffer = &blob;
2676 r.in.offered = needed;
2678 status = dcerpc_spoolss_EnumJobs(p, tctx, &r);
2680 torture_assert_ntstatus_ok(tctx, status, "EnumJobs failed");
2681 torture_assert_werr_ok(tctx, r.out.result, "EnumJobs failed");
2682 torture_assert(tctx, info, "No jobs returned");
2684 CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumJobs, *r.out.info, r.in.level, count, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
2686 for (j = 0; j < count; j++) {
2688 torture_assert(tctx, test_GetJob(tctx, p, handle, info[j].info1.job_id),
2689 "failed to call test_GetJob");
2691 /* FIXME - gd */
2692 if (!torture_setting_bool(tctx, "samba3", false)) {
2693 test_SetJob(tctx, p, handle, info[j].info1.job_id, SPOOLSS_JOB_CONTROL_PAUSE);
2694 test_SetJob(tctx, p, handle, info[j].info1.job_id, SPOOLSS_JOB_CONTROL_RESUME);
2698 } else {
2699 torture_assert_werr_ok(tctx, r.out.result, "EnumJobs failed");
2702 return true;
2705 static bool test_DoPrintTest(struct torture_context *tctx,
2706 struct dcerpc_pipe *p,
2707 struct policy_handle *handle)
2709 bool ret = true;
2710 NTSTATUS status;
2711 struct spoolss_StartDocPrinter s;
2712 struct spoolss_DocumentInfo1 info1;
2713 struct spoolss_StartPagePrinter sp;
2714 struct spoolss_WritePrinter w;
2715 struct spoolss_EndPagePrinter ep;
2716 struct spoolss_EndDocPrinter e;
2717 int i;
2718 uint32_t job_id;
2719 uint32_t num_written;
2721 torture_comment(tctx, "Testing StartDocPrinter\n");
2723 s.in.handle = handle;
2724 s.in.level = 1;
2725 s.in.info.info1 = &info1;
2726 s.out.job_id = &job_id;
2727 info1.document_name = "TorturePrintJob";
2728 info1.output_file = NULL;
2729 info1.datatype = "RAW";
2731 status = dcerpc_spoolss_StartDocPrinter(p, tctx, &s);
2732 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_StartDocPrinter failed");
2733 torture_assert_werr_ok(tctx, s.out.result, "StartDocPrinter failed");
2735 for (i=1; i < 4; i++) {
2736 torture_comment(tctx, "Testing StartPagePrinter: Page[%d]\n", i);
2738 sp.in.handle = handle;
2740 status = dcerpc_spoolss_StartPagePrinter(p, tctx, &sp);
2741 torture_assert_ntstatus_ok(tctx, status,
2742 "dcerpc_spoolss_StartPagePrinter failed");
2743 torture_assert_werr_ok(tctx, sp.out.result, "StartPagePrinter failed");
2745 torture_comment(tctx, "Testing WritePrinter: Page[%d]\n", i);
2747 w.in.handle = handle;
2748 w.in.data = data_blob_string_const(talloc_asprintf(tctx,"TortureTestPage: %d\nData\n",i));
2749 w.out.num_written = &num_written;
2751 status = dcerpc_spoolss_WritePrinter(p, tctx, &w);
2752 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_WritePrinter failed");
2753 torture_assert_werr_ok(tctx, w.out.result, "WritePrinter failed");
2755 torture_comment(tctx, "Testing EndPagePrinter: Page[%d]\n", i);
2757 ep.in.handle = handle;
2759 status = dcerpc_spoolss_EndPagePrinter(p, tctx, &ep);
2760 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EndPagePrinter failed");
2761 torture_assert_werr_ok(tctx, ep.out.result, "EndPagePrinter failed");
2764 torture_comment(tctx, "Testing EndDocPrinter\n");
2766 e.in.handle = handle;
2768 status = dcerpc_spoolss_EndDocPrinter(p, tctx, &e);
2769 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EndDocPrinter failed");
2770 torture_assert_werr_ok(tctx, e.out.result, "EndDocPrinter failed");
2772 ret &= test_AddJob(tctx, p, handle);
2773 ret &= test_EnumJobs(tctx, p, handle);
2775 ret &= test_SetJob(tctx, p, handle, job_id, SPOOLSS_JOB_CONTROL_DELETE);
2777 return ret;
2780 static bool test_PausePrinter(struct torture_context *tctx,
2781 struct dcerpc_pipe *p,
2782 struct policy_handle *handle)
2784 NTSTATUS status;
2785 struct spoolss_SetPrinter r;
2786 struct spoolss_SetPrinterInfoCtr info_ctr;
2787 struct spoolss_DevmodeContainer devmode_ctr;
2788 struct sec_desc_buf secdesc_ctr;
2790 info_ctr.level = 0;
2791 info_ctr.info.info0 = NULL;
2793 ZERO_STRUCT(devmode_ctr);
2794 ZERO_STRUCT(secdesc_ctr);
2796 r.in.handle = handle;
2797 r.in.info_ctr = &info_ctr;
2798 r.in.devmode_ctr = &devmode_ctr;
2799 r.in.secdesc_ctr = &secdesc_ctr;
2800 r.in.command = SPOOLSS_PRINTER_CONTROL_PAUSE;
2802 torture_comment(tctx, "Testing SetPrinter: SPOOLSS_PRINTER_CONTROL_PAUSE\n");
2804 status = dcerpc_spoolss_SetPrinter(p, tctx, &r);
2806 torture_assert_ntstatus_ok(tctx, status, "SetPrinter failed");
2808 torture_assert_werr_ok(tctx, r.out.result, "SetPrinter failed");
2810 return true;
2813 static bool test_ResumePrinter(struct torture_context *tctx,
2814 struct dcerpc_pipe *p,
2815 struct policy_handle *handle)
2817 NTSTATUS status;
2818 struct spoolss_SetPrinter r;
2819 struct spoolss_SetPrinterInfoCtr info_ctr;
2820 struct spoolss_DevmodeContainer devmode_ctr;
2821 struct sec_desc_buf secdesc_ctr;
2823 info_ctr.level = 0;
2824 info_ctr.info.info0 = NULL;
2826 ZERO_STRUCT(devmode_ctr);
2827 ZERO_STRUCT(secdesc_ctr);
2829 r.in.handle = handle;
2830 r.in.info_ctr = &info_ctr;
2831 r.in.devmode_ctr = &devmode_ctr;
2832 r.in.secdesc_ctr = &secdesc_ctr;
2833 r.in.command = SPOOLSS_PRINTER_CONTROL_RESUME;
2835 torture_comment(tctx, "Testing SetPrinter: SPOOLSS_PRINTER_CONTROL_RESUME\n");
2837 status = dcerpc_spoolss_SetPrinter(p, tctx, &r);
2839 torture_assert_ntstatus_ok(tctx, status, "SetPrinter failed");
2841 torture_assert_werr_ok(tctx, r.out.result, "SetPrinter failed");
2843 return true;
2846 static bool test_GetPrinterData(struct torture_context *tctx,
2847 struct dcerpc_pipe *p,
2848 struct policy_handle *handle,
2849 const char *value_name,
2850 enum winreg_Type *type_p,
2851 uint8_t **data_p,
2852 uint32_t *needed_p)
2854 NTSTATUS status;
2855 struct spoolss_GetPrinterData r;
2856 uint32_t needed;
2857 enum winreg_Type type;
2858 union spoolss_PrinterData data;
2860 r.in.handle = handle;
2861 r.in.value_name = value_name;
2862 r.in.offered = 0;
2863 r.out.needed = &needed;
2864 r.out.type = &type;
2865 r.out.data = talloc_zero_array(tctx, uint8_t, r.in.offered);
2867 torture_comment(tctx, "Testing GetPrinterData(%s)\n", r.in.value_name);
2869 status = dcerpc_spoolss_GetPrinterData(p, tctx, &r);
2870 torture_assert_ntstatus_ok(tctx, status, "GetPrinterData failed");
2872 if (W_ERROR_EQUAL(r.out.result, WERR_MORE_DATA)) {
2873 r.in.offered = needed;
2874 r.out.data = talloc_zero_array(tctx, uint8_t, r.in.offered);
2875 status = dcerpc_spoolss_GetPrinterData(p, tctx, &r);
2876 torture_assert_ntstatus_ok(tctx, status, "GetPrinterData failed");
2879 torture_assert_werr_ok(tctx, r.out.result,
2880 talloc_asprintf(tctx, "GetPrinterData(%s) failed", r.in.value_name));
2882 CHECK_NEEDED_SIZE_LEVEL(spoolss_PrinterData, &data, type, lp_iconv_convenience(tctx->lp_ctx), needed, 1);
2884 if (type_p) {
2885 *type_p = type;
2888 if (data_p) {
2889 *data_p = r.out.data;
2892 if (needed_p) {
2893 *needed_p = needed;
2896 return true;
2899 static bool test_GetPrinterDataEx(struct torture_context *tctx,
2900 struct dcerpc_pipe *p,
2901 struct policy_handle *handle,
2902 const char *key_name,
2903 const char *value_name,
2904 enum winreg_Type *type_p,
2905 uint8_t **data_p,
2906 uint32_t *needed_p)
2908 NTSTATUS status;
2909 struct spoolss_GetPrinterDataEx r;
2910 enum winreg_Type type;
2911 uint32_t needed;
2912 union spoolss_PrinterData data;
2914 r.in.handle = handle;
2915 r.in.key_name = key_name;
2916 r.in.value_name = value_name;
2917 r.in.offered = 0;
2918 r.out.type = &type;
2919 r.out.needed = &needed;
2920 r.out.data = talloc_zero_array(tctx, uint8_t, r.in.offered);
2922 torture_comment(tctx, "Testing GetPrinterDataEx(%s - %s)\n",
2923 r.in.key_name, r.in.value_name);
2925 status = dcerpc_spoolss_GetPrinterDataEx(p, tctx, &r);
2926 if (!NT_STATUS_IS_OK(status)) {
2927 if (NT_STATUS_EQUAL(status,NT_STATUS_NET_WRITE_FAULT) &&
2928 p->last_fault_code == DCERPC_FAULT_OP_RNG_ERROR) {
2929 torture_skip(tctx, "GetPrinterDataEx not supported by server\n");
2931 torture_assert_ntstatus_ok(tctx, status, "GetPrinterDataEx failed");
2934 if (W_ERROR_EQUAL(r.out.result, WERR_MORE_DATA)) {
2935 r.in.offered = needed;
2936 r.out.data = talloc_zero_array(tctx, uint8_t, r.in.offered);
2937 status = dcerpc_spoolss_GetPrinterDataEx(p, tctx, &r);
2938 torture_assert_ntstatus_ok(tctx, status, "GetPrinterDataEx failed");
2941 torture_assert_werr_ok(tctx, r.out.result,
2942 talloc_asprintf(tctx, "GetPrinterDataEx(%s - %s) failed", r.in.key_name, r.in.value_name));
2944 CHECK_NEEDED_SIZE_LEVEL(spoolss_PrinterData, &data, type, lp_iconv_convenience(tctx->lp_ctx), needed, 1);
2946 if (type_p) {
2947 *type_p = type;
2950 if (data_p) {
2951 *data_p = r.out.data;
2954 if (needed_p) {
2955 *needed_p = needed;
2958 return true;
2961 static bool test_GetPrinterData_list(struct torture_context *tctx,
2962 struct dcerpc_pipe *p,
2963 struct policy_handle *handle,
2964 const char **architecture)
2966 const char *list[] = {
2967 "W3SvcInstalled",
2968 "BeepEnabled",
2969 "EventLog",
2970 /* "NetPopup", not on w2k8 */
2971 /* "NetPopupToComputer", not on w2k8 */
2972 "MajorVersion",
2973 "MinorVersion",
2974 "DefaultSpoolDirectory",
2975 "Architecture",
2976 "DsPresent",
2977 "OSVersion",
2978 /* "OSVersionEx", not on s3 */
2979 "DNSMachineName"
2981 int i;
2983 for (i=0; i < ARRAY_SIZE(list); i++) {
2984 enum winreg_Type type, type_ex;
2985 uint8_t *data, *data_ex;
2986 uint32_t needed, needed_ex;
2988 torture_assert(tctx, test_GetPrinterData(tctx, p, handle, list[i], &type, &data, &needed),
2989 talloc_asprintf(tctx, "GetPrinterData failed on %s\n", list[i]));
2990 torture_assert(tctx, test_GetPrinterDataEx(tctx, p, handle, "random_string", list[i], &type_ex, &data_ex, &needed_ex),
2991 talloc_asprintf(tctx, "GetPrinterDataEx failed on %s\n", list[i]));
2992 torture_assert_int_equal(tctx, type, type_ex, "type mismatch");
2993 torture_assert_int_equal(tctx, needed, needed_ex, "needed mismatch");
2994 torture_assert_mem_equal(tctx, data, data_ex, needed, "data mismatch");
2996 if (strequal(list[i], "Architecture")) {
2997 if (architecture) {
2998 DATA_BLOB blob = data_blob_const(data, needed);
2999 *architecture = reg_val_data_string(tctx, lp_iconv_convenience(tctx->lp_ctx), REG_SZ, blob);
3004 return true;
3007 static bool test_EnumPrinterData(struct torture_context *tctx,
3008 struct dcerpc_pipe *p,
3009 struct policy_handle *handle,
3010 uint32_t enum_index,
3011 uint32_t value_offered,
3012 uint32_t data_offered,
3013 enum winreg_Type *type_p,
3014 uint32_t *value_needed_p,
3015 uint32_t *data_needed_p,
3016 const char **value_name_p,
3017 uint8_t **data_p,
3018 WERROR *result_p)
3020 struct spoolss_EnumPrinterData r;
3021 uint32_t data_needed;
3022 uint32_t value_needed;
3023 enum winreg_Type type;
3025 r.in.handle = handle;
3026 r.in.enum_index = enum_index;
3027 r.in.value_offered = value_offered;
3028 r.in.data_offered = data_offered;
3029 r.out.data_needed = &data_needed;
3030 r.out.value_needed = &value_needed;
3031 r.out.type = &type;
3032 r.out.data = talloc_zero_array(tctx, uint8_t, r.in.data_offered);
3033 r.out.value_name = talloc_zero_array(tctx, const char, r.in.value_offered);
3035 torture_comment(tctx, "Testing EnumPrinterData(%d)\n", enum_index);
3037 torture_assert_ntstatus_ok(tctx,
3038 dcerpc_spoolss_EnumPrinterData(p, tctx, &r),
3039 "EnumPrinterData failed");
3041 if (type_p) {
3042 *type_p = type;
3044 if (value_needed_p) {
3045 *value_needed_p = value_needed;
3047 if (data_needed_p) {
3048 *data_needed_p = data_needed;
3050 if (value_name_p) {
3051 *value_name_p = r.out.value_name;
3053 if (data_p) {
3054 *data_p = r.out.data;
3056 if (result_p) {
3057 *result_p = r.out.result;
3060 return true;
3064 static bool test_EnumPrinterData_all(struct torture_context *tctx,
3065 struct dcerpc_pipe *p,
3066 struct policy_handle *handle)
3068 uint32_t enum_index = 0;
3069 enum winreg_Type type;
3070 uint32_t value_needed;
3071 uint32_t data_needed;
3072 uint8_t *data;
3073 const char *value_name;
3074 WERROR result;
3076 do {
3077 torture_assert(tctx,
3078 test_EnumPrinterData(tctx, p, handle, enum_index, 0, 0,
3079 &type, &value_needed, &data_needed,
3080 &value_name, &data, &result),
3081 "EnumPrinterData failed");
3083 if (W_ERROR_EQUAL(result, WERR_NO_MORE_ITEMS)) {
3084 break;
3087 torture_assert(tctx,
3088 test_EnumPrinterData(tctx, p, handle, enum_index, value_needed, data_needed,
3089 &type, &value_needed, &data_needed,
3090 &value_name, &data, &result),
3091 "EnumPrinterData failed");
3093 if (W_ERROR_EQUAL(result, WERR_NO_MORE_ITEMS)) {
3094 break;
3097 enum_index++;
3099 } while (W_ERROR_IS_OK(result));
3101 return true;
3104 static bool test_EnumPrinterDataEx(struct torture_context *tctx,
3105 struct dcerpc_pipe *p,
3106 struct policy_handle *handle,
3107 const char *key_name,
3108 uint32_t *count_p,
3109 struct spoolss_PrinterEnumValues **info_p)
3111 struct spoolss_EnumPrinterDataEx r;
3112 struct spoolss_PrinterEnumValues *info;
3113 uint32_t needed;
3114 uint32_t count;
3116 r.in.handle = handle;
3117 r.in.key_name = key_name;
3118 r.in.offered = 0;
3119 r.out.needed = &needed;
3120 r.out.count = &count;
3121 r.out.info = &info;
3123 torture_comment(tctx, "Testing EnumPrinterDataEx(%s)\n", key_name);
3125 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_EnumPrinterDataEx(p, tctx, &r),
3126 "EnumPrinterDataEx failed");
3127 if (W_ERROR_EQUAL(r.out.result, WERR_MORE_DATA)) {
3128 r.in.offered = needed;
3129 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_EnumPrinterDataEx(p, tctx, &r),
3130 "EnumPrinterDataEx failed");
3133 torture_assert_werr_ok(tctx, r.out.result, "EnumPrinterDataEx failed");
3135 CHECK_NEEDED_SIZE_ENUM(spoolss_EnumPrinterDataEx, info, count, lp_iconv_convenience(tctx->lp_ctx), needed, 1);
3137 if (count_p) {
3138 *count_p = count;
3140 if (info_p) {
3141 *info_p = info;
3144 return true;
3147 static bool test_EnumPrinterData_consistency(struct torture_context *tctx,
3148 struct dcerpc_pipe *p,
3149 struct policy_handle *handle)
3151 uint32_t count;
3152 struct spoolss_PrinterEnumValues *info;
3153 int i;
3154 uint32_t value_needed, data_needed;
3155 uint32_t value_offered, data_offered;
3156 WERROR result;
3158 torture_comment(tctx, "Testing EnumPrinterData vs EnumPrinterDataEx consistency");
3160 torture_assert(tctx,
3161 test_EnumPrinterDataEx(tctx, p, handle, "PrinterDriverData", &count, &info),
3162 "failed to call EnumPrinterDataEx");
3164 /* get the max sizes for value and data */
3166 torture_assert(tctx,
3167 test_EnumPrinterData(tctx, p, handle, 0, 0, 0,
3168 NULL, &value_needed, &data_needed,
3169 NULL, NULL, &result),
3170 "EnumPrinterData failed");
3171 torture_assert_werr_ok(tctx, result, "unexpected result");
3173 /* check if the reply from the EnumPrinterData really matches max values */
3175 for (i=0; i < count; i++) {
3176 if (info[i].value_name_len > value_needed) {
3177 torture_fail(tctx,
3178 talloc_asprintf(tctx,
3179 "EnumPrinterDataEx gave a reply with value length %d which is larger then expected max value length %d from EnumPrinterData",
3180 info[i].value_name_len, value_needed));
3182 if (info[i].data_length > data_needed) {
3183 torture_fail(tctx,
3184 talloc_asprintf(tctx,
3185 "EnumPrinterDataEx gave a reply with data length %d which is larger then expected max data length %d from EnumPrinterData",
3186 info[i].data_length, data_needed));
3190 /* assuming that both EnumPrinterData and EnumPrinterDataEx do either
3191 * sort or not sort the replies by value name, we should be able to do
3192 * the following entry comparison */
3194 data_offered = data_needed;
3195 value_offered = value_needed;
3197 for (i=0; i < count; i++) {
3199 enum winreg_Type type;
3200 const char *value_name;
3201 uint8_t *data;
3202 WERROR result;
3203 uint32_t value_needed, data_needed;
3205 torture_assert(tctx,
3206 test_EnumPrinterData(tctx, p, handle, i, value_offered, data_offered,
3207 &type, &value_needed, &data_needed,
3208 &value_name, &data, &result),
3209 "EnumPrinterData failed");
3211 if (i -1 == count) {
3212 torture_assert_werr_equal(tctx, result, WERR_NO_MORE_ITEMS,
3213 "unexpected result");
3214 break;
3215 } else {
3216 torture_assert_werr_ok(tctx, result, "unexpected result");
3219 torture_assert_int_equal(tctx, type, info[i].type, "type mismatch");
3220 torture_assert_int_equal(tctx, value_needed, info[i].value_name_len, "value name length mismatch");
3221 torture_assert_str_equal(tctx, value_name, info[i].value_name, "value name mismatch");
3222 torture_assert_int_equal(tctx, data_needed, info[i].data_length, "data length mismatch");
3223 torture_assert_mem_equal(tctx, data, info[i].data->data, info[i].data_length, "data mismatch");
3226 return true;
3229 static bool test_DeletePrinterData(struct torture_context *tctx,
3230 struct dcerpc_pipe *p,
3231 struct policy_handle *handle,
3232 const char *value_name)
3234 NTSTATUS status;
3235 struct spoolss_DeletePrinterData r;
3237 r.in.handle = handle;
3238 r.in.value_name = value_name;
3240 torture_comment(tctx, "Testing DeletePrinterData(%s)\n",
3241 r.in.value_name);
3243 status = dcerpc_spoolss_DeletePrinterData(p, tctx, &r);
3245 torture_assert_ntstatus_ok(tctx, status, "DeletePrinterData failed");
3246 torture_assert_werr_ok(tctx, r.out.result, "DeletePrinterData failed");
3248 return true;
3251 static bool test_DeletePrinterDataEx(struct torture_context *tctx,
3252 struct dcerpc_pipe *p,
3253 struct policy_handle *handle,
3254 const char *key_name,
3255 const char *value_name)
3257 struct spoolss_DeletePrinterDataEx r;
3259 r.in.handle = handle;
3260 r.in.key_name = key_name;
3261 r.in.value_name = value_name;
3263 torture_comment(tctx, "Testing DeletePrinterDataEx(%s - %s)\n",
3264 r.in.key_name, r.in.value_name);
3266 torture_assert_ntstatus_ok(tctx,
3267 dcerpc_spoolss_DeletePrinterDataEx(p, tctx, &r),
3268 "DeletePrinterDataEx failed");
3269 torture_assert_werr_ok(tctx, r.out.result,
3270 "DeletePrinterDataEx failed");
3272 return true;
3275 static bool test_DeletePrinterKey(struct torture_context *tctx,
3276 struct dcerpc_pipe *p,
3277 struct policy_handle *handle,
3278 const char *key_name)
3280 struct spoolss_DeletePrinterKey r;
3282 r.in.handle = handle;
3283 r.in.key_name = key_name;
3285 torture_comment(tctx, "Testing DeletePrinterKey(%s)\n", r.in.key_name);
3287 if (strequal(key_name, "") && !torture_setting_bool(tctx, "dangerous", false)) {
3288 torture_skip(tctx, "not wiping out printer registry - enable dangerous tests to use\n");
3289 return true;
3292 torture_assert_ntstatus_ok(tctx,
3293 dcerpc_spoolss_DeletePrinterKey(p, tctx, &r),
3294 "DeletePrinterKey failed");
3295 torture_assert_werr_ok(tctx, r.out.result,
3296 "DeletePrinterKey failed");
3298 return true;
3301 static bool test_winreg_OpenHKLM(struct torture_context *tctx,
3302 struct dcerpc_pipe *p,
3303 struct policy_handle *handle)
3305 struct winreg_OpenHKLM r;
3307 r.in.system_name = NULL;
3308 r.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
3309 r.out.handle = handle;
3311 torture_comment(tctx, "Testing winreg_OpenHKLM\n");
3313 torture_assert_ntstatus_ok(tctx, dcerpc_winreg_OpenHKLM(p, tctx, &r), "OpenHKLM failed");
3314 torture_assert_werr_ok(tctx, r.out.result, "OpenHKLM failed");
3316 return true;
3319 static void init_winreg_String(struct winreg_String *name, const char *s)
3321 name->name = s;
3322 if (s) {
3323 name->name_len = 2 * (strlen_m(s) + 1);
3324 name->name_size = name->name_len;
3325 } else {
3326 name->name_len = 0;
3327 name->name_size = 0;
3331 static bool test_winreg_OpenKey(struct torture_context *tctx,
3332 struct dcerpc_pipe *p,
3333 struct policy_handle *hive_handle,
3334 const char *keyname,
3335 struct policy_handle *key_handle)
3337 struct winreg_OpenKey r;
3339 r.in.parent_handle = hive_handle;
3340 init_winreg_String(&r.in.keyname, keyname);
3341 r.in.options = REG_KEYTYPE_NON_VOLATILE;
3342 r.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
3343 r.out.handle = key_handle;
3345 torture_comment(tctx, "Testing winreg_OpenKey(%s)\n", keyname);
3347 torture_assert_ntstatus_ok(tctx, dcerpc_winreg_OpenKey(p, tctx, &r), "OpenKey failed");
3348 torture_assert_werr_ok(tctx, r.out.result, "OpenKey failed");
3350 return true;
3353 static bool test_winreg_CloseKey(struct torture_context *tctx,
3354 struct dcerpc_pipe *p,
3355 struct policy_handle *handle)
3357 struct winreg_CloseKey r;
3359 r.in.handle = handle;
3360 r.out.handle = handle;
3362 torture_comment(tctx, "Testing winreg_CloseKey\n");
3364 torture_assert_ntstatus_ok(tctx, dcerpc_winreg_CloseKey(p, tctx, &r), "CloseKey failed");
3365 torture_assert_werr_ok(tctx, r.out.result, "CloseKey failed");
3367 return true;
3370 bool test_winreg_QueryValue(struct torture_context *tctx,
3371 struct dcerpc_pipe *p,
3372 struct policy_handle *handle,
3373 const char *value_name,
3374 enum winreg_Type *type_p,
3375 uint32_t *data_size_p,
3376 uint32_t *data_length_p,
3377 uint8_t **data_p)
3379 struct winreg_QueryValue r;
3380 enum winreg_Type type = REG_NONE;
3381 uint32_t data_size = 0;
3382 uint32_t data_length = 0;
3383 struct winreg_String valuename;
3384 uint8_t *data = NULL;
3386 init_winreg_String(&valuename, value_name);
3388 data = talloc_zero_array(tctx, uint8_t, 0);
3390 r.in.handle = handle;
3391 r.in.value_name = &valuename;
3392 r.in.type = &type;
3393 r.in.data_size = &data_size;
3394 r.in.data_length = &data_length;
3395 r.in.data = data;
3396 r.out.type = &type;
3397 r.out.data = data;
3398 r.out.data_size = &data_size;
3399 r.out.data_length = &data_length;
3401 torture_comment(tctx, "Testing winreg_QueryValue(%s)\n", value_name);
3403 torture_assert_ntstatus_ok(tctx, dcerpc_winreg_QueryValue(p, tctx, &r), "QueryValue failed");
3404 if (W_ERROR_EQUAL(r.out.result, WERR_MORE_DATA)) {
3405 *r.in.data_size = *r.out.data_size;
3406 data = talloc_zero_array(tctx, uint8_t, *r.in.data_size);
3407 r.in.data = data;
3408 r.out.data = data;
3409 torture_assert_ntstatus_ok(tctx, dcerpc_winreg_QueryValue(p, tctx, &r), "QueryValue failed");
3411 torture_assert_werr_ok(tctx, r.out.result, "QueryValue failed");
3413 if (type_p) {
3414 *type_p = *r.out.type;
3416 if (data_size_p) {
3417 *data_size_p = *r.out.data_size;
3419 if (data_length_p) {
3420 *data_length_p = *r.out.data_length;
3422 if (data_p) {
3423 *data_p = r.out.data;
3426 return true;
3429 static bool test_winreg_query_printerdata(struct torture_context *tctx,
3430 struct dcerpc_pipe *p,
3431 struct policy_handle *handle,
3432 const char *printer_name,
3433 const char *key_name,
3434 const char *value_name,
3435 enum winreg_Type *w_type,
3436 uint32_t *w_size,
3437 uint32_t *w_length,
3438 uint8_t **w_data)
3440 const char *printer_key;
3441 struct policy_handle key_handle;
3443 printer_key = talloc_asprintf(tctx, "%s\\%s\\%s",
3444 TOP_LEVEL_PRINTER_KEY, printer_name, key_name);
3446 torture_assert(tctx,
3447 test_winreg_OpenKey(tctx, p, handle, printer_key, &key_handle), "");
3449 torture_assert(tctx,
3450 test_winreg_QueryValue(tctx, p, &key_handle, value_name, w_type, w_size, w_length, w_data), "");
3452 torture_assert(tctx,
3453 test_winreg_CloseKey(tctx, p, &key_handle), "");
3455 return true;
3458 static bool test_SetPrinterData(struct torture_context *tctx,
3459 struct dcerpc_pipe *p,
3460 struct policy_handle *handle,
3461 const char *value_name,
3462 enum winreg_Type type,
3463 uint8_t *data,
3464 uint32_t offered)
3466 struct spoolss_SetPrinterData r;
3468 r.in.handle = handle;
3469 r.in.value_name = value_name;
3470 r.in.type = type;
3471 r.in.data = data;
3472 r.in.offered = offered;
3474 torture_comment(tctx, "Testing SetPrinterData(%s)\n",
3475 r.in.value_name);
3477 torture_assert_ntstatus_ok(tctx,
3478 dcerpc_spoolss_SetPrinterData(p, tctx, &r),
3479 "SetPrinterData failed");
3480 torture_assert_werr_ok(tctx, r.out.result,
3481 "SetPrinterData failed");
3483 return true;
3486 static bool test_SetPrinterData_matrix(struct torture_context *tctx,
3487 struct dcerpc_pipe *p,
3488 struct policy_handle *handle,
3489 const char *printer_name,
3490 struct dcerpc_pipe *winreg_pipe,
3491 struct policy_handle *hive_handle)
3493 const char *values[] = {
3494 "spootyfoot",
3495 "spooty\\foot",
3496 #if 0
3497 /* FIXME: not working with s3 atm. */
3498 "spooty,foot",
3499 "spooty,fo,ot",
3500 #endif
3501 "spooty foot",
3502 #if 0
3503 /* FIXME: not working with s3 atm. */
3504 "spooty\\fo,ot",
3505 "spooty,fo\\ot"
3506 #endif
3508 int i;
3510 for (i=0; i < ARRAY_SIZE(values); i++) {
3512 enum winreg_Type type;
3513 DATA_BLOB blob;
3514 uint8_t *data;
3515 uint32_t needed;
3517 torture_assert(tctx,
3518 reg_string_to_val(tctx, lp_iconv_convenience(tctx->lp_ctx),
3519 "REG_SZ", "dog", &type, &blob), "");
3521 torture_assert(tctx,
3522 test_SetPrinterData(tctx, p, handle, values[i], REG_SZ, blob.data, blob.length),
3523 "SetPrinterData failed");
3525 torture_assert(tctx,
3526 test_GetPrinterData(tctx, p, handle, values[i], &type, &data, &needed),
3527 "GetPrinterData failed");
3529 torture_assert_int_equal(tctx, type, REG_SZ, "type mismatch");
3530 torture_assert_int_equal(tctx, needed, blob.length, "size mismatch");
3531 torture_assert_mem_equal(tctx, data, blob.data, blob.length, "buffer mismatch");
3533 if (winreg_pipe && hive_handle) {
3535 enum winreg_Type w_type;
3536 uint32_t w_size;
3537 uint32_t w_length;
3538 uint8_t *w_data;
3540 torture_assert(tctx,
3541 test_winreg_query_printerdata(tctx, winreg_pipe, hive_handle,
3542 printer_name, "PrinterDriverData", values[i],
3543 &w_type, &w_size, &w_length, &w_data), "");
3545 torture_assert_int_equal(tctx, w_type, REG_SZ, "winreg type mismatch");
3546 torture_assert_int_equal(tctx, w_size, blob.length, "winreg size mismatch");
3547 torture_assert_int_equal(tctx, w_length, blob.length, "winreg length mismatch");
3548 torture_assert_mem_equal(tctx, w_data, blob.data, blob.length, "winreg buffer mismatch");
3551 torture_assert(tctx,
3552 test_DeletePrinterData(tctx, p, handle, values[i]),
3553 "DeletePrinterData failed");
3556 return true;
3560 static bool test_EnumPrinterKey(struct torture_context *tctx,
3561 struct dcerpc_pipe *p,
3562 struct policy_handle *handle,
3563 const char *key_name,
3564 const char ***array);
3566 static bool test_SetPrinterDataEx(struct torture_context *tctx,
3567 struct dcerpc_pipe *p,
3568 struct policy_handle *handle,
3569 const char *key_name,
3570 const char *value_name,
3571 enum winreg_Type type,
3572 uint8_t *data,
3573 uint32_t offered)
3575 NTSTATUS status;
3576 struct spoolss_SetPrinterDataEx r;
3578 r.in.handle = handle;
3579 r.in.key_name = key_name;
3580 r.in.value_name = value_name;
3581 r.in.type = type;
3582 r.in.data = data;
3583 r.in.offered = offered;
3585 torture_comment(tctx, "Testing SetPrinterDataEx(%s - %s) type: %s, offered: 0x%08x\n",
3586 r.in.key_name, r.in.value_name, str_regtype(r.in.type), r.in.offered);
3588 status = dcerpc_spoolss_SetPrinterDataEx(p, tctx, &r);
3590 torture_assert_ntstatus_ok(tctx, status, "SetPrinterDataEx failed");
3591 torture_assert_werr_ok(tctx, r.out.result, "SetPrinterDataEx failed");
3593 return true;
3596 static bool test_SetPrinterDataEx_matrix(struct torture_context *tctx,
3597 struct dcerpc_pipe *p,
3598 struct policy_handle *handle,
3599 const char *printername,
3600 struct dcerpc_pipe *winreg_pipe,
3601 struct policy_handle *hive_handle)
3603 const char *value_name = "dog";
3604 const char *keys[] = {
3605 "torturedataex",
3606 "torture data ex",
3607 #if 0
3608 /* FIXME: not working with s3 atm. */
3609 "torturedataex_with_subkey\\subkey",
3610 "torturedataex_with_subkey\\subkey:0",
3611 "torturedataex_with_subkey\\subkey:1",
3612 "torturedataex_with_subkey\\subkey\\subsubkey",
3613 "torturedataex_with_subkey\\subkey\\subsubkey:0",
3614 "torturedataex_with_subkey\\subkey\\subsubkey:1",
3615 #endif
3616 "torture,data",
3617 #if 0
3618 /* FIXME: not working with s3 atm. */
3620 "torture,data,ex",
3621 "torture,data\\ex",
3622 "torture\\data,ex"
3623 #endif
3625 enum winreg_Type types[] = {
3626 REG_SZ,
3627 REG_DWORD,
3628 REG_BINARY
3630 const char *str = "abcdefghijklmnopqrstuvwxzy";
3631 int i, t, s;
3634 for (i=0; i < ARRAY_SIZE(keys); i++) {
3635 for (t=0; t < ARRAY_SIZE(types); t++) {
3636 for (s=0; s < strlen(str); s++) {
3638 char *c;
3639 const char *key;
3640 enum winreg_Type type;
3641 const char *string = talloc_strndup(tctx, str, s);
3642 DATA_BLOB blob = data_blob_string_const(string);
3643 const char **subkeys;
3644 DATA_BLOB data;
3645 uint8_t *data_out;
3646 uint32_t needed, offered = 0;
3647 uint32_t ecount;
3648 struct spoolss_PrinterEnumValues *einfo;
3650 switch (types[t]) {
3651 case REG_BINARY:
3652 case REG_DWORD:
3653 data = blob;
3654 offered = blob.length;
3655 break;
3656 case REG_SZ:
3657 torture_assert(tctx,
3658 reg_string_to_val(tctx, lp_iconv_convenience(tctx->lp_ctx),
3659 "REG_SZ", string, &type, &data), "");
3660 offered = data.length;
3661 /*strlen_m_term(data.string)*2;*/
3662 break;
3663 default:
3664 torture_fail(tctx, talloc_asprintf(tctx, "type %d untested\n", types[t]));
3667 torture_assert(tctx,
3668 test_SetPrinterDataEx(tctx, p, handle, keys[i], value_name, types[t], data.data, offered),
3669 "failed to call SetPrinterDataEx");
3671 torture_assert(tctx,
3672 test_GetPrinterDataEx(tctx, p, handle, keys[i], value_name, &type, &data_out, &needed),
3673 "failed to call GetPrinterDataEx");
3675 torture_assert(tctx,
3676 test_EnumPrinterDataEx(tctx, p, handle, keys[i], &ecount, &einfo),
3677 "failed to call EnumPrinterDataEx");
3679 torture_assert_int_equal(tctx, types[t], type, "type mismatch");
3680 torture_assert_int_equal(tctx, needed, offered, "size mismatch");
3681 torture_assert_mem_equal(tctx, data_out, data.data, offered, "buffer mismatch");
3683 torture_assert_int_equal(tctx, ecount, 1, "unexpected enum count");
3684 torture_assert_str_equal(tctx, einfo[0].value_name, value_name, "value_name mismatch");
3685 torture_assert_int_equal(tctx, einfo[0].value_name_len, strlen_m_term(value_name)*2, "unexpected value_name_len");
3686 torture_assert_int_equal(tctx, einfo[0].type, types[t], "type mismatch");
3687 torture_assert_int_equal(tctx, einfo[0].data_length, offered, "size mismatch");
3688 if (einfo[0].data_length > 0) {
3689 torture_assert_mem_equal(tctx, einfo[0].data->data, data.data, offered, "buffer mismatch");
3692 if (winreg_pipe && hive_handle) {
3694 enum winreg_Type w_type;
3695 uint32_t w_size;
3696 uint32_t w_length;
3697 uint8_t *w_data;
3699 torture_assert(tctx,
3700 test_winreg_query_printerdata(tctx, winreg_pipe, hive_handle,
3701 printername, keys[i], value_name,
3702 &w_type, &w_size, &w_length, &w_data), "");
3704 torture_assert_int_equal(tctx, w_type, types[t], "winreg type mismatch");
3705 torture_assert_int_equal(tctx, w_size, offered, "winreg size mismatch");
3706 torture_assert_int_equal(tctx, w_length, offered, "winreg length mismatch");
3707 torture_assert_mem_equal(tctx, w_data, data.data, offered, "winreg buffer mismatch");
3710 key = talloc_strdup(tctx, keys[i]);
3712 if (!test_DeletePrinterDataEx(tctx, p, handle, keys[i], value_name)) {
3713 return false;
3716 c = strchr(key, '\\');
3717 if (c) {
3718 int k;
3720 /* we have subkeys */
3722 *c = 0;
3724 if (!test_EnumPrinterKey(tctx, p, handle, key, &subkeys)) {
3725 return false;
3728 for (k=0; subkeys && subkeys[k]; k++) {
3730 const char *current_key = talloc_asprintf(tctx, "%s\\%s", key, subkeys[k]);
3732 if (!test_DeletePrinterKey(tctx, p, handle, current_key)) {
3733 return false;
3737 if (!test_DeletePrinterKey(tctx, p, handle, key)) {
3738 return false;
3741 } else {
3742 if (!test_DeletePrinterKey(tctx, p, handle, key)) {
3743 return false;
3750 return true;
3753 static bool test_PrinterData_winreg(struct torture_context *tctx,
3754 struct dcerpc_pipe *p,
3755 struct policy_handle *handle,
3756 const char *printer_name)
3758 struct dcerpc_pipe *p2;
3759 bool ret = true;
3760 struct policy_handle hive_handle;
3762 torture_assert_ntstatus_ok(tctx,
3763 torture_rpc_connection(tctx, &p2, &ndr_table_winreg),
3764 "could not open winreg pipe");
3766 torture_assert(tctx, test_winreg_OpenHKLM(tctx, p2, &hive_handle), "");
3768 ret &= test_SetPrinterData_matrix(tctx, p, handle, printer_name, p2, &hive_handle);
3769 ret &= test_SetPrinterDataEx_matrix(tctx, p, handle, printer_name, p2, &hive_handle);
3771 test_winreg_CloseKey(tctx, p2, &hive_handle);
3773 talloc_free(p2);
3775 return ret;
3778 static bool test_GetChangeID_PrinterData(struct torture_context *tctx,
3779 struct dcerpc_pipe *p,
3780 struct policy_handle *handle,
3781 uint32_t *change_id)
3783 enum winreg_Type type;
3784 uint8_t *data;
3785 uint32_t needed;
3787 torture_assert(tctx,
3788 test_GetPrinterData(tctx, p, handle, "ChangeID", &type, &data, &needed),
3789 "failed to call GetPrinterData");
3791 torture_assert(tctx, type == REG_DWORD, "unexpected type");
3792 torture_assert_int_equal(tctx, needed, 4, "unexpected size");
3794 *change_id = IVAL(data, 0);
3796 return true;
3799 static bool test_GetChangeID_PrinterDataEx(struct torture_context *tctx,
3800 struct dcerpc_pipe *p,
3801 struct policy_handle *handle,
3802 uint32_t *change_id)
3804 enum winreg_Type type;
3805 uint8_t *data;
3806 uint32_t needed;
3808 torture_assert(tctx,
3809 test_GetPrinterDataEx(tctx, p, handle, "PrinterDriverData", "ChangeID", &type, &data, &needed),
3810 "failed to call GetPrinterData");
3812 torture_assert(tctx, type == REG_DWORD, "unexpected type");
3813 torture_assert_int_equal(tctx, needed, 4, "unexpected size");
3815 *change_id = IVAL(data, 0);
3817 return true;
3820 static bool test_GetChangeID_PrinterInfo(struct torture_context *tctx,
3821 struct dcerpc_pipe *p,
3822 struct policy_handle *handle,
3823 uint32_t *change_id)
3825 union spoolss_PrinterInfo info;
3827 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 0, &info),
3828 "failed to query Printer level 0");
3830 *change_id = info.info0.change_id;
3832 return true;
3835 static bool test_ChangeID(struct torture_context *tctx,
3836 struct dcerpc_pipe *p,
3837 struct policy_handle *handle)
3839 uint32_t change_id, change_id_ex, change_id_info;
3840 uint32_t change_id2, change_id_ex2, change_id_info2;
3841 union spoolss_PrinterInfo info;
3842 const char *comment;
3845 torture_comment(tctx, "Testing ChangeID: id change test #1\n");
3847 torture_assert(tctx, test_GetChangeID_PrinterData(tctx, p, handle, &change_id),
3848 "failed to query for ChangeID");
3849 torture_assert(tctx, test_GetChangeID_PrinterDataEx(tctx, p, handle, &change_id_ex),
3850 "failed to query for ChangeID");
3851 torture_assert(tctx, test_GetChangeID_PrinterInfo(tctx, p, handle, &change_id_info),
3852 "failed to query for ChangeID");
3854 torture_assert_int_equal(tctx, change_id, change_id_ex,
3855 "change_ids should all be equal");
3856 torture_assert_int_equal(tctx, change_id_ex, change_id_info,
3857 "change_ids should all be equal");
3860 torture_comment(tctx, "Testing ChangeID: id change test #2\n");
3862 torture_assert(tctx, test_GetChangeID_PrinterData(tctx, p, handle, &change_id),
3863 "failed to query for ChangeID");
3864 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 2, &info),
3865 "failed to query Printer level 2");
3866 torture_assert(tctx, test_GetChangeID_PrinterDataEx(tctx, p, handle, &change_id_ex),
3867 "failed to query for ChangeID");
3868 torture_assert(tctx, test_GetChangeID_PrinterInfo(tctx, p, handle, &change_id_info),
3869 "failed to query for ChangeID");
3870 torture_assert_int_equal(tctx, change_id, change_id_ex,
3871 "change_id should not have changed");
3872 torture_assert_int_equal(tctx, change_id_ex, change_id_info,
3873 "change_id should not have changed");
3876 torture_comment(tctx, "Testing ChangeID: id change test #3\n");
3878 torture_assert(tctx, test_GetChangeID_PrinterData(tctx, p, handle, &change_id),
3879 "failed to query for ChangeID");
3880 torture_assert(tctx, test_GetChangeID_PrinterDataEx(tctx, p, handle, &change_id_ex),
3881 "failed to query for ChangeID");
3882 torture_assert(tctx, test_GetChangeID_PrinterInfo(tctx, p, handle, &change_id_info),
3883 "failed to query for ChangeID");
3884 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 2, &info),
3885 "failed to query Printer level 2");
3886 comment = talloc_strdup(tctx, info.info2.comment);
3889 struct spoolss_SetPrinterInfoCtr info_ctr;
3890 struct spoolss_DevmodeContainer devmode_ctr;
3891 struct sec_desc_buf secdesc_ctr;
3892 struct spoolss_SetPrinterInfo2 info2;
3894 ZERO_STRUCT(info_ctr);
3895 ZERO_STRUCT(devmode_ctr);
3896 ZERO_STRUCT(secdesc_ctr);
3898 info2.servername = info.info2.servername;
3899 info2.printername = info.info2.printername;
3900 info2.sharename = info.info2.sharename;
3901 info2.portname = info.info2.portname;
3902 info2.drivername = info.info2.drivername;
3903 info2.comment = "torture_comment";
3904 info2.location = info.info2.location;
3905 info2.devmode_ptr = 0;
3906 info2.sepfile = info.info2.sepfile;
3907 info2.printprocessor = info.info2.printprocessor;
3908 info2.datatype = info.info2.datatype;
3909 info2.parameters = info.info2.parameters;
3910 info2.secdesc_ptr = 0;
3911 info2.attributes = info.info2.attributes;
3912 info2.priority = info.info2.priority;
3913 info2.defaultpriority = info.info2.defaultpriority;
3914 info2.starttime = info.info2.starttime;
3915 info2.untiltime = info.info2.untiltime;
3916 info2.status = info.info2.status;
3917 info2.cjobs = info.info2.cjobs;
3918 info2.averageppm = info.info2.averageppm;
3920 info_ctr.level = 2;
3921 info_ctr.info.info2 = &info2;
3923 torture_assert(tctx, test_SetPrinter(tctx, p, handle, &info_ctr, &devmode_ctr, &secdesc_ctr, 0),
3924 "failed to call SetPrinter");
3926 info2.comment = comment;
3928 torture_assert(tctx, test_SetPrinter(tctx, p, handle, &info_ctr, &devmode_ctr, &secdesc_ctr, 0),
3929 "failed to call SetPrinter");
3933 torture_assert(tctx, test_GetChangeID_PrinterData(tctx, p, handle, &change_id2),
3934 "failed to query for ChangeID");
3935 torture_assert(tctx, test_GetChangeID_PrinterDataEx(tctx, p, handle, &change_id_ex2),
3936 "failed to query for ChangeID");
3937 torture_assert(tctx, test_GetChangeID_PrinterInfo(tctx, p, handle, &change_id_info2),
3938 "failed to query for ChangeID");
3940 torture_assert_int_equal(tctx, change_id2, change_id_ex2,
3941 "change_ids should all be equal");
3942 torture_assert_int_equal(tctx, change_id_ex2, change_id_info2,
3943 "change_ids should all be equal");
3945 torture_assert(tctx, (change_id < change_id2),
3946 talloc_asprintf(tctx, "change_id %d needs to be larger than change_id %d",
3947 change_id2, change_id));
3948 torture_assert(tctx, (change_id_ex < change_id_ex2),
3949 talloc_asprintf(tctx, "change_id %d needs to be larger than change_id %d",
3950 change_id_ex2, change_id_ex));
3951 torture_assert(tctx, (change_id_info < change_id_info2),
3952 talloc_asprintf(tctx, "change_id %d needs to be larger than change_id %d",
3953 change_id_info2, change_id_info));
3955 return true;
3958 static bool test_SecondaryClosePrinter(struct torture_context *tctx,
3959 struct dcerpc_pipe *p,
3960 struct policy_handle *handle)
3962 NTSTATUS status;
3963 struct dcerpc_binding *b;
3964 struct dcerpc_pipe *p2;
3965 struct spoolss_ClosePrinter cp;
3967 /* only makes sense on SMB */
3968 if (p->conn->transport.transport != NCACN_NP) {
3969 return true;
3972 torture_comment(tctx, "testing close on secondary pipe\n");
3974 status = dcerpc_parse_binding(tctx, p->conn->binding_string, &b);
3975 torture_assert_ntstatus_ok(tctx, status, "Failed to parse dcerpc binding");
3977 status = dcerpc_secondary_connection(p, &p2, b);
3978 torture_assert_ntstatus_ok(tctx, status, "Failed to create secondary connection");
3980 status = dcerpc_bind_auth_none(p2, &ndr_table_spoolss);
3981 torture_assert_ntstatus_ok(tctx, status, "Failed to create bind on secondary connection");
3983 cp.in.handle = handle;
3984 cp.out.handle = handle;
3986 status = dcerpc_spoolss_ClosePrinter(p2, tctx, &cp);
3987 torture_assert_ntstatus_equal(tctx, status, NT_STATUS_NET_WRITE_FAULT,
3988 "ERROR: Allowed close on secondary connection");
3990 torture_assert_int_equal(tctx, p2->last_fault_code, DCERPC_FAULT_CONTEXT_MISMATCH,
3991 "Unexpected fault code");
3993 talloc_free(p2);
3995 return true;
3998 static bool test_OpenPrinter_badname(struct torture_context *tctx,
3999 struct dcerpc_pipe *p, const char *name)
4001 NTSTATUS status;
4002 struct spoolss_OpenPrinter op;
4003 struct spoolss_OpenPrinterEx opEx;
4004 struct policy_handle handle;
4005 bool ret = true;
4007 op.in.printername = name;
4008 op.in.datatype = NULL;
4009 op.in.devmode_ctr.devmode= NULL;
4010 op.in.access_mask = 0;
4011 op.out.handle = &handle;
4013 torture_comment(tctx, "\nTesting OpenPrinter(%s) with bad name\n", op.in.printername);
4015 status = dcerpc_spoolss_OpenPrinter(p, tctx, &op);
4016 torture_assert_ntstatus_ok(tctx, status, "OpenPrinter failed");
4017 if (!W_ERROR_EQUAL(WERR_INVALID_PRINTER_NAME,op.out.result)) {
4018 torture_comment(tctx, "OpenPrinter(%s) unexpected result[%s] should be WERR_INVALID_PRINTER_NAME\n",
4019 name, win_errstr(op.out.result));
4022 if (W_ERROR_IS_OK(op.out.result)) {
4023 ret &=test_ClosePrinter(tctx, p, &handle);
4026 opEx.in.printername = name;
4027 opEx.in.datatype = NULL;
4028 opEx.in.devmode_ctr.devmode = NULL;
4029 opEx.in.access_mask = 0;
4030 opEx.in.level = 1;
4031 opEx.in.userlevel.level1 = NULL;
4032 opEx.out.handle = &handle;
4034 torture_comment(tctx, "Testing OpenPrinterEx(%s) with bad name\n", opEx.in.printername);
4036 status = dcerpc_spoolss_OpenPrinterEx(p, tctx, &opEx);
4037 torture_assert_ntstatus_ok(tctx, status, "OpenPrinterEx failed");
4038 if (!W_ERROR_EQUAL(WERR_INVALID_PARAM,opEx.out.result)) {
4039 torture_comment(tctx, "OpenPrinterEx(%s) unexpected result[%s] should be WERR_INVALID_PARAM\n",
4040 name, win_errstr(opEx.out.result));
4043 if (W_ERROR_IS_OK(opEx.out.result)) {
4044 ret &=test_ClosePrinter(tctx, p, &handle);
4047 return ret;
4050 static bool test_OpenPrinter(struct torture_context *tctx,
4051 struct dcerpc_pipe *p,
4052 const char *name,
4053 const char *environment)
4055 NTSTATUS status;
4056 struct spoolss_OpenPrinter r;
4057 struct policy_handle handle;
4058 bool ret = true;
4060 r.in.printername = talloc_asprintf(tctx, "\\\\%s\\%s", dcerpc_server_name(p), name);
4061 r.in.datatype = NULL;
4062 r.in.devmode_ctr.devmode= NULL;
4063 r.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
4064 r.out.handle = &handle;
4066 torture_comment(tctx, "Testing OpenPrinter(%s)\n", r.in.printername);
4068 status = dcerpc_spoolss_OpenPrinter(p, tctx, &r);
4070 torture_assert_ntstatus_ok(tctx, status, "OpenPrinter failed");
4072 torture_assert_werr_ok(tctx, r.out.result, "OpenPrinter failed");
4074 if (!test_GetPrinter(tctx, p, &handle, environment)) {
4075 ret = false;
4078 if (!torture_setting_bool(tctx, "samba3", false)) {
4079 if (!test_SecondaryClosePrinter(tctx, p, &handle)) {
4080 ret = false;
4084 if (!test_ClosePrinter(tctx, p, &handle)) {
4085 ret = false;
4088 return ret;
4091 static bool call_OpenPrinterEx(struct torture_context *tctx,
4092 struct dcerpc_pipe *p,
4093 const char *name,
4094 struct spoolss_DeviceMode *devmode,
4095 struct policy_handle *handle)
4097 struct spoolss_OpenPrinterEx r;
4098 struct spoolss_UserLevel1 userlevel1;
4099 NTSTATUS status;
4101 if (name && name[0]) {
4102 r.in.printername = talloc_asprintf(tctx, "\\\\%s\\%s",
4103 dcerpc_server_name(p), name);
4104 } else {
4105 r.in.printername = talloc_asprintf(tctx, "\\\\%s",
4106 dcerpc_server_name(p));
4109 r.in.datatype = NULL;
4110 r.in.devmode_ctr.devmode= devmode;
4111 r.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
4112 r.in.level = 1;
4113 r.in.userlevel.level1 = &userlevel1;
4114 r.out.handle = handle;
4116 userlevel1.size = 1234;
4117 userlevel1.client = "hello";
4118 userlevel1.user = "spottyfoot!";
4119 userlevel1.build = 1;
4120 userlevel1.major = 2;
4121 userlevel1.minor = 3;
4122 userlevel1.processor = 4;
4124 torture_comment(tctx, "Testing OpenPrinterEx(%s)\n", r.in.printername);
4126 status = dcerpc_spoolss_OpenPrinterEx(p, tctx, &r);
4128 torture_assert_ntstatus_ok(tctx, status, "OpenPrinterEx failed");
4130 torture_assert_werr_ok(tctx, r.out.result, "OpenPrinterEx failed");
4132 return true;
4135 static bool test_OpenPrinterEx(struct torture_context *tctx,
4136 struct dcerpc_pipe *p,
4137 const char *name,
4138 const char *environment)
4140 struct policy_handle handle;
4141 bool ret = true;
4143 if (!call_OpenPrinterEx(tctx, p, name, NULL, &handle)) {
4144 return false;
4147 if (!test_PrinterInfo_SD(tctx, p, &handle)) {
4148 ret = false;
4151 if (!test_GetPrinter(tctx, p, &handle, environment)) {
4152 ret = false;
4155 if (!test_EnumForms(tctx, p, &handle, false)) {
4156 ret = false;
4159 if (!test_AddForm(tctx, p, &handle, false)) {
4160 ret = false;
4163 if (!test_EnumPrinterData_all(tctx, p, &handle)) {
4164 ret = false;
4167 if (!test_EnumPrinterDataEx(tctx, p, &handle, "PrinterDriverData", NULL, NULL)) {
4168 ret = false;
4171 if (!test_EnumPrinterData_consistency(tctx, p, handle)) {
4172 ret = false;
4175 if (!test_printer_keys(tctx, p, &handle)) {
4176 ret = false;
4179 if (!test_PausePrinter(tctx, p, &handle)) {
4180 ret = false;
4183 if (!test_DoPrintTest(tctx, p, &handle)) {
4184 ret = false;
4187 if (!test_ResumePrinter(tctx, p, &handle)) {
4188 ret = false;
4191 if (!test_SetPrinterData_matrix(tctx, p, &handle, name, NULL, NULL)) {
4192 ret = false;
4195 if (!test_SetPrinterDataEx_matrix(tctx, p, &handle, name, NULL, NULL)) {
4196 ret = false;
4199 if (!torture_setting_bool(tctx, "samba3", false)) {
4200 if (!test_SecondaryClosePrinter(tctx, p, &handle)) {
4201 ret = false;
4205 if (!test_ClosePrinter(tctx, p, &handle)) {
4206 ret = false;
4209 return ret;
4212 static bool test_EnumPrinters_old(struct torture_context *tctx,
4213 struct dcerpc_pipe *p,
4214 const char *environment)
4216 struct spoolss_EnumPrinters r;
4217 NTSTATUS status;
4218 uint16_t levels[] = {1, 2, 4, 5};
4219 int i;
4220 bool ret = true;
4222 for (i=0;i<ARRAY_SIZE(levels);i++) {
4223 union spoolss_PrinterInfo *info;
4224 int j;
4225 uint32_t needed;
4226 uint32_t count;
4228 r.in.flags = PRINTER_ENUM_LOCAL;
4229 r.in.server = "";
4230 r.in.level = levels[i];
4231 r.in.buffer = NULL;
4232 r.in.offered = 0;
4233 r.out.needed = &needed;
4234 r.out.count = &count;
4235 r.out.info = &info;
4237 torture_comment(tctx, "Testing EnumPrinters level %u\n", r.in.level);
4239 status = dcerpc_spoolss_EnumPrinters(p, tctx, &r);
4240 torture_assert_ntstatus_ok(tctx, status, "EnumPrinters failed");
4242 if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
4243 DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed);
4244 data_blob_clear(&blob);
4245 r.in.buffer = &blob;
4246 r.in.offered = needed;
4247 status = dcerpc_spoolss_EnumPrinters(p, tctx, &r);
4250 torture_assert_ntstatus_ok(tctx, status, "EnumPrinters failed");
4252 torture_assert_werr_ok(tctx, r.out.result, "EnumPrinters failed");
4254 CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumPrinters, info, r.in.level, count, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
4256 if (!info) {
4257 torture_comment(tctx, "No printers returned\n");
4258 return true;
4261 for (j=0;j<count;j++) {
4262 if (r.in.level == 1) {
4263 char *unc = talloc_strdup(tctx, info[j].info1.name);
4264 char *slash, *name;
4265 name = unc;
4266 if (unc[0] == '\\' && unc[1] == '\\') {
4267 unc +=2;
4269 slash = strchr(unc, '\\');
4270 if (slash) {
4271 slash++;
4272 name = slash;
4274 if (!test_OpenPrinter(tctx, p, name, environment)) {
4275 ret = false;
4277 if (!test_OpenPrinterEx(tctx, p, name, environment)) {
4278 ret = false;
4284 return ret;
4287 static bool test_GetPrinterDriver(struct torture_context *tctx,
4288 struct dcerpc_pipe *p,
4289 struct policy_handle *handle,
4290 const char *driver_name)
4292 struct spoolss_GetPrinterDriver r;
4293 uint32_t needed;
4295 r.in.handle = handle;
4296 r.in.architecture = "W32X86";
4297 r.in.level = 1;
4298 r.in.buffer = NULL;
4299 r.in.offered = 0;
4300 r.out.needed = &needed;
4302 torture_comment(tctx, "Testing GetPrinterDriver level %d\n", r.in.level);
4304 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_GetPrinterDriver(p, tctx, &r),
4305 "failed to call GetPrinterDriver");
4306 if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
4307 DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed);
4308 data_blob_clear(&blob);
4309 r.in.buffer = &blob;
4310 r.in.offered = needed;
4311 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_GetPrinterDriver(p, tctx, &r),
4312 "failed to call GetPrinterDriver");
4315 torture_assert_werr_ok(tctx, r.out.result,
4316 "failed to call GetPrinterDriver");
4318 CHECK_NEEDED_SIZE_LEVEL(spoolss_DriverInfo, r.out.info, r.in.level, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
4320 return true;
4323 static bool test_GetPrinterDriver2(struct torture_context *tctx,
4324 struct dcerpc_pipe *p,
4325 struct policy_handle *handle,
4326 const char *driver_name,
4327 const char *architecture)
4329 struct spoolss_GetPrinterDriver2 r;
4330 uint16_t levels[] = {1, 2, 3, 4, 5, 6, 8, 101 };
4331 uint32_t needed;
4332 uint32_t server_major_version;
4333 uint32_t server_minor_version;
4334 int i;
4336 r.in.handle = handle;
4337 r.in.architecture = architecture;
4338 r.in.client_major_version = 3;
4339 r.in.client_minor_version = 0;
4340 r.out.needed = &needed;
4341 r.out.server_major_version = &server_major_version;
4342 r.out.server_minor_version = &server_minor_version;
4344 for (i=0;i<ARRAY_SIZE(levels);i++) {
4346 r.in.buffer = NULL;
4347 r.in.offered = 0;
4348 r.in.level = levels[i];
4350 torture_comment(tctx, "Testing GetPrinterDriver2(%s) level %d\n",
4351 driver_name, r.in.level);
4353 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_GetPrinterDriver2(p, tctx, &r),
4354 "failed to call GetPrinterDriver2");
4355 if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
4356 DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed);
4357 data_blob_clear(&blob);
4358 r.in.buffer = &blob;
4359 r.in.offered = needed;
4360 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_GetPrinterDriver2(p, tctx, &r),
4361 "failed to call GetPrinterDriver2");
4364 if (W_ERROR_EQUAL(r.out.result, WERR_INVALID_LEVEL)) {
4365 switch (r.in.level) {
4366 case 101:
4367 case 8:
4368 continue;
4369 default:
4370 break;
4374 torture_assert_werr_ok(tctx, r.out.result,
4375 "failed to call GetPrinterDriver2");
4377 CHECK_NEEDED_SIZE_LEVEL(spoolss_DriverInfo, r.out.info, r.in.level, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
4380 return true;
4383 static bool test_EnumPrinterDrivers_old(struct torture_context *tctx,
4384 struct dcerpc_pipe *p,
4385 const char *environment)
4387 struct spoolss_EnumPrinterDrivers r;
4388 NTSTATUS status;
4389 uint16_t levels[] = {1, 2, 3, 4, 5, 6};
4390 int i;
4392 for (i=0;i<ARRAY_SIZE(levels);i++) {
4394 uint32_t needed;
4395 uint32_t count;
4396 union spoolss_DriverInfo *info;
4398 r.in.server = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
4399 r.in.environment = environment;
4400 r.in.level = levels[i];
4401 r.in.buffer = NULL;
4402 r.in.offered = 0;
4403 r.out.needed = &needed;
4404 r.out.count = &count;
4405 r.out.info = &info;
4407 torture_comment(tctx, "Testing EnumPrinterDrivers level %u\n", r.in.level);
4409 status = dcerpc_spoolss_EnumPrinterDrivers(p, tctx, &r);
4411 torture_assert_ntstatus_ok(tctx, status, "EnumPrinterDrivers failed");
4413 if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
4414 DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed);
4415 data_blob_clear(&blob);
4416 r.in.buffer = &blob;
4417 r.in.offered = needed;
4418 status = dcerpc_spoolss_EnumPrinterDrivers(p, tctx, &r);
4421 torture_assert_ntstatus_ok(tctx, status, "EnumPrinterDrivers failed");
4423 torture_assert_werr_ok(tctx, r.out.result, "EnumPrinterDrivers failed");
4425 if (!info) {
4426 torture_comment(tctx, "No printer drivers returned\n");
4427 break;
4430 CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumPrinterDrivers, info, r.in.level, count, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
4433 return true;
4436 static bool test_DeletePrinter(struct torture_context *tctx,
4437 struct dcerpc_pipe *p,
4438 struct policy_handle *handle)
4440 struct spoolss_DeletePrinter r;
4442 torture_comment(tctx, "Testing DeletePrinter\n");
4444 r.in.handle = handle;
4446 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_DeletePrinter(p, tctx, &r),
4447 "failed to delete printer");
4448 torture_assert_werr_ok(tctx, r.out.result,
4449 "failed to delete printer");
4451 return true;
4454 static bool test_EnumPrinters_findname(struct torture_context *tctx,
4455 struct dcerpc_pipe *p,
4456 uint32_t flags,
4457 uint32_t level,
4458 const char *name,
4459 bool *found)
4461 struct spoolss_EnumPrinters e;
4462 uint32_t count;
4463 union spoolss_PrinterInfo *info;
4464 uint32_t needed;
4465 int i;
4467 *found = false;
4469 e.in.flags = flags;
4470 e.in.server = NULL;
4471 e.in.level = level;
4472 e.in.buffer = NULL;
4473 e.in.offered = 0;
4474 e.out.count = &count;
4475 e.out.info = &info;
4476 e.out.needed = &needed;
4478 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_EnumPrinters(p, tctx, &e),
4479 "failed to enum printers");
4481 if (W_ERROR_EQUAL(e.out.result, WERR_INSUFFICIENT_BUFFER)) {
4482 DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed);
4483 data_blob_clear(&blob);
4484 e.in.buffer = &blob;
4485 e.in.offered = needed;
4487 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_EnumPrinters(p, tctx, &e),
4488 "failed to enum printers");
4491 torture_assert_werr_ok(tctx, e.out.result,
4492 "failed to enum printers");
4494 for (i=0; i < count; i++) {
4496 const char *current = NULL;
4497 const char *q;
4499 switch (level) {
4500 case 1:
4501 current = info[i].info1.name;
4502 break;
4505 if (strequal(current, name)) {
4506 *found = true;
4507 break;
4510 q = strrchr(current, '\\');
4511 if (q) {
4512 if (!e.in.server) {
4513 torture_warning(tctx,
4514 "server returns printername %s incl. servername although we did not set servername", current);
4516 q++;
4517 if (strequal(q, name)) {
4518 *found = true;
4519 break;
4524 return true;
4527 static bool test_AddPrinter_wellknown(struct torture_context *tctx,
4528 struct dcerpc_pipe *p,
4529 const char *printername,
4530 bool ex)
4532 WERROR result;
4533 struct spoolss_AddPrinter r;
4534 struct spoolss_AddPrinterEx rex;
4535 struct spoolss_SetPrinterInfoCtr info_ctr;
4536 struct spoolss_SetPrinterInfo1 info1;
4537 struct spoolss_DevmodeContainer devmode_ctr;
4538 struct sec_desc_buf secdesc_ctr;
4539 struct spoolss_UserLevelCtr userlevel_ctr;
4540 struct policy_handle handle;
4541 bool found = false;
4543 ZERO_STRUCT(devmode_ctr);
4544 ZERO_STRUCT(secdesc_ctr);
4545 ZERO_STRUCT(userlevel_ctr);
4546 ZERO_STRUCT(info1);
4548 torture_comment(tctx, "Testing AddPrinter%s level 1\n", ex ? "Ex":"");
4550 /* try to add printer to wellknown printer list (level 1) */
4552 userlevel_ctr.level = 1;
4554 info_ctr.info.info1 = &info1;
4555 info_ctr.level = 1;
4557 rex.in.server = NULL;
4558 rex.in.info_ctr = &info_ctr;
4559 rex.in.devmode_ctr = &devmode_ctr;
4560 rex.in.secdesc_ctr = &secdesc_ctr;
4561 rex.in.userlevel_ctr = &userlevel_ctr;
4562 rex.out.handle = &handle;
4564 r.in.server = NULL;
4565 r.in.info_ctr = &info_ctr;
4566 r.in.devmode_ctr = &devmode_ctr;
4567 r.in.secdesc_ctr = &secdesc_ctr;
4568 r.out.handle = &handle;
4570 torture_assert_ntstatus_ok(tctx, ex ? dcerpc_spoolss_AddPrinterEx(p, tctx, &rex) :
4571 dcerpc_spoolss_AddPrinter(p, tctx, &r),
4572 "failed to add printer");
4573 result = ex ? rex.out.result : r.out.result;
4574 torture_assert_werr_equal(tctx, result, WERR_INVALID_PRINTER_NAME,
4575 "unexpected result code");
4577 info1.name = printername;
4578 info1.flags = PRINTER_ATTRIBUTE_SHARED;
4580 torture_assert_ntstatus_ok(tctx, ex ? dcerpc_spoolss_AddPrinterEx(p, tctx, &rex) :
4581 dcerpc_spoolss_AddPrinter(p, tctx, &r),
4582 "failed to add printer");
4583 result = ex ? rex.out.result : r.out.result;
4584 torture_assert_werr_equal(tctx, result, WERR_PRINTER_ALREADY_EXISTS,
4585 "unexpected result code");
4587 /* bizarre protocol, WERR_PRINTER_ALREADY_EXISTS means success here,
4588 better do a real check to see the printer is really there */
4590 torture_assert(tctx, test_EnumPrinters_findname(tctx, p,
4591 PRINTER_ENUM_NETWORK, 1,
4592 printername,
4593 &found),
4594 "failed to enum printers");
4596 torture_assert(tctx, found, "failed to find newly added printer");
4598 info1.flags = 0;
4600 torture_assert_ntstatus_ok(tctx, ex ? dcerpc_spoolss_AddPrinterEx(p, tctx, &rex) :
4601 dcerpc_spoolss_AddPrinter(p, tctx, &r),
4602 "failed to add printer");
4603 result = ex ? rex.out.result : r.out.result;
4604 torture_assert_werr_equal(tctx, result, WERR_PRINTER_ALREADY_EXISTS,
4605 "unexpected result code");
4607 /* bizarre protocol, WERR_PRINTER_ALREADY_EXISTS means success here,
4608 better do a real check to see the printer has really been removed
4609 from the well known printer list */
4611 found = false;
4613 torture_assert(tctx, test_EnumPrinters_findname(tctx, p,
4614 PRINTER_ENUM_NETWORK, 1,
4615 printername,
4616 &found),
4617 "failed to enum printers");
4618 #if 0
4619 torture_assert(tctx, !found, "printer still in well known printer list");
4620 #endif
4621 return true;
4624 static bool test_AddPrinter_normal(struct torture_context *tctx,
4625 struct dcerpc_pipe *p,
4626 struct policy_handle *handle_p,
4627 const char *printername,
4628 const char *drivername,
4629 const char *portname,
4630 bool ex)
4632 WERROR result;
4633 struct spoolss_AddPrinter r;
4634 struct spoolss_AddPrinterEx rex;
4635 struct spoolss_SetPrinterInfoCtr info_ctr;
4636 struct spoolss_SetPrinterInfo2 info2;
4637 struct spoolss_DevmodeContainer devmode_ctr;
4638 struct sec_desc_buf secdesc_ctr;
4639 struct spoolss_UserLevelCtr userlevel_ctr;
4640 struct policy_handle handle;
4641 bool found = false;
4642 bool existing_printer_deleted = false;
4644 ZERO_STRUCT(devmode_ctr);
4645 ZERO_STRUCT(secdesc_ctr);
4646 ZERO_STRUCT(userlevel_ctr);
4648 torture_comment(tctx, "Testing AddPrinter%s level 2\n", ex ? "Ex":"");
4650 userlevel_ctr.level = 1;
4652 rex.in.server = NULL;
4653 rex.in.info_ctr = &info_ctr;
4654 rex.in.devmode_ctr = &devmode_ctr;
4655 rex.in.secdesc_ctr = &secdesc_ctr;
4656 rex.in.userlevel_ctr = &userlevel_ctr;
4657 rex.out.handle = &handle;
4659 r.in.server = NULL;
4660 r.in.info_ctr = &info_ctr;
4661 r.in.devmode_ctr = &devmode_ctr;
4662 r.in.secdesc_ctr = &secdesc_ctr;
4663 r.out.handle = &handle;
4665 again:
4667 /* try to add printer to printer list (level 2) */
4669 ZERO_STRUCT(info2);
4671 info_ctr.info.info2 = &info2;
4672 info_ctr.level = 2;
4674 torture_assert_ntstatus_ok(tctx, ex ? dcerpc_spoolss_AddPrinterEx(p, tctx, &rex) :
4675 dcerpc_spoolss_AddPrinter(p, tctx, &r),
4676 "failed to add printer");
4677 result = ex ? rex.out.result : r.out.result;
4678 torture_assert_werr_equal(tctx, result, WERR_INVALID_PRINTER_NAME,
4679 "unexpected result code");
4681 info2.printername = printername;
4683 torture_assert_ntstatus_ok(tctx, ex ? dcerpc_spoolss_AddPrinterEx(p, tctx, &rex) :
4684 dcerpc_spoolss_AddPrinter(p, tctx, &r),
4685 "failed to add printer");
4686 result = ex ? rex.out.result : r.out.result;
4688 if (W_ERROR_EQUAL(result, WERR_PRINTER_ALREADY_EXISTS)) {
4689 struct policy_handle printer_handle;
4691 if (existing_printer_deleted) {
4692 torture_fail(tctx, "already deleted printer still existing?");
4695 torture_assert(tctx, call_OpenPrinterEx(tctx, p, printername, NULL, &printer_handle),
4696 "failed to open printer handle");
4698 torture_assert(tctx, test_DeletePrinter(tctx, p, &printer_handle),
4699 "failed to delete printer");
4701 torture_assert(tctx, test_ClosePrinter(tctx, p, &printer_handle),
4702 "failed to close server handle");
4704 existing_printer_deleted = true;
4706 goto again;
4709 torture_assert_werr_equal(tctx, result, WERR_UNKNOWN_PORT,
4710 "unexpected result code");
4712 info2.portname = portname;
4714 torture_assert_ntstatus_ok(tctx, ex ? dcerpc_spoolss_AddPrinterEx(p, tctx, &rex) :
4715 dcerpc_spoolss_AddPrinter(p, tctx, &r),
4716 "failed to add printer");
4717 result = ex ? rex.out.result : r.out.result;
4718 torture_assert_werr_equal(tctx, result, WERR_UNKNOWN_PRINTER_DRIVER,
4719 "unexpected result code");
4721 info2.drivername = drivername;
4723 torture_assert_ntstatus_ok(tctx, ex ? dcerpc_spoolss_AddPrinterEx(p, tctx, &rex) :
4724 dcerpc_spoolss_AddPrinter(p, tctx, &r),
4725 "failed to add printer");
4726 result = ex ? rex.out.result : r.out.result;
4728 /* w2k8r2 allows to add printer w/o defining printprocessor */
4730 if (!W_ERROR_IS_OK(result)) {
4731 torture_assert_werr_equal(tctx, result, WERR_UNKNOWN_PRINTPROCESSOR,
4732 "unexpected result code");
4734 info2.printprocessor = "winprint";
4736 torture_assert_ntstatus_ok(tctx, ex ? dcerpc_spoolss_AddPrinterEx(p, tctx, &rex) :
4737 dcerpc_spoolss_AddPrinter(p, tctx, &r),
4738 "failed to add printer");
4739 result = ex ? rex.out.result : r.out.result;
4740 torture_assert_werr_ok(tctx, result,
4741 "failed to add printer");
4744 *handle_p = handle;
4746 /* we are paranoid, really check if the printer is there now */
4748 torture_assert(tctx, test_EnumPrinters_findname(tctx, p,
4749 PRINTER_ENUM_LOCAL, 1,
4750 printername,
4751 &found),
4752 "failed to enum printers");
4753 torture_assert(tctx, found, "failed to find newly added printer");
4755 torture_assert_ntstatus_ok(tctx, ex ? dcerpc_spoolss_AddPrinterEx(p, tctx, &rex) :
4756 dcerpc_spoolss_AddPrinter(p, tctx, &r),
4757 "failed to add printer");
4758 result = ex ? rex.out.result : r.out.result;
4759 torture_assert_werr_equal(tctx, result, WERR_PRINTER_ALREADY_EXISTS,
4760 "unexpected result code");
4762 return true;
4765 static bool test_AddPrinterEx(struct torture_context *tctx,
4766 struct dcerpc_pipe *p,
4767 struct policy_handle *handle_p,
4768 const char *printername,
4769 const char *drivername,
4770 const char *portname)
4772 bool ret = true;
4774 if (!torture_setting_bool(tctx, "samba3", false)) {
4775 if (!test_AddPrinter_wellknown(tctx, p, TORTURE_WELLKNOWN_PRINTER_EX, true)) {
4776 torture_comment(tctx, "failed to add printer to well known list\n");
4777 ret = false;
4781 if (!test_AddPrinter_normal(tctx, p, handle_p,
4782 printername, drivername, portname,
4783 true)) {
4784 torture_comment(tctx, "failed to add printer to printer list\n");
4785 ret = false;
4788 return ret;
4791 static bool test_AddPrinter(struct torture_context *tctx,
4792 struct dcerpc_pipe *p,
4793 struct policy_handle *handle_p,
4794 const char *printername,
4795 const char *drivername,
4796 const char *portname)
4798 bool ret = true;
4800 if (!torture_setting_bool(tctx, "samba3", false)) {
4801 if (!test_AddPrinter_wellknown(tctx, p, TORTURE_WELLKNOWN_PRINTER, false)) {
4802 torture_comment(tctx, "failed to add printer to well known list\n");
4803 ret = false;
4807 if (!test_AddPrinter_normal(tctx, p, handle_p,
4808 printername, drivername, portname,
4809 false)) {
4810 torture_comment(tctx, "failed to add printer to printer list\n");
4811 ret = false;
4814 return ret;
4817 static bool test_printer_info(struct torture_context *tctx,
4818 struct dcerpc_pipe *p,
4819 struct policy_handle *handle)
4821 bool ret = true;
4823 if (torture_setting_bool(tctx, "samba3", false)) {
4824 torture_skip(tctx, "skipping printer info cross tests against samba 3");
4827 if (!test_PrinterInfo(tctx, p, handle)) {
4828 ret = false;
4831 if (!test_SetPrinter_errors(tctx, p, handle)) {
4832 ret = false;
4835 return ret;
4838 static bool test_EnumPrinterKey(struct torture_context *tctx,
4839 struct dcerpc_pipe *p,
4840 struct policy_handle *handle,
4841 const char *key_name,
4842 const char ***array)
4844 struct spoolss_EnumPrinterKey r;
4845 uint32_t needed = 0;
4846 union spoolss_KeyNames key_buffer;
4847 int32_t offered[] = { 0, 1, 2, 3, 4, 5, -1, -2, -3, -4, -5, 256, 512, 1024, 2048 };
4848 uint32_t _ndr_size;
4849 int i;
4851 r.in.handle = handle;
4852 r.in.key_name = key_name;
4853 r.out.key_buffer = &key_buffer;
4854 r.out.needed = &needed;
4855 r.out._ndr_size = &_ndr_size;
4857 for (i=0; i < ARRAY_SIZE(offered); i++) {
4859 if (offered[i] < 0 && needed) {
4860 if (needed <= 4) {
4861 continue;
4863 r.in.offered = needed + offered[i];
4864 } else {
4865 r.in.offered = offered[i];
4868 ZERO_STRUCT(key_buffer);
4870 torture_comment(tctx, "Testing EnumPrinterKey(%s) with %d offered\n", r.in.key_name, r.in.offered);
4872 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_EnumPrinterKey(p, tctx, &r),
4873 "failed to call EnumPrinterKey");
4874 if (W_ERROR_EQUAL(r.out.result, WERR_MORE_DATA)) {
4876 torture_assert(tctx, (_ndr_size == r.in.offered/2),
4877 talloc_asprintf(tctx, "EnumPrinterKey size mismatch, _ndr_size %d (expected %d)",
4878 _ndr_size, r.in.offered/2));
4880 r.in.offered = needed;
4881 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_EnumPrinterKey(p, tctx, &r),
4882 "failed to call EnumPrinterKey");
4885 if (offered[i] > 0) {
4886 torture_assert_werr_ok(tctx, r.out.result,
4887 "failed to call EnumPrinterKey");
4890 torture_assert(tctx, (_ndr_size == r.in.offered/2),
4891 talloc_asprintf(tctx, "EnumPrinterKey size mismatch, _ndr_size %d (expected %d)",
4892 _ndr_size, r.in.offered/2));
4894 torture_assert(tctx, (*r.out.needed <= r.in.offered),
4895 talloc_asprintf(tctx, "EnumPrinterKey size mismatch: needed %d is not <= offered %d", *r.out.needed, r.in.offered));
4897 torture_assert(tctx, (*r.out.needed <= _ndr_size * 2),
4898 talloc_asprintf(tctx, "EnumPrinterKey size mismatch: needed %d is not <= _ndr_size %d * 2", *r.out.needed, _ndr_size));
4900 if (key_buffer.string_array) {
4901 uint32_t calc_needed = 0;
4902 int s;
4903 for (s=0; key_buffer.string_array[s]; s++) {
4904 calc_needed += strlen_m_term(key_buffer.string_array[s])*2;
4906 if (!key_buffer.string_array[0]) {
4907 calc_needed += 2;
4909 calc_needed += 2;
4911 torture_assert_int_equal(tctx, *r.out.needed, calc_needed,
4912 "EnumPrinterKey unexpected size");
4916 if (array) {
4917 *array = key_buffer.string_array;
4920 return true;
4923 bool test_printer_keys(struct torture_context *tctx,
4924 struct dcerpc_pipe *p,
4925 struct policy_handle *handle)
4927 const char **key_array = NULL;
4928 int i;
4930 torture_comment(tctx, "\nTesting Printer Keys\n");
4932 torture_assert(tctx, test_EnumPrinterKey(tctx, p, handle, "", &key_array),
4933 "failed to call test_EnumPrinterKey");
4935 for (i=0; key_array && key_array[i]; i++) {
4936 torture_assert(tctx, test_EnumPrinterKey(tctx, p, handle, key_array[i], NULL),
4937 "failed to call test_EnumPrinterKey");
4939 for (i=0; key_array && key_array[i]; i++) {
4940 torture_assert(tctx, test_EnumPrinterDataEx(tctx, p, handle, key_array[i], NULL, NULL),
4941 "failed to call test_EnumPrinterDataEx");
4944 return true;
4947 static bool test_one_printer(struct torture_context *tctx,
4948 struct dcerpc_pipe *p,
4949 struct policy_handle *handle,
4950 const char *name)
4952 bool ret = true;
4954 if (!test_printer_info(tctx, p, handle)) {
4955 ret = false;
4958 if (!test_PrinterInfo_SD(tctx, p, handle)) {
4959 ret = false;
4962 if (!test_PrinterInfo_DevMode(tctx, p, handle, name)) {
4963 ret = false;
4966 if (!test_ChangeID(tctx, p, handle)) {
4967 ret = false;
4970 if (!test_printer_keys(tctx, p, handle)) {
4971 ret = false;
4974 if (!test_EnumPrinterData_consistency(tctx, p, handle)) {
4975 ret = false;
4978 if (!test_SetPrinterDataEx_matrix(tctx, p, handle, name, NULL, NULL)) {
4979 ret = false;
4982 if (!test_PrinterData_winreg(tctx, p, handle, name)) {
4983 ret = false;
4986 return ret;
4989 static bool test_printer(struct torture_context *tctx,
4990 struct dcerpc_pipe *p)
4992 bool ret = true;
4993 struct policy_handle handle[2];
4994 bool found = false;
4995 const char *drivername = "Microsoft XPS Document Writer";
4996 const char *portname = "LPT1:";
4998 /* test printer created via AddPrinter */
5000 if (!test_AddPrinter(tctx, p, &handle[0], TORTURE_PRINTER, drivername, portname)) {
5001 return false;
5004 if (!test_one_printer(tctx, p, &handle[0], TORTURE_PRINTER)) {
5005 ret = false;
5008 if (!test_DeletePrinter(tctx, p, &handle[0])) {
5009 ret = false;
5012 if (!test_EnumPrinters_findname(tctx, p, PRINTER_ENUM_LOCAL, 1,
5013 TORTURE_PRINTER, &found)) {
5014 ret = false;
5017 torture_assert(tctx, !found, "deleted printer still there");
5019 /* test printer created via AddPrinterEx */
5021 if (!test_AddPrinterEx(tctx, p, &handle[1], TORTURE_PRINTER_EX, drivername, portname)) {
5022 return false;
5025 if (!test_one_printer(tctx, p, &handle[1], TORTURE_PRINTER_EX)) {
5026 ret = false;
5029 if (!test_DeletePrinter(tctx, p, &handle[1])) {
5030 ret = false;
5033 if (!test_EnumPrinters_findname(tctx, p, PRINTER_ENUM_LOCAL, 1,
5034 TORTURE_PRINTER_EX, &found)) {
5035 ret = false;
5038 torture_assert(tctx, !found, "deleted printer still there");
5040 return ret;
5043 static bool test_architecture_buffer(struct torture_context *tctx,
5044 struct dcerpc_pipe *p)
5046 struct spoolss_OpenPrinterEx r;
5047 struct spoolss_UserLevel1 u1;
5048 struct policy_handle handle;
5049 uint32_t architectures[] = {
5050 PROCESSOR_ARCHITECTURE_INTEL,
5051 PROCESSOR_ARCHITECTURE_IA64,
5052 PROCESSOR_ARCHITECTURE_AMD64
5054 uint32_t needed[3];
5055 int i;
5057 for (i=0; i < ARRAY_SIZE(architectures); i++) {
5059 torture_comment(tctx, "Testing OpenPrinterEx with architecture %d\n", architectures[i]);
5061 u1.size = 0;
5062 u1.client = NULL;
5063 u1.user = NULL;
5064 u1.build = 0;
5065 u1.major = 3;
5066 u1.minor = 0;
5067 u1.processor = architectures[i];
5069 r.in.printername = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
5070 r.in.datatype = NULL;
5071 r.in.devmode_ctr.devmode= NULL;
5072 r.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
5073 r.in.level = 1;
5074 r.in.userlevel.level1 = &u1;
5075 r.out.handle = &handle;
5077 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_OpenPrinterEx(p, tctx, &r), "");
5078 torture_assert_werr_ok(tctx, r.out.result, "");
5081 struct spoolss_EnumPrinters e;
5082 uint32_t count;
5083 union spoolss_PrinterInfo *info;
5085 e.in.flags = PRINTER_ENUM_LOCAL;
5086 e.in.server = NULL;
5087 e.in.level = 2;
5088 e.in.buffer = NULL;
5089 e.in.offered = 0;
5090 e.out.count = &count;
5091 e.out.info = &info;
5092 e.out.needed = &needed[i];
5094 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_EnumPrinters(p, tctx, &e), "");
5095 #if 0
5096 torture_comment(tctx, "needed was %d\n", needed[i]);
5097 #endif
5100 torture_assert(tctx, test_ClosePrinter(tctx, p, &handle), "");
5103 for (i=1; i < ARRAY_SIZE(architectures); i++) {
5104 if (needed[i-1] != needed[i]) {
5105 torture_fail(tctx,
5106 talloc_asprintf(tctx, "needed size %d for architecture %d != needed size %d for architecture %d\n",
5107 needed[i-1], architectures[i-1], needed[i], architectures[i]));
5111 return true;
5114 bool torture_rpc_spoolss(struct torture_context *torture)
5116 NTSTATUS status;
5117 struct dcerpc_pipe *p;
5118 bool ret = true;
5119 struct test_spoolss_context *ctx;
5120 const char *environment = SPOOLSS_ARCHITECTURE_NT_X86;
5122 status = torture_rpc_connection(torture, &p, &ndr_table_spoolss);
5123 if (!NT_STATUS_IS_OK(status)) {
5124 return false;
5127 ctx = talloc_zero(torture, struct test_spoolss_context);
5129 ret &= test_OpenPrinter_server(torture, p, &ctx->server_handle);
5130 ret &= test_GetPrinterData_list(torture, p, &ctx->server_handle, &environment);
5131 ret &= test_EnumForms(torture, p, &ctx->server_handle, true);
5132 ret &= test_AddForm(torture, p, &ctx->server_handle, true);
5133 ret &= test_EnumPorts(torture, p, ctx);
5134 ret &= test_GetPrinterDriverDirectory(torture, p, ctx, environment);
5135 ret &= test_GetPrintProcessorDirectory(torture, p, ctx, environment);
5136 ret &= test_EnumPrinterDrivers(torture, p, ctx, environment);
5137 ret &= test_EnumPrinterDrivers(torture, p, ctx, SPOOLSS_ARCHITECTURE_ALL);
5138 ret &= test_EnumMonitors(torture, p, ctx);
5139 ret &= test_EnumPrintProcessors(torture, p, ctx, environment);
5140 ret &= test_EnumPrintProcDataTypes(torture, p, ctx);
5141 ret &= test_EnumPrinters(torture, p, ctx);
5142 ret &= test_OpenPrinter_badname(torture, p, "__INVALID_PRINTER__");
5143 ret &= test_OpenPrinter_badname(torture, p, "\\\\__INVALID_HOST__");
5144 ret &= test_OpenPrinter_badname(torture, p, "");
5145 ret &= test_OpenPrinter_badname(torture, p, "\\\\\\");
5146 ret &= test_OpenPrinter_badname(torture, p, "\\\\\\__INVALID_PRINTER__");
5147 ret &= test_OpenPrinter_badname(torture, p, talloc_asprintf(torture, "\\\\%s\\", dcerpc_server_name(p)));
5148 ret &= test_OpenPrinter_badname(torture, p,
5149 talloc_asprintf(torture, "\\\\%s\\__INVALID_PRINTER__", dcerpc_server_name(p)));
5152 ret &= test_AddPort(torture, p);
5153 ret &= test_EnumPorts_old(torture, p);
5154 ret &= test_EnumPrinters_old(torture, p, environment);
5155 ret &= test_EnumPrinterDrivers_old(torture, p, environment);
5156 ret &= test_architecture_buffer(torture, p);
5158 return ret;
5161 struct torture_suite *torture_rpc_spoolss_printer(TALLOC_CTX *mem_ctx)
5163 struct torture_suite *suite = torture_suite_create(mem_ctx, "SPOOLSS-PRINTER");
5165 struct torture_rpc_tcase *tcase = torture_suite_add_rpc_iface_tcase(suite,
5166 "printer", &ndr_table_spoolss);
5168 torture_rpc_tcase_add_test(tcase, "printer", test_printer);
5170 return suite;