s4-smbtorture: fix smbtorture after setprinter IDL fixes.
[Samba/bb.git] / source4 / torture / rpc / spoolss.c
blob65bc3619caf96ca3342da18daf3e448f8561ddb9
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
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 "torture/rpc/rpc.h"
27 #include "librpc/gen_ndr/ndr_misc.h"
28 #include "librpc/gen_ndr/ndr_spoolss.h"
29 #include "librpc/gen_ndr/ndr_spoolss_c.h"
30 #include "param/param.h"
32 #define TORTURE_WELLKNOWN_PRINTER "torture_wkn_printer"
33 #define TORTURE_PRINTER "torture_printer"
34 #define TORTURE_WELLKNOWN_PRINTER_EX "torture_wkn_printer_ex"
35 #define TORTURE_PRINTER_EX "torture_printer_ex"
37 struct test_spoolss_context {
38 /* print server handle */
39 struct policy_handle server_handle;
41 /* for EnumPorts */
42 uint32_t port_count[3];
43 union spoolss_PortInfo *ports[3];
45 /* for EnumPrinterDrivers */
46 uint32_t driver_count[8];
47 union spoolss_DriverInfo *drivers[8];
49 /* for EnumMonitors */
50 uint32_t monitor_count[3];
51 union spoolss_MonitorInfo *monitors[3];
53 /* for EnumPrintProcessors */
54 uint32_t print_processor_count[2];
55 union spoolss_PrintProcessorInfo *print_processors[2];
57 /* for EnumPrinters */
58 uint32_t printer_count[6];
59 union spoolss_PrinterInfo *printers[6];
62 #define COMPARE_STRING(tctx, c,r,e) \
63 torture_assert_str_equal(tctx, c.e, r.e, "invalid value")
65 /* not every compiler supports __typeof__() */
66 #if (__GNUC__ >= 3)
67 #define _CHECK_FIELD_SIZE(c,r,e,type) do {\
68 if (sizeof(__typeof__(c.e)) != sizeof(type)) { \
69 torture_fail(tctx, #c "." #e "field is not " #type "\n"); \
71 if (sizeof(__typeof__(r.e)) != sizeof(type)) { \
72 torture_fail(tctx, #r "." #e "field is not " #type "\n"); \
74 } while(0)
75 #else
76 #define _CHECK_FIELD_SIZE(c,r,e,type) do {} while(0)
77 #endif
79 #define COMPARE_UINT32(tctx, c, r, e) do {\
80 _CHECK_FIELD_SIZE(c, r, e, uint32_t); \
81 torture_assert_int_equal(tctx, c.e, r.e, "invalid value"); \
82 } while(0)
84 #define COMPARE_UINT64(tctx, c, r, e) do {\
85 _CHECK_FIELD_SIZE(c, r, e, uint64_t); \
86 torture_assert_int_equal(tctx, c.e, r.e, "invalid value"); \
87 } while(0)
90 #define COMPARE_NTTIME(tctx, c, r, e) do {\
91 _CHECK_FIELD_SIZE(c, r, e, NTTIME); \
92 torture_assert_int_equal(tctx, c.e, r.e, "invalid value"); \
93 } while(0)
95 #define COMPARE_STRING_ARRAY(tctx, c,r,e) do {\
96 int __i; \
97 if (!c.e && !r.e) { \
98 break; \
99 } \
100 if (c.e && !r.e) { \
101 torture_fail(tctx, #r "." #e " field is NULL and " #c "." #e " is not\n"); \
103 if (!c.e && r.e) { \
104 torture_fail(tctx, #c "." #e " field is NULL and " #r "." #e " is not\n"); \
106 for (__i=0;c.e[__i] != NULL; __i++) { \
107 torture_assert_str_equal(tctx, c.e[__i], r.e[__i], "invalid value"); \
109 } while(0)
111 #define CHECK_ALIGN(size, n) do {\
112 if (size % n) {\
113 torture_warning(tctx, "%d is *NOT* %d byte aligned, should be %d",\
114 size, n, size + n - (size % n));\
116 } while(0)
118 #define DO_ROUND(size, n) (((size)+((n)-1)) & ~((n)-1))
120 #define CHECK_NEEDED_SIZE_ENUM_LEVEL(fn, info, level, count, ic, needed, align) do { \
121 uint32_t size = ndr_size_##fn##_info(tctx, ic, level, count, info);\
122 uint32_t round_size = DO_ROUND(size, align);\
123 if (round_size != needed) {\
124 torture_warning(tctx, __location__": "#fn" level %d (count: %d) got unexpected needed size: %d, we calculated: %d", level, count, needed, round_size);\
125 CHECK_ALIGN(size, align);\
127 } while(0)
129 #define CHECK_NEEDED_SIZE_ENUM(fn, info, count, ic, needed, align) do { \
130 uint32_t size = ndr_size_##fn##_info(tctx, ic, count, info);\
131 uint32_t round_size = DO_ROUND(size, align);\
132 if (round_size != needed) {\
133 torture_warning(tctx, __location__": "#fn" (count: %d) got unexpected needed size: %d, we calculated: %d", count, needed, round_size);\
134 CHECK_ALIGN(size, align);\
136 } while(0)
138 #define CHECK_NEEDED_SIZE_LEVEL(fn, info, level, ic, needed, align) do { \
139 uint32_t size = ndr_size_##fn(info, level, ic, 0);\
140 uint32_t round_size = DO_ROUND(size, align);\
141 if (round_size != needed) {\
142 torture_warning(tctx, __location__": "#fn" level %d got unexpected needed size: %d, we calculated: %d", level, needed, round_size);\
143 CHECK_ALIGN(size, align);\
145 } while(0)
147 static bool test_OpenPrinter_server(struct torture_context *tctx,
148 struct dcerpc_pipe *p,
149 struct policy_handle *server_handle)
151 NTSTATUS status;
152 struct spoolss_OpenPrinter op;
154 op.in.printername = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
155 op.in.datatype = NULL;
156 op.in.devmode_ctr.devmode= NULL;
157 op.in.access_mask = 0;
158 op.out.handle = server_handle;
160 torture_comment(tctx, "Testing OpenPrinter(%s)\n", op.in.printername);
162 status = dcerpc_spoolss_OpenPrinter(p, tctx, &op);
163 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_OpenPrinter failed");
164 torture_assert_werr_ok(tctx, op.out.result, "dcerpc_spoolss_OpenPrinter failed");
166 return true;
169 static bool test_EnumPorts(struct torture_context *tctx,
170 struct dcerpc_pipe *p,
171 struct test_spoolss_context *ctx)
173 NTSTATUS status;
174 struct spoolss_EnumPorts r;
175 uint16_t levels[] = { 1, 2 };
176 int i, j;
178 for (i=0;i<ARRAY_SIZE(levels);i++) {
179 int level = levels[i];
180 DATA_BLOB blob;
181 uint32_t needed;
182 uint32_t count;
183 union spoolss_PortInfo *info;
185 r.in.servername = "";
186 r.in.level = level;
187 r.in.buffer = NULL;
188 r.in.offered = 0;
189 r.out.needed = &needed;
190 r.out.count = &count;
191 r.out.info = &info;
193 torture_comment(tctx, "Testing EnumPorts level %u\n", r.in.level);
195 status = dcerpc_spoolss_EnumPorts(p, ctx, &r);
196 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EnumPorts failed");
197 if (W_ERROR_IS_OK(r.out.result)) {
198 /* TODO: do some more checks here */
199 continue;
201 torture_assert_werr_equal(tctx, r.out.result, WERR_INSUFFICIENT_BUFFER,
202 "EnumPorts unexpected return code");
204 blob = data_blob_talloc(ctx, NULL, needed);
205 data_blob_clear(&blob);
206 r.in.buffer = &blob;
207 r.in.offered = needed;
209 status = dcerpc_spoolss_EnumPorts(p, ctx, &r);
210 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EnumPorts failed");
212 torture_assert_werr_ok(tctx, r.out.result, "EnumPorts failed");
214 torture_assert(tctx, info, "EnumPorts returned no info");
216 CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumPorts, info, r.in.level, count, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
218 ctx->port_count[level] = count;
219 ctx->ports[level] = info;
222 for (i=1;i<ARRAY_SIZE(levels);i++) {
223 int level = levels[i];
224 int old_level = levels[i-1];
225 torture_assert_int_equal(tctx, ctx->port_count[level], ctx->port_count[old_level],
226 "EnumPorts invalid value");
228 /* if the array sizes are not the same we would maybe segfault in the following code */
230 for (i=0;i<ARRAY_SIZE(levels);i++) {
231 int level = levels[i];
232 for (j=0;j<ctx->port_count[level];j++) {
233 union spoolss_PortInfo *cur = &ctx->ports[level][j];
234 union spoolss_PortInfo *ref = &ctx->ports[2][j];
235 switch (level) {
236 case 1:
237 COMPARE_STRING(tctx, cur->info1, ref->info2, port_name);
238 break;
239 case 2:
240 /* level 2 is our reference, and it makes no sense to compare it to itself */
241 break;
246 return true;
249 static bool test_GetPrintProcessorDirectory(struct torture_context *tctx,
250 struct dcerpc_pipe *p,
251 struct test_spoolss_context *ctx)
253 NTSTATUS status;
254 struct spoolss_GetPrintProcessorDirectory r;
255 struct {
256 uint16_t level;
257 const char *server;
258 } levels[] = {{
259 .level = 1,
260 .server = NULL
262 .level = 1,
263 .server = ""
265 .level = 78,
266 .server = ""
268 .level = 1,
269 .server = talloc_asprintf(ctx, "\\\\%s", dcerpc_server_name(p))
271 .level = 1024,
272 .server = talloc_asprintf(ctx, "\\\\%s", dcerpc_server_name(p))
275 int i;
276 uint32_t needed;
278 for (i=0;i<ARRAY_SIZE(levels);i++) {
279 int level = levels[i].level;
280 DATA_BLOB blob;
282 r.in.server = levels[i].server;
283 r.in.environment = SPOOLSS_ARCHITECTURE_NT_X86;
284 r.in.level = level;
285 r.in.buffer = NULL;
286 r.in.offered = 0;
287 r.out.needed = &needed;
289 torture_comment(tctx, "Testing GetPrintProcessorDirectory level %u\n", r.in.level);
291 status = dcerpc_spoolss_GetPrintProcessorDirectory(p, ctx, &r);
292 torture_assert_ntstatus_ok(tctx, status,
293 "dcerpc_spoolss_GetPrintProcessorDirectory failed");
294 torture_assert_werr_equal(tctx, r.out.result, WERR_INSUFFICIENT_BUFFER,
295 "GetPrintProcessorDirectory unexpected return code");
297 blob = data_blob_talloc(ctx, NULL, needed);
298 data_blob_clear(&blob);
299 r.in.buffer = &blob;
300 r.in.offered = needed;
302 status = dcerpc_spoolss_GetPrintProcessorDirectory(p, ctx, &r);
303 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_GetPrintProcessorDirectory failed");
305 torture_assert_werr_ok(tctx, r.out.result, "GetPrintProcessorDirectory failed");
307 CHECK_NEEDED_SIZE_LEVEL(spoolss_PrintProcessorDirectoryInfo, r.out.info, r.in.level, lp_iconv_convenience(tctx->lp_ctx), needed, 2);
310 return true;
314 static bool test_GetPrinterDriverDirectory(struct torture_context *tctx,
315 struct dcerpc_pipe *p,
316 struct test_spoolss_context *ctx)
318 NTSTATUS status;
319 struct spoolss_GetPrinterDriverDirectory r;
320 struct {
321 uint16_t level;
322 const char *server;
323 } levels[] = {{
324 .level = 1,
325 .server = NULL
327 .level = 1,
328 .server = ""
330 .level = 78,
331 .server = ""
333 .level = 1,
334 .server = talloc_asprintf(ctx, "\\\\%s", dcerpc_server_name(p))
336 .level = 1024,
337 .server = talloc_asprintf(ctx, "\\\\%s", dcerpc_server_name(p))
340 int i;
341 uint32_t needed;
343 for (i=0;i<ARRAY_SIZE(levels);i++) {
344 int level = levels[i].level;
345 DATA_BLOB blob;
347 r.in.server = levels[i].server;
348 r.in.environment = SPOOLSS_ARCHITECTURE_NT_X86;
349 r.in.level = level;
350 r.in.buffer = NULL;
351 r.in.offered = 0;
352 r.out.needed = &needed;
354 torture_comment(tctx, "Testing GetPrinterDriverDirectory level %u\n", r.in.level);
356 status = dcerpc_spoolss_GetPrinterDriverDirectory(p, ctx, &r);
357 torture_assert_ntstatus_ok(tctx, status,
358 "dcerpc_spoolss_GetPrinterDriverDirectory failed");
359 torture_assert_werr_equal(tctx, r.out.result, WERR_INSUFFICIENT_BUFFER,
360 "GetPrinterDriverDirectory unexpected return code");
362 blob = data_blob_talloc(ctx, NULL, needed);
363 data_blob_clear(&blob);
364 r.in.buffer = &blob;
365 r.in.offered = needed;
367 status = dcerpc_spoolss_GetPrinterDriverDirectory(p, ctx, &r);
368 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_GetPrinterDriverDirectory failed");
370 torture_assert_werr_ok(tctx, r.out.result, "GetPrinterDriverDirectory failed");
372 CHECK_NEEDED_SIZE_LEVEL(spoolss_DriverDirectoryInfo, r.out.info, r.in.level, lp_iconv_convenience(tctx->lp_ctx), needed, 2);
375 return true;
378 static bool test_EnumPrinterDrivers(struct torture_context *tctx,
379 struct dcerpc_pipe *p,
380 struct test_spoolss_context *ctx,
381 const char *architecture)
383 NTSTATUS status;
384 struct spoolss_EnumPrinterDrivers r;
385 uint16_t levels[] = { 1, 2, 3, 4, 5, 6, 8 };
386 int i, j;
388 for (i=0;i<ARRAY_SIZE(levels);i++) {
389 int level = levels[i];
390 DATA_BLOB blob;
391 uint32_t needed;
392 uint32_t count;
393 union spoolss_DriverInfo *info;
395 /* FIXME: gd, come back and fix "" as server, and handle
396 * priority of returned error codes in torture test and samba 3
397 * server */
399 r.in.server = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
400 r.in.environment = architecture;
401 r.in.level = level;
402 r.in.buffer = NULL;
403 r.in.offered = 0;
404 r.out.needed = &needed;
405 r.out.count = &count;
406 r.out.info = &info;
408 torture_comment(tctx, "Testing EnumPrinterDrivers level %u (%s)\n", r.in.level, r.in.environment);
410 status = dcerpc_spoolss_EnumPrinterDrivers(p, ctx, &r);
411 torture_assert_ntstatus_ok(tctx, status,
412 "dcerpc_spoolss_EnumPrinterDrivers failed");
413 if (W_ERROR_IS_OK(r.out.result)) {
414 /* TODO: do some more checks here */
415 continue;
417 if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
418 blob = data_blob_talloc(ctx, NULL, needed);
419 data_blob_clear(&blob);
420 r.in.buffer = &blob;
421 r.in.offered = needed;
423 status = dcerpc_spoolss_EnumPrinterDrivers(p, ctx, &r);
424 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EnumPrinterDrivers failed");
427 torture_assert_werr_ok(tctx, r.out.result, "EnumPrinterDrivers failed");
429 CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumPrinterDrivers, info, r.in.level, count, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
431 ctx->driver_count[level] = count;
432 ctx->drivers[level] = info;
435 for (i=1;i<ARRAY_SIZE(levels);i++) {
436 int level = levels[i];
437 int old_level = levels[i-1];
439 torture_assert_int_equal(tctx, ctx->driver_count[level], ctx->driver_count[old_level],
440 "EnumPrinterDrivers invalid value");
443 for (i=0;i<ARRAY_SIZE(levels);i++) {
444 int level = levels[i];
446 for (j=0;j<ctx->driver_count[level];j++) {
447 union spoolss_DriverInfo *cur = &ctx->drivers[level][j];
448 union spoolss_DriverInfo *ref = &ctx->drivers[8][j];
450 switch (level) {
451 case 1:
452 COMPARE_STRING(tctx, cur->info1, ref->info8, driver_name);
453 break;
454 case 2:
455 COMPARE_UINT32(tctx, cur->info2, ref->info8, version);
456 COMPARE_STRING(tctx, cur->info2, ref->info8, driver_name);
457 COMPARE_STRING(tctx, cur->info2, ref->info8, architecture);
458 COMPARE_STRING(tctx, cur->info2, ref->info8, driver_path);
459 COMPARE_STRING(tctx, cur->info2, ref->info8, data_file);
460 COMPARE_STRING(tctx, cur->info2, ref->info8, config_file);
461 break;
462 case 3:
463 COMPARE_UINT32(tctx, cur->info3, ref->info8, version);
464 COMPARE_STRING(tctx, cur->info3, ref->info8, driver_name);
465 COMPARE_STRING(tctx, cur->info3, ref->info8, architecture);
466 COMPARE_STRING(tctx, cur->info3, ref->info8, driver_path);
467 COMPARE_STRING(tctx, cur->info3, ref->info8, data_file);
468 COMPARE_STRING(tctx, cur->info3, ref->info8, config_file);
469 COMPARE_STRING(tctx, cur->info3, ref->info8, help_file);
470 COMPARE_STRING_ARRAY(tctx, cur->info3, ref->info8, dependent_files);
471 COMPARE_STRING(tctx, cur->info3, ref->info8, monitor_name);
472 COMPARE_STRING(tctx, cur->info3, ref->info8, default_datatype);
473 break;
474 case 4:
475 COMPARE_UINT32(tctx, cur->info4, ref->info8, version);
476 COMPARE_STRING(tctx, cur->info4, ref->info8, driver_name);
477 COMPARE_STRING(tctx, cur->info4, ref->info8, architecture);
478 COMPARE_STRING(tctx, cur->info4, ref->info8, driver_path);
479 COMPARE_STRING(tctx, cur->info4, ref->info8, data_file);
480 COMPARE_STRING(tctx, cur->info4, ref->info8, config_file);
481 COMPARE_STRING(tctx, cur->info4, ref->info8, help_file);
482 COMPARE_STRING_ARRAY(tctx, cur->info4, ref->info8, dependent_files);
483 COMPARE_STRING(tctx, cur->info4, ref->info8, monitor_name);
484 COMPARE_STRING(tctx, cur->info4, ref->info8, default_datatype);
485 COMPARE_STRING_ARRAY(tctx, cur->info4, ref->info8, previous_names);
486 break;
487 case 5:
488 COMPARE_UINT32(tctx, cur->info5, ref->info8, version);
489 COMPARE_STRING(tctx, cur->info5, ref->info8, driver_name);
490 COMPARE_STRING(tctx, cur->info5, ref->info8, architecture);
491 COMPARE_STRING(tctx, cur->info5, ref->info8, driver_path);
492 COMPARE_STRING(tctx, cur->info5, ref->info8, data_file);
493 COMPARE_STRING(tctx, cur->info5, ref->info8, config_file);
494 /*COMPARE_UINT32(tctx, cur->info5, ref->info8, driver_attributes);*/
495 /*COMPARE_UINT32(tctx, cur->info5, ref->info8, config_version);*/
496 /*TODO: ! COMPARE_UINT32(tctx, cur->info5, ref->info8, driver_version); */
497 break;
498 case 6:
499 COMPARE_UINT32(tctx, cur->info6, ref->info8, version);
500 COMPARE_STRING(tctx, cur->info6, ref->info8, driver_name);
501 COMPARE_STRING(tctx, cur->info6, ref->info8, architecture);
502 COMPARE_STRING(tctx, cur->info6, ref->info8, driver_path);
503 COMPARE_STRING(tctx, cur->info6, ref->info8, data_file);
504 COMPARE_STRING(tctx, cur->info6, ref->info8, config_file);
505 COMPARE_STRING(tctx, cur->info6, ref->info8, help_file);
506 COMPARE_STRING_ARRAY(tctx, cur->info6, ref->info8, dependent_files);
507 COMPARE_STRING(tctx, cur->info6, ref->info8, monitor_name);
508 COMPARE_STRING(tctx, cur->info6, ref->info8, default_datatype);
509 COMPARE_STRING_ARRAY(tctx, cur->info6, ref->info8, previous_names);
510 COMPARE_NTTIME(tctx, cur->info6, ref->info8, driver_date);
511 COMPARE_UINT64(tctx, cur->info6, ref->info8, driver_version);
512 COMPARE_STRING(tctx, cur->info6, ref->info8, manufacturer_name);
513 COMPARE_STRING(tctx, cur->info6, ref->info8, manufacturer_url);
514 COMPARE_STRING(tctx, cur->info6, ref->info8, hardware_id);
515 COMPARE_STRING(tctx, cur->info6, ref->info8, provider);
516 break;
517 case 8:
518 /* level 8 is our reference, and it makes no sense to compare it to itself */
519 break;
524 return true;
527 static bool test_EnumMonitors(struct torture_context *tctx,
528 struct dcerpc_pipe *p,
529 struct test_spoolss_context *ctx)
531 NTSTATUS status;
532 struct spoolss_EnumMonitors r;
533 uint16_t levels[] = { 1, 2 };
534 int i, j;
536 for (i=0;i<ARRAY_SIZE(levels);i++) {
537 int level = levels[i];
538 DATA_BLOB blob;
539 uint32_t needed;
540 uint32_t count;
541 union spoolss_MonitorInfo *info;
543 r.in.servername = "";
544 r.in.level = level;
545 r.in.buffer = NULL;
546 r.in.offered = 0;
547 r.out.needed = &needed;
548 r.out.count = &count;
549 r.out.info = &info;
551 torture_comment(tctx, "Testing EnumMonitors level %u\n", r.in.level);
553 status = dcerpc_spoolss_EnumMonitors(p, ctx, &r);
554 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EnumMonitors failed");
555 if (W_ERROR_IS_OK(r.out.result)) {
556 /* TODO: do some more checks here */
557 continue;
559 torture_assert_werr_equal(tctx, r.out.result, WERR_INSUFFICIENT_BUFFER,
560 "EnumMonitors failed");
562 blob = data_blob_talloc(ctx, NULL, needed);
563 data_blob_clear(&blob);
564 r.in.buffer = &blob;
565 r.in.offered = needed;
567 status = dcerpc_spoolss_EnumMonitors(p, ctx, &r);
568 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EnumMonitors failed");
570 torture_assert_werr_ok(tctx, r.out.result, "EnumMonitors failed");
572 CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumMonitors, info, r.in.level, count, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
574 ctx->monitor_count[level] = count;
575 ctx->monitors[level] = info;
578 for (i=1;i<ARRAY_SIZE(levels);i++) {
579 int level = levels[i];
580 int old_level = levels[i-1];
581 torture_assert_int_equal(tctx, ctx->monitor_count[level], ctx->monitor_count[old_level],
582 "EnumMonitors invalid value");
585 for (i=0;i<ARRAY_SIZE(levels);i++) {
586 int level = levels[i];
587 for (j=0;j<ctx->monitor_count[level];j++) {
588 union spoolss_MonitorInfo *cur = &ctx->monitors[level][j];
589 union spoolss_MonitorInfo *ref = &ctx->monitors[2][j];
590 switch (level) {
591 case 1:
592 COMPARE_STRING(tctx, cur->info1, ref->info2, monitor_name);
593 break;
594 case 2:
595 /* level 2 is our reference, and it makes no sense to compare it to itself */
596 break;
601 return true;
604 static bool test_EnumPrintProcessors(struct torture_context *tctx,
605 struct dcerpc_pipe *p,
606 struct test_spoolss_context *ctx)
608 NTSTATUS status;
609 struct spoolss_EnumPrintProcessors r;
610 uint16_t levels[] = { 1 };
611 int i, j;
613 for (i=0;i<ARRAY_SIZE(levels);i++) {
614 int level = levels[i];
615 DATA_BLOB blob;
616 uint32_t needed;
617 uint32_t count;
618 union spoolss_PrintProcessorInfo *info;
620 r.in.servername = "";
621 r.in.environment = SPOOLSS_ARCHITECTURE_NT_X86;
622 r.in.level = level;
623 r.in.buffer = NULL;
624 r.in.offered = 0;
625 r.out.needed = &needed;
626 r.out.count = &count;
627 r.out.info = &info;
629 torture_comment(tctx, "Testing EnumPrintProcessors level %u\n", r.in.level);
631 status = dcerpc_spoolss_EnumPrintProcessors(p, ctx, &r);
632 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EnumPrintProcessors failed");
633 if (W_ERROR_IS_OK(r.out.result)) {
634 /* TODO: do some more checks here */
635 continue;
637 torture_assert_werr_equal(tctx, r.out.result, WERR_INSUFFICIENT_BUFFER,
638 "EnumPrintProcessors unexpected return code");
640 blob = data_blob_talloc(ctx, NULL, needed);
641 data_blob_clear(&blob);
642 r.in.buffer = &blob;
643 r.in.offered = needed;
645 status = dcerpc_spoolss_EnumPrintProcessors(p, ctx, &r);
646 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EnumPrintProcessors failed");
648 torture_assert_werr_ok(tctx, r.out.result, "EnumPrintProcessors failed");
650 CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumPrintProcessors, info, r.in.level, count, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
652 ctx->print_processor_count[level] = count;
653 ctx->print_processors[level] = info;
656 for (i=1;i<ARRAY_SIZE(levels);i++) {
657 int level = levels[i];
658 int old_level = levels[i-1];
659 torture_assert_int_equal(tctx, ctx->print_processor_count[level], ctx->print_processor_count[old_level],
660 "EnumPrintProcessors failed");
663 for (i=0;i<ARRAY_SIZE(levels);i++) {
664 int level = levels[i];
665 for (j=0;j<ctx->print_processor_count[level];j++) {
666 #if 0
667 union spoolss_PrintProcessorInfo *cur = &ctx->print_processors[level][j];
668 union spoolss_PrintProcessorInfo *ref = &ctx->print_processors[1][j];
669 #endif
670 switch (level) {
671 case 1:
672 /* level 1 is our reference, and it makes no sense to compare it to itself */
673 break;
678 return true;
681 static bool test_EnumPrintProcDataTypes(struct torture_context *tctx,
682 struct dcerpc_pipe *p,
683 struct test_spoolss_context *ctx)
685 NTSTATUS status;
686 struct spoolss_EnumPrintProcDataTypes r;
687 uint16_t levels[] = { 1 };
688 int i;
690 for (i=0;i<ARRAY_SIZE(levels);i++) {
691 int level = levels[i];
692 DATA_BLOB blob;
693 uint32_t needed;
694 uint32_t count;
695 union spoolss_PrintProcDataTypesInfo *info;
697 r.in.servername = "";
698 r.in.print_processor_name = "winprint";
699 r.in.level = level;
700 r.in.buffer = NULL;
701 r.in.offered = 0;
702 r.out.needed = &needed;
703 r.out.count = &count;
704 r.out.info = &info;
706 torture_comment(tctx, "Testing EnumPrintProcDataTypes level %u\n", r.in.level);
708 status = dcerpc_spoolss_EnumPrintProcDataTypes(p, ctx, &r);
709 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EnumPrintProcDataType failed");
710 if (W_ERROR_IS_OK(r.out.result)) {
711 /* TODO: do some more checks here */
712 continue;
714 torture_assert_werr_equal(tctx, r.out.result, WERR_INSUFFICIENT_BUFFER,
715 "EnumPrintProcDataTypes unexpected return code");
717 blob = data_blob_talloc(ctx, NULL, needed);
718 data_blob_clear(&blob);
719 r.in.buffer = &blob;
720 r.in.offered = needed;
722 status = dcerpc_spoolss_EnumPrintProcDataTypes(p, ctx, &r);
723 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EnumPrintProcDataTypes failed");
725 torture_assert_werr_ok(tctx, r.out.result, "EnumPrintProcDataTypes failed");
727 CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumPrintProcDataTypes, info, r.in.level, count, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
731 return true;
735 static bool test_EnumPrinters(struct torture_context *tctx,
736 struct dcerpc_pipe *p,
737 struct test_spoolss_context *ctx)
739 struct spoolss_EnumPrinters r;
740 NTSTATUS status;
741 uint16_t levels[] = { 0, 1, 2, 4, 5 };
742 int i, j;
744 for (i=0;i<ARRAY_SIZE(levels);i++) {
745 int level = levels[i];
746 DATA_BLOB blob;
747 uint32_t needed;
748 uint32_t count;
749 union spoolss_PrinterInfo *info;
751 r.in.flags = PRINTER_ENUM_LOCAL;
752 r.in.server = "";
753 r.in.level = level;
754 r.in.buffer = NULL;
755 r.in.offered = 0;
756 r.out.needed = &needed;
757 r.out.count = &count;
758 r.out.info = &info;
760 torture_comment(tctx, "Testing EnumPrinters level %u\n", r.in.level);
762 status = dcerpc_spoolss_EnumPrinters(p, ctx, &r);
763 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EnumPrinters failed");
764 if (W_ERROR_IS_OK(r.out.result)) {
765 /* TODO: do some more checks here */
766 continue;
768 torture_assert_werr_equal(tctx, r.out.result, WERR_INSUFFICIENT_BUFFER,
769 "EnumPrinters unexpected return code");
771 blob = data_blob_talloc(ctx, NULL, needed);
772 data_blob_clear(&blob);
773 r.in.buffer = &blob;
774 r.in.offered = needed;
776 status = dcerpc_spoolss_EnumPrinters(p, ctx, &r);
777 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EnumPrinters failed");
779 torture_assert_werr_ok(tctx, r.out.result, "EnumPrinters failed");
781 CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumPrinters, info, r.in.level, count, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
783 ctx->printer_count[level] = count;
784 ctx->printers[level] = info;
787 for (i=1;i<ARRAY_SIZE(levels);i++) {
788 int level = levels[i];
789 int old_level = levels[i-1];
790 torture_assert_int_equal(tctx, ctx->printer_count[level], ctx->printer_count[old_level],
791 "EnumPrinters invalid value");
794 for (i=0;i<ARRAY_SIZE(levels);i++) {
795 int level = levels[i];
796 for (j=0;j<ctx->printer_count[level];j++) {
797 union spoolss_PrinterInfo *cur = &ctx->printers[level][j];
798 union spoolss_PrinterInfo *ref = &ctx->printers[2][j];
799 switch (level) {
800 case 0:
801 COMPARE_STRING(tctx, cur->info0, ref->info2, printername);
802 COMPARE_STRING(tctx, cur->info0, ref->info2, servername);
803 COMPARE_UINT32(tctx, cur->info0, ref->info2, cjobs);
804 /*COMPARE_UINT32(tctx, cur->info0, ref->info2, total_jobs);
805 COMPARE_UINT32(tctx, cur->info0, ref->info2, total_bytes);
806 COMPARE_SPOOLSS_TIME(cur->info0, ref->info2, spoolss_Time time);
807 COMPARE_UINT32(tctx, cur->info0, ref->info2, global_counter);
808 COMPARE_UINT32(tctx, cur->info0, ref->info2, total_pages);
809 COMPARE_UINT32(tctx, cur->info0, ref->info2, version);
810 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown10);
811 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown11);
812 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown12);
813 COMPARE_UINT32(tctx, cur->info0, ref->info2, session_counter);
814 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown14);
815 COMPARE_UINT32(tctx, cur->info0, ref->info2, printer_errors);
816 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown16);
817 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown17);
818 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown18);
819 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown19);
820 COMPARE_UINT32(tctx, cur->info0, ref->info2, change_id);
821 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown21);*/
822 COMPARE_UINT32(tctx, cur->info0, ref->info2, status);
823 /*COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown23);
824 COMPARE_UINT32(tctx, cur->info0, ref->info2, c_setprinter);
825 COMPARE_UINT16(cur->info0, ref->info2, unknown25);
826 COMPARE_UINT16(cur->info0, ref->info2, unknown26);
827 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown27);
828 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown28);
829 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown29);*/
830 break;
831 case 1:
832 /*COMPARE_UINT32(tctx, cur->info1, ref->info2, flags);*/
833 /*COMPARE_STRING(tctx, cur->info1, ref->info2, name);*/
834 /*COMPARE_STRING(tctx, cur->info1, ref->info2, description);*/
835 COMPARE_STRING(tctx, cur->info1, ref->info2, comment);
836 break;
837 case 2:
838 /* level 2 is our reference, and it makes no sense to compare it to itself */
839 break;
840 case 4:
841 COMPARE_STRING(tctx, cur->info4, ref->info2, printername);
842 COMPARE_STRING(tctx, cur->info4, ref->info2, servername);
843 COMPARE_UINT32(tctx, cur->info4, ref->info2, attributes);
844 break;
845 case 5:
846 COMPARE_STRING(tctx, cur->info5, ref->info2, printername);
847 COMPARE_STRING(tctx, cur->info5, ref->info2, portname);
848 COMPARE_UINT32(tctx, cur->info5, ref->info2, attributes);
849 /*COMPARE_UINT32(tctx, cur->info5, ref->info2, device_not_selected_timeout);
850 COMPARE_UINT32(tctx, cur->info5, ref->info2, transmission_retry_timeout);*/
851 break;
856 /* TODO:
857 * - verify that the port of a printer was in the list returned by EnumPorts
860 return true;
863 static bool test_GetPrinterDriver2(struct torture_context *tctx,
864 struct dcerpc_pipe *p,
865 struct policy_handle *handle,
866 const char *driver_name);
868 static bool test_GetPrinter(struct torture_context *tctx,
869 struct dcerpc_pipe *p,
870 struct policy_handle *handle)
872 NTSTATUS status;
873 struct spoolss_GetPrinter r;
874 uint16_t levels[] = {0, 1, 2, 3, 4, 5, 6, 7, 8};
875 int i;
876 uint32_t needed;
878 for (i=0;i<ARRAY_SIZE(levels);i++) {
879 r.in.handle = handle;
880 r.in.level = levels[i];
881 r.in.buffer = NULL;
882 r.in.offered = 0;
883 r.out.needed = &needed;
885 torture_comment(tctx, "Testing GetPrinter level %u\n", r.in.level);
887 status = dcerpc_spoolss_GetPrinter(p, tctx, &r);
888 torture_assert_ntstatus_ok(tctx, status, "GetPrinter failed");
890 if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
891 DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed);
892 data_blob_clear(&blob);
893 r.in.buffer = &blob;
894 r.in.offered = needed;
895 status = dcerpc_spoolss_GetPrinter(p, tctx, &r);
898 torture_assert_ntstatus_ok(tctx, status, "GetPrinter failed");
900 torture_assert_werr_ok(tctx, r.out.result, "GetPrinter failed");
902 CHECK_NEEDED_SIZE_LEVEL(spoolss_PrinterInfo, r.out.info, r.in.level, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
904 if ((r.in.level == 2) && r.out.info->info2.drivername && strlen(r.out.info->info2.drivername)) {
905 torture_assert(tctx,
906 test_GetPrinterDriver2(tctx, p, handle, r.out.info->info2.drivername),
907 "failed to call test_GetPrinterDriver2");
911 return true;
914 static bool test_SetPrinter_errors(struct torture_context *tctx,
915 struct dcerpc_pipe *p,
916 struct policy_handle *handle)
918 struct spoolss_SetPrinter r;
919 uint16_t levels[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
920 int i;
922 struct spoolss_SetPrinterInfoCtr info_ctr;
923 struct spoolss_DevmodeContainer devmode_ctr;
924 struct sec_desc_buf secdesc_ctr;
926 info_ctr.level = 0;
927 info_ctr.info.info0 = NULL;
929 ZERO_STRUCT(devmode_ctr);
930 ZERO_STRUCT(secdesc_ctr);
932 r.in.handle = handle;
933 r.in.info_ctr = &info_ctr;
934 r.in.devmode_ctr = &devmode_ctr;
935 r.in.secdesc_ctr = &secdesc_ctr;
936 r.in.command = 0;
938 torture_comment(tctx, "Testing SetPrinter all zero\n");
940 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_SetPrinter(p, tctx, &r),
941 "failed to call SetPrinter");
942 torture_assert_werr_equal(tctx, r.out.result, WERR_INVALID_PARAM,
943 "failed to call SetPrinter");
945 again:
946 for (i=0; i < ARRAY_SIZE(levels); i++) {
948 struct spoolss_SetPrinterInfo0 info0;
949 struct spoolss_SetPrinterInfo1 info1;
950 struct spoolss_SetPrinterInfo2 info2;
951 struct spoolss_SetPrinterInfo3 info3;
952 struct spoolss_SetPrinterInfo4 info4;
953 struct spoolss_SetPrinterInfo5 info5;
954 struct spoolss_SetPrinterInfo6 info6;
955 struct spoolss_SetPrinterInfo7 info7;
956 struct spoolss_SetPrinterInfo8 info8;
957 struct spoolss_SetPrinterInfo9 info9;
960 info_ctr.level = levels[i];
961 switch (levels[i]) {
962 case 0:
963 ZERO_STRUCT(info0);
964 info_ctr.info.info0 = &info0;
965 break;
966 case 1:
967 ZERO_STRUCT(info1);
968 info_ctr.info.info1 = &info1;
969 break;
970 case 2:
971 ZERO_STRUCT(info2);
972 info_ctr.info.info2 = &info2;
973 break;
974 case 3:
975 ZERO_STRUCT(info3);
976 info_ctr.info.info3 = &info3;
977 break;
978 case 4:
979 ZERO_STRUCT(info4);
980 info_ctr.info.info4 = &info4;
981 break;
982 case 5:
983 ZERO_STRUCT(info5);
984 info_ctr.info.info5 = &info5;
985 break;
986 case 6:
987 ZERO_STRUCT(info6);
988 info_ctr.info.info6 = &info6;
989 break;
990 case 7:
991 ZERO_STRUCT(info7);
992 info_ctr.info.info7 = &info7;
993 break;
994 case 8:
995 ZERO_STRUCT(info8);
996 info_ctr.info.info8 = &info8;
997 break;
998 case 9:
999 ZERO_STRUCT(info9);
1000 info_ctr.info.info9 = &info9;
1001 break;
1004 torture_comment(tctx, "Testing SetPrinter level %d, command %d\n",
1005 info_ctr.level, r.in.command);
1007 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_SetPrinter(p, tctx, &r),
1008 "failed to call SetPrinter");
1010 switch (r.in.command) {
1011 case SPOOLSS_PRINTER_CONTROL_UNPAUSE: /* 0 */
1012 /* is ignored for all levels other then 0 */
1013 if (info_ctr.level > 0) {
1014 /* ignored then */
1015 break;
1017 case SPOOLSS_PRINTER_CONTROL_PAUSE: /* 1 */
1018 case SPOOLSS_PRINTER_CONTROL_RESUME: /* 2 */
1019 case SPOOLSS_PRINTER_CONTROL_PURGE: /* 3 */
1020 if (info_ctr.level > 0) {
1021 /* is invalid for all levels other then 0 */
1022 torture_assert_werr_equal(tctx, r.out.result, WERR_INVALID_PRINTER_COMMAND,
1023 "unexpected error code returned");
1024 continue;
1025 } else {
1026 torture_assert_werr_ok(tctx, r.out.result,
1027 "failed to call SetPrinter with non 0 command");
1028 continue;
1030 break;
1032 case SPOOLSS_PRINTER_CONTROL_SET_STATUS: /* 4 */
1033 /* FIXME: gd needs further investigation */
1034 default:
1035 torture_assert_werr_equal(tctx, r.out.result, WERR_INVALID_PRINTER_COMMAND,
1036 "unexpected error code returned");
1037 continue;
1040 switch (info_ctr.level) {
1041 case 1:
1042 torture_assert_werr_equal(tctx, r.out.result, WERR_UNKNOWN_LEVEL,
1043 "unexpected error code returned");
1044 break;
1045 case 2:
1046 torture_assert_werr_equal(tctx, r.out.result, WERR_UNKNOWN_PRINTER_DRIVER,
1047 "unexpected error code returned");
1048 break;
1049 case 3:
1050 case 4:
1051 case 5:
1052 case 7:
1053 torture_assert_werr_equal(tctx, r.out.result, WERR_INVALID_PARAM,
1054 "unexpected error code returned");
1055 break;
1056 case 9:
1057 torture_assert_werr_equal(tctx, r.out.result, WERR_NOT_SUPPORTED,
1058 "unexpected error code returned");
1059 break;
1060 default:
1061 torture_assert_werr_ok(tctx, r.out.result,
1062 "failed to call SetPrinter");
1063 break;
1067 if (r.in.command < 5) {
1068 r.in.command++;
1069 goto again;
1072 return true;
1075 static void clear_info2(struct spoolss_SetPrinterInfoCtr *r)
1077 if ((r->level == 2) && (r->info.info2)) {
1078 r->info.info2->secdesc_ptr = 0;
1079 r->info.info2->devmode_ptr = 0;
1083 static bool test_PrinterInfo(struct torture_context *tctx,
1084 struct dcerpc_pipe *p,
1085 struct policy_handle *handle)
1087 NTSTATUS status;
1088 struct spoolss_SetPrinter s;
1089 struct spoolss_GetPrinter q;
1090 struct spoolss_GetPrinter q0;
1091 struct spoolss_SetPrinterInfoCtr info_ctr;
1092 union spoolss_PrinterInfo info;
1093 struct spoolss_DevmodeContainer devmode_ctr;
1094 struct sec_desc_buf secdesc_ctr;
1095 uint32_t needed;
1096 bool ret = true;
1097 int i;
1099 uint32_t status_list[] = {
1100 /* these do not stick
1101 PRINTER_STATUS_PAUSED,
1102 PRINTER_STATUS_ERROR,
1103 PRINTER_STATUS_PENDING_DELETION, */
1104 PRINTER_STATUS_PAPER_JAM,
1105 PRINTER_STATUS_PAPER_OUT,
1106 PRINTER_STATUS_MANUAL_FEED,
1107 PRINTER_STATUS_PAPER_PROBLEM,
1108 PRINTER_STATUS_OFFLINE,
1109 PRINTER_STATUS_IO_ACTIVE,
1110 PRINTER_STATUS_BUSY,
1111 PRINTER_STATUS_PRINTING,
1112 PRINTER_STATUS_OUTPUT_BIN_FULL,
1113 PRINTER_STATUS_NOT_AVAILABLE,
1114 PRINTER_STATUS_WAITING,
1115 PRINTER_STATUS_PROCESSING,
1116 PRINTER_STATUS_INITIALIZING,
1117 PRINTER_STATUS_WARMING_UP,
1118 PRINTER_STATUS_TONER_LOW,
1119 PRINTER_STATUS_NO_TONER,
1120 PRINTER_STATUS_PAGE_PUNT,
1121 PRINTER_STATUS_USER_INTERVENTION,
1122 PRINTER_STATUS_OUT_OF_MEMORY,
1123 PRINTER_STATUS_DOOR_OPEN,
1124 PRINTER_STATUS_SERVER_UNKNOWN,
1125 PRINTER_STATUS_POWER_SAVE,
1126 /* these do not stick
1127 0x02000000,
1128 0x04000000,
1129 0x08000000,
1130 0x10000000,
1131 0x20000000,
1132 0x40000000,
1133 0x80000000 */
1135 uint32_t default_attribute = PRINTER_ATTRIBUTE_LOCAL;
1136 uint32_t attribute_list[] = {
1137 PRINTER_ATTRIBUTE_QUEUED,
1138 /* fails with WERR_INVALID_DATATYPE:
1139 PRINTER_ATTRIBUTE_DIRECT, */
1140 /* does not stick
1141 PRINTER_ATTRIBUTE_DEFAULT, */
1142 PRINTER_ATTRIBUTE_SHARED,
1143 /* does not stick
1144 PRINTER_ATTRIBUTE_NETWORK, */
1145 PRINTER_ATTRIBUTE_HIDDEN,
1146 PRINTER_ATTRIBUTE_LOCAL,
1147 PRINTER_ATTRIBUTE_ENABLE_DEVQ,
1148 PRINTER_ATTRIBUTE_KEEPPRINTEDJOBS,
1149 PRINTER_ATTRIBUTE_DO_COMPLETE_FIRST,
1150 PRINTER_ATTRIBUTE_WORK_OFFLINE,
1151 /* does not stick
1152 PRINTER_ATTRIBUTE_ENABLE_BIDI, */
1153 /* fails with WERR_INVALID_DATATYPE:
1154 PRINTER_ATTRIBUTE_RAW_ONLY, */
1155 /* these do not stick
1156 PRINTER_ATTRIBUTE_PUBLISHED,
1157 PRINTER_ATTRIBUTE_FAX,
1158 PRINTER_ATTRIBUTE_TS,
1159 0x00010000,
1160 0x00020000,
1161 0x00040000,
1162 0x00080000,
1163 0x00100000,
1164 0x00200000,
1165 0x00400000,
1166 0x00800000,
1167 0x01000000,
1168 0x02000000,
1169 0x04000000,
1170 0x08000000,
1171 0x10000000,
1172 0x20000000,
1173 0x40000000,
1174 0x80000000 */
1177 ZERO_STRUCT(devmode_ctr);
1178 ZERO_STRUCT(secdesc_ctr);
1180 s.in.handle = handle;
1181 s.in.command = 0;
1182 s.in.info_ctr = &info_ctr;
1183 s.in.devmode_ctr = &devmode_ctr;
1184 s.in.secdesc_ctr = &secdesc_ctr;
1186 q.in.handle = handle;
1187 q.out.info = &info;
1188 q0 = q;
1190 #define TESTGETCALL(call, r) \
1191 r.in.buffer = NULL; \
1192 r.in.offered = 0;\
1193 r.out.needed = &needed; \
1194 status = dcerpc_spoolss_ ##call(p, tctx, &r); \
1195 if (!NT_STATUS_IS_OK(status)) { \
1196 torture_comment(tctx, #call " level %u failed - %s (%s)\n", \
1197 r.in.level, nt_errstr(status), __location__); \
1198 ret = false; \
1199 break; \
1201 if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {\
1202 DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed); \
1203 data_blob_clear(&blob); \
1204 r.in.buffer = &blob; \
1205 r.in.offered = needed; \
1207 status = dcerpc_spoolss_ ##call(p, tctx, &r); \
1208 if (!NT_STATUS_IS_OK(status)) { \
1209 torture_comment(tctx, #call " level %u failed - %s (%s)\n", \
1210 r.in.level, nt_errstr(status), __location__); \
1211 ret = false; \
1212 break; \
1214 if (!W_ERROR_IS_OK(r.out.result)) { \
1215 torture_comment(tctx, #call " level %u failed - %s (%s)\n", \
1216 r.in.level, win_errstr(r.out.result), __location__); \
1217 ret = false; \
1218 break; \
1222 #define TESTSETCALL_EXP(call, r, err) \
1223 clear_info2(&info_ctr);\
1224 status = dcerpc_spoolss_ ##call(p, tctx, &r); \
1225 if (!NT_STATUS_IS_OK(status)) { \
1226 torture_comment(tctx, #call " level %u failed - %s (%s)\n", \
1227 r.in.info_ctr->level, nt_errstr(status), __location__); \
1228 ret = false; \
1229 break; \
1231 if (!W_ERROR_IS_OK(err)) { \
1232 if (!W_ERROR_EQUAL(err, r.out.result)) { \
1233 torture_comment(tctx, #call " level %u failed - %s, expected %s (%s)\n", \
1234 r.in.info_ctr->level, win_errstr(r.out.result), win_errstr(err), __location__); \
1235 ret = false; \
1237 break; \
1239 if (!W_ERROR_IS_OK(r.out.result)) { \
1240 torture_comment(tctx, #call " level %u failed - %s (%s)\n", \
1241 r.in.info_ctr->level, win_errstr(r.out.result), __location__); \
1242 ret = false; \
1243 break; \
1246 #define TESTSETCALL(call, r) \
1247 TESTSETCALL_EXP(call, r, WERR_OK)
1249 #define STRING_EQUAL(s1, s2, field) \
1250 if ((s1 && !s2) || (s2 && !s1) || strcmp(s1, s2)) { \
1251 torture_comment(tctx, "Failed to set %s to '%s' (%s)\n", \
1252 #field, s2, __location__); \
1253 ret = false; \
1254 break; \
1257 #define MEM_EQUAL(s1, s2, length, field) \
1258 if ((s1 && !s2) || (s2 && !s1) || memcmp(s1, s2, length)) { \
1259 torture_comment(tctx, "Failed to set %s to '%s' (%s)\n", \
1260 #field, (const char *)s2, __location__); \
1261 ret = false; \
1262 break; \
1265 #define INT_EQUAL(i1, i2, field) \
1266 if (i1 != i2) { \
1267 torture_comment(tctx, "Failed to set %s to 0x%llx - got 0x%llx (%s)\n", \
1268 #field, (unsigned long long)i2, (unsigned long long)i1, __location__); \
1269 ret = false; \
1270 break; \
1273 #define TEST_PRINTERINFO_STRING_EXP_ERR(lvl1, field1, lvl2, field2, value, err) do { \
1274 torture_comment(tctx, "field test %d/%s vs %d/%s\n", lvl1, #field1, lvl2, #field2); \
1275 q.in.level = lvl1; \
1276 TESTGETCALL(GetPrinter, q) \
1277 info_ctr.level = lvl1; \
1278 info_ctr.info.info ## lvl1 = (struct spoolss_SetPrinterInfo ## lvl1 *)&q.out.info->info ## lvl1; \
1279 info_ctr.info.info ## lvl1->field1 = value;\
1280 TESTSETCALL_EXP(SetPrinter, s, err) \
1281 info_ctr.info.info ## lvl1->field1 = ""; \
1282 TESTGETCALL(GetPrinter, q) \
1283 info_ctr.info.info ## lvl1->field1 = value; \
1284 STRING_EQUAL(info_ctr.info.info ## lvl1->field1, value, field1); \
1285 q.in.level = lvl2; \
1286 TESTGETCALL(GetPrinter, q) \
1287 info_ctr.info.info ## lvl2 = (struct spoolss_SetPrinterInfo ## lvl2 *)&q.out.info->info ## lvl2; \
1288 STRING_EQUAL(info_ctr.info.info ## lvl2->field2, value, field2); \
1289 } while (0)
1291 #define TEST_PRINTERINFO_STRING(lvl1, field1, lvl2, field2, value) do { \
1292 TEST_PRINTERINFO_STRING_EXP_ERR(lvl1, field1, lvl2, field2, value, WERR_OK); \
1293 } while (0);
1295 #define TEST_PRINTERINFO_INT_EXP(lvl1, field1, lvl2, field2, value, exp_value) do { \
1296 torture_comment(tctx, "field test %d/%s vs %d/%s\n", lvl1, #field1, lvl2, #field2); \
1297 q.in.level = lvl1; \
1298 TESTGETCALL(GetPrinter, q) \
1299 info_ctr.level = lvl1; \
1300 info_ctr.info.info ## lvl1 = (struct spoolss_SetPrinterInfo ## lvl1 *)&q.out.info->info ## lvl1; \
1301 info_ctr.info.info ## lvl1->field1 = value; \
1302 TESTSETCALL(SetPrinter, s) \
1303 info_ctr.info.info ## lvl1->field1 = 0; \
1304 TESTGETCALL(GetPrinter, q) \
1305 info_ctr.info.info ## lvl1 = (struct spoolss_SetPrinterInfo ## lvl1 *)&q.out.info->info ## lvl1; \
1306 INT_EQUAL(info_ctr.info.info ## lvl1->field1, exp_value, field1); \
1307 q.in.level = lvl2; \
1308 TESTGETCALL(GetPrinter, q) \
1309 info_ctr.info.info ## lvl2 = (struct spoolss_SetPrinterInfo ## lvl2 *)&q.out.info->info ## lvl2; \
1310 INT_EQUAL(info_ctr.info.info ## lvl2->field2, exp_value, field1); \
1311 } while (0)
1313 #define TEST_PRINTERINFO_INT(lvl1, field1, lvl2, field2, value) do { \
1314 TEST_PRINTERINFO_INT_EXP(lvl1, field1, lvl2, field2, value, value); \
1315 } while (0)
1317 q0.in.level = 0;
1318 do { TESTGETCALL(GetPrinter, q0) } while (0);
1320 TEST_PRINTERINFO_STRING(2, comment, 1, comment, "xx2-1 comment");
1321 TEST_PRINTERINFO_STRING(2, comment, 2, comment, "xx2-2 comment");
1323 /* level 0 printername does not stick */
1324 /* TEST_PRINTERINFO_STRING(2, printername, 0, printername, "xx2-0 printer"); */
1325 TEST_PRINTERINFO_STRING(2, printername, 1, name, "xx2-1 printer");
1326 TEST_PRINTERINFO_STRING(2, printername, 2, printername, "xx2-2 printer");
1327 TEST_PRINTERINFO_STRING(2, printername, 4, printername, "xx2-4 printer");
1328 TEST_PRINTERINFO_STRING(2, printername, 5, printername, "xx2-5 printer");
1329 /* TEST_PRINTERINFO_STRING(4, printername, 0, printername, "xx4-0 printer"); */
1330 TEST_PRINTERINFO_STRING(4, printername, 1, name, "xx4-1 printer");
1331 TEST_PRINTERINFO_STRING(4, printername, 2, printername, "xx4-2 printer");
1332 TEST_PRINTERINFO_STRING(4, printername, 4, printername, "xx4-4 printer");
1333 TEST_PRINTERINFO_STRING(4, printername, 5, printername, "xx4-5 printer");
1334 /* TEST_PRINTERINFO_STRING(5, printername, 0, printername, "xx5-0 printer"); */
1335 TEST_PRINTERINFO_STRING(5, printername, 1, name, "xx5-1 printer");
1336 TEST_PRINTERINFO_STRING(5, printername, 2, printername, "xx5-2 printer");
1337 TEST_PRINTERINFO_STRING(5, printername, 4, printername, "xx5-4 printer");
1338 TEST_PRINTERINFO_STRING(5, printername, 5, printername, "xx5-5 printer");
1340 /* servername can be set but does not stick
1341 TEST_PRINTERINFO_STRING(2, servername, 0, servername, "xx2-0 servername");
1342 TEST_PRINTERINFO_STRING(2, servername, 2, servername, "xx2-2 servername");
1343 TEST_PRINTERINFO_STRING(2, servername, 4, servername, "xx2-4 servername");
1346 /* passing an invalid port will result in WERR_UNKNOWN_PORT */
1347 TEST_PRINTERINFO_STRING_EXP_ERR(2, portname, 2, portname, "xx2-2 portname", WERR_UNKNOWN_PORT);
1348 TEST_PRINTERINFO_STRING_EXP_ERR(2, portname, 5, portname, "xx2-5 portname", WERR_UNKNOWN_PORT);
1349 TEST_PRINTERINFO_STRING_EXP_ERR(5, portname, 2, portname, "xx5-2 portname", WERR_UNKNOWN_PORT);
1350 TEST_PRINTERINFO_STRING_EXP_ERR(5, portname, 5, portname, "xx5-5 portname", WERR_UNKNOWN_PORT);
1352 TEST_PRINTERINFO_STRING(2, sharename, 2, sharename, "xx2-2 sharename");
1353 /* passing an invalid driver will result in WERR_UNKNOWN_PRINTER_DRIVER */
1354 TEST_PRINTERINFO_STRING_EXP_ERR(2, drivername, 2, drivername, "xx2-2 drivername", WERR_UNKNOWN_PRINTER_DRIVER);
1355 TEST_PRINTERINFO_STRING(2, location, 2, location, "xx2-2 location");
1356 /* passing an invalid sepfile will result in WERR_INVALID_SEPARATOR_FILE */
1357 TEST_PRINTERINFO_STRING_EXP_ERR(2, sepfile, 2, sepfile, "xx2-2 sepfile", WERR_INVALID_SEPARATOR_FILE);
1358 /* passing an invalid printprocessor will result in WERR_UNKNOWN_PRINTPROCESSOR */
1359 TEST_PRINTERINFO_STRING_EXP_ERR(2, printprocessor, 2, printprocessor, "xx2-2 printprocessor", WERR_UNKNOWN_PRINTPROCESSOR);
1360 TEST_PRINTERINFO_STRING(2, datatype, 2, datatype, "xx2-2 datatype");
1361 TEST_PRINTERINFO_STRING(2, parameters, 2, parameters, "xx2-2 parameters");
1363 for (i=0; i < ARRAY_SIZE(attribute_list); i++) {
1364 /* TEST_PRINTERINFO_INT_EXP(2, attributes, 1, flags,
1365 attribute_list[i],
1366 (attribute_list[i] | default_attribute)
1367 ); */
1368 TEST_PRINTERINFO_INT_EXP(2, attributes, 2, attributes,
1369 attribute_list[i],
1370 (attribute_list[i] | default_attribute)
1372 TEST_PRINTERINFO_INT_EXP(2, attributes, 4, attributes,
1373 attribute_list[i],
1374 (attribute_list[i] | default_attribute)
1376 TEST_PRINTERINFO_INT_EXP(2, attributes, 5, attributes,
1377 attribute_list[i],
1378 (attribute_list[i] | default_attribute)
1380 /* TEST_PRINTERINFO_INT_EXP(4, attributes, 1, flags,
1381 attribute_list[i],
1382 (attribute_list[i] | default_attribute)
1383 ); */
1384 TEST_PRINTERINFO_INT_EXP(4, attributes, 2, attributes,
1385 attribute_list[i],
1386 (attribute_list[i] | default_attribute)
1388 TEST_PRINTERINFO_INT_EXP(4, attributes, 4, attributes,
1389 attribute_list[i],
1390 (attribute_list[i] | default_attribute)
1392 TEST_PRINTERINFO_INT_EXP(4, attributes, 5, attributes,
1393 attribute_list[i],
1394 (attribute_list[i] | default_attribute)
1396 /* TEST_PRINTERINFO_INT_EXP(5, attributes, 1, flags,
1397 attribute_list[i],
1398 (attribute_list[i] | default_attribute)
1399 ); */
1400 TEST_PRINTERINFO_INT_EXP(5, attributes, 2, attributes,
1401 attribute_list[i],
1402 (attribute_list[i] | default_attribute)
1404 TEST_PRINTERINFO_INT_EXP(5, attributes, 4, attributes,
1405 attribute_list[i],
1406 (attribute_list[i] | default_attribute)
1408 TEST_PRINTERINFO_INT_EXP(5, attributes, 5, attributes,
1409 attribute_list[i],
1410 (attribute_list[i] | default_attribute)
1414 for (i=0; i < ARRAY_SIZE(status_list); i++) {
1415 /* level 2 sets do not stick
1416 TEST_PRINTERINFO_INT(2, status, 0, status, status_list[i]);
1417 TEST_PRINTERINFO_INT(2, status, 2, status, status_list[i]);
1418 TEST_PRINTERINFO_INT(2, status, 6, status, status_list[i]); */
1419 TEST_PRINTERINFO_INT(6, status, 0, status, status_list[i]);
1420 TEST_PRINTERINFO_INT(6, status, 2, status, status_list[i]);
1421 TEST_PRINTERINFO_INT(6, status, 6, status, status_list[i]);
1424 /* priorities need to be between 0 and 99
1425 passing an invalid priority will result in WERR_INVALID_PRIORITY */
1426 TEST_PRINTERINFO_INT(2, priority, 2, priority, 0);
1427 TEST_PRINTERINFO_INT(2, priority, 2, priority, 1);
1428 TEST_PRINTERINFO_INT(2, priority, 2, priority, 99);
1429 /* TEST_PRINTERINFO_INT(2, priority, 2, priority, 100); */
1430 TEST_PRINTERINFO_INT(2, defaultpriority,2, defaultpriority, 0);
1431 TEST_PRINTERINFO_INT(2, defaultpriority,2, defaultpriority, 1);
1432 TEST_PRINTERINFO_INT(2, defaultpriority,2, defaultpriority, 99);
1433 /* TEST_PRINTERINFO_INT(2, defaultpriority,2, defaultpriority, 100); */
1435 TEST_PRINTERINFO_INT(2, starttime, 2, starttime, __LINE__);
1436 TEST_PRINTERINFO_INT(2, untiltime, 2, untiltime, __LINE__);
1438 /* does not stick
1439 TEST_PRINTERINFO_INT(2, cjobs, 2, cjobs, __LINE__);
1440 TEST_PRINTERINFO_INT(2, averageppm, 2, averageppm, __LINE__); */
1442 /* does not stick
1443 TEST_PRINTERINFO_INT(5, device_not_selected_timeout, 5, device_not_selected_timeout, __LINE__);
1444 TEST_PRINTERINFO_INT(5, transmission_retry_timeout, 5, transmission_retry_timeout, __LINE__); */
1446 /* FIXME: gd also test devmode and secdesc behavior */
1449 /* verify composition of level 1 description field */
1450 const char *description;
1451 const char *tmp;
1453 q0.in.level = 1;
1454 do { TESTGETCALL(GetPrinter, q0) } while (0);
1456 description = talloc_strdup(tctx, q0.out.info->info1.description);
1458 q0.in.level = 2;
1459 do { TESTGETCALL(GetPrinter, q0) } while (0);
1461 tmp = talloc_asprintf(tctx, "%s,%s,%s",
1462 q0.out.info->info2.printername,
1463 q0.out.info->info2.drivername,
1464 q0.out.info->info2.location);
1466 do { STRING_EQUAL(description, tmp, "description")} while (0);
1469 return ret;
1473 static bool test_ClosePrinter(struct torture_context *tctx,
1474 struct dcerpc_pipe *p,
1475 struct policy_handle *handle)
1477 NTSTATUS status;
1478 struct spoolss_ClosePrinter r;
1480 r.in.handle = handle;
1481 r.out.handle = handle;
1483 torture_comment(tctx, "Testing ClosePrinter\n");
1485 status = dcerpc_spoolss_ClosePrinter(p, tctx, &r);
1486 torture_assert_ntstatus_ok(tctx, status, "ClosePrinter failed");
1487 torture_assert_werr_ok(tctx, r.out.result, "ClosePrinter failed");
1489 return true;
1492 static bool test_GetForm(struct torture_context *tctx,
1493 struct dcerpc_pipe *p,
1494 struct policy_handle *handle,
1495 const char *form_name,
1496 uint32_t level)
1498 NTSTATUS status;
1499 struct spoolss_GetForm r;
1500 uint32_t needed;
1502 r.in.handle = handle;
1503 r.in.form_name = form_name;
1504 r.in.level = level;
1505 r.in.buffer = NULL;
1506 r.in.offered = 0;
1507 r.out.needed = &needed;
1509 torture_comment(tctx, "Testing GetForm level %d\n", r.in.level);
1511 status = dcerpc_spoolss_GetForm(p, tctx, &r);
1512 torture_assert_ntstatus_ok(tctx, status, "GetForm failed");
1514 if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
1515 DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed);
1516 data_blob_clear(&blob);
1517 r.in.buffer = &blob;
1518 r.in.offered = needed;
1519 status = dcerpc_spoolss_GetForm(p, tctx, &r);
1520 torture_assert_ntstatus_ok(tctx, status, "GetForm failed");
1522 torture_assert_werr_ok(tctx, r.out.result, "GetForm failed");
1524 torture_assert(tctx, r.out.info, "No form info returned");
1527 torture_assert_werr_ok(tctx, r.out.result, "GetForm failed");
1529 CHECK_NEEDED_SIZE_LEVEL(spoolss_FormInfo, r.out.info, r.in.level, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
1531 return true;
1534 static bool test_EnumForms(struct torture_context *tctx,
1535 struct dcerpc_pipe *p,
1536 struct policy_handle *handle, bool print_server)
1538 NTSTATUS status;
1539 struct spoolss_EnumForms r;
1540 bool ret = true;
1541 uint32_t needed;
1542 uint32_t count;
1543 uint32_t levels[] = { 1, 2 };
1544 int i;
1546 for (i=0; i<ARRAY_SIZE(levels); i++) {
1548 union spoolss_FormInfo *info;
1550 r.in.handle = handle;
1551 r.in.level = levels[i];
1552 r.in.buffer = NULL;
1553 r.in.offered = 0;
1554 r.out.needed = &needed;
1555 r.out.count = &count;
1556 r.out.info = &info;
1558 torture_comment(tctx, "Testing EnumForms level %d\n", levels[i]);
1560 status = dcerpc_spoolss_EnumForms(p, tctx, &r);
1561 torture_assert_ntstatus_ok(tctx, status, "EnumForms failed");
1563 if ((r.in.level == 2) && (W_ERROR_EQUAL(r.out.result, WERR_UNKNOWN_LEVEL))) {
1564 break;
1567 if (print_server && W_ERROR_EQUAL(r.out.result, WERR_BADFID))
1568 torture_fail(tctx, "EnumForms on the PrintServer isn't supported by test server (NT4)");
1570 if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
1571 int j;
1572 DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed);
1573 data_blob_clear(&blob);
1574 r.in.buffer = &blob;
1575 r.in.offered = needed;
1577 status = dcerpc_spoolss_EnumForms(p, tctx, &r);
1579 torture_assert(tctx, info, "No forms returned");
1581 for (j = 0; j < count; j++) {
1582 if (!print_server)
1583 ret &= test_GetForm(tctx, p, handle, info[j].info1.form_name, levels[i]);
1587 torture_assert_ntstatus_ok(tctx, status, "EnumForms failed");
1589 torture_assert_werr_ok(tctx, r.out.result, "EnumForms failed");
1591 CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumForms, info, r.in.level, count, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
1594 return true;
1597 static bool test_DeleteForm(struct torture_context *tctx,
1598 struct dcerpc_pipe *p,
1599 struct policy_handle *handle,
1600 const char *form_name)
1602 NTSTATUS status;
1603 struct spoolss_DeleteForm r;
1605 r.in.handle = handle;
1606 r.in.form_name = form_name;
1608 status = dcerpc_spoolss_DeleteForm(p, tctx, &r);
1610 torture_assert_ntstatus_ok(tctx, status, "DeleteForm failed");
1612 torture_assert_werr_ok(tctx, r.out.result, "DeleteForm failed");
1614 return true;
1617 static bool test_AddForm(struct torture_context *tctx,
1618 struct dcerpc_pipe *p,
1619 struct policy_handle *handle, bool print_server)
1621 struct spoolss_AddForm r;
1622 struct spoolss_AddFormInfo1 addform;
1623 const char *form_name = "testform3";
1624 NTSTATUS status;
1625 bool ret = true;
1627 r.in.handle = handle;
1628 r.in.level = 1;
1629 r.in.info.info1 = &addform;
1630 addform.flags = SPOOLSS_FORM_USER;
1631 addform.form_name = form_name;
1632 addform.size.width = 50;
1633 addform.size.height = 25;
1634 addform.area.left = 5;
1635 addform.area.top = 10;
1636 addform.area.right = 45;
1637 addform.area.bottom = 15;
1639 status = dcerpc_spoolss_AddForm(p, tctx, &r);
1641 torture_assert_ntstatus_ok(tctx, status, "AddForm failed");
1643 torture_assert_werr_ok(tctx, r.out.result, "AddForm failed");
1645 if (!print_server) ret &= test_GetForm(tctx, p, handle, form_name, 1);
1648 struct spoolss_SetForm sf;
1649 struct spoolss_AddFormInfo1 setform;
1651 sf.in.handle = handle;
1652 sf.in.form_name = form_name;
1653 sf.in.level = 1;
1654 sf.in.info.info1= &setform;
1655 setform.flags = addform.flags;
1656 setform.form_name = addform.form_name;
1657 setform.size = addform.size;
1658 setform.area = addform.area;
1660 setform.size.width = 1234;
1662 status = dcerpc_spoolss_SetForm(p, tctx, &sf);
1664 torture_assert_ntstatus_ok(tctx, status, "SetForm failed");
1666 torture_assert_werr_ok(tctx, r.out.result, "SetForm failed");
1669 if (!print_server) ret &= test_GetForm(tctx, p, handle, form_name, 1);
1672 struct spoolss_EnumForms e;
1673 union spoolss_FormInfo *info;
1674 uint32_t needed;
1675 uint32_t count;
1676 bool found = false;
1678 e.in.handle = handle;
1679 e.in.level = 1;
1680 e.in.buffer = NULL;
1681 e.in.offered = 0;
1682 e.out.needed = &needed;
1683 e.out.count = &count;
1684 e.out.info = &info;
1686 torture_comment(tctx, "Testing EnumForms level 1\n");
1688 status = dcerpc_spoolss_EnumForms(p, tctx, &e);
1689 torture_assert_ntstatus_ok(tctx, status, "EnumForms failed");
1691 if (print_server && W_ERROR_EQUAL(e.out.result, WERR_BADFID))
1692 torture_fail(tctx, "EnumForms on the PrintServer isn't supported by test server (NT4)");
1694 if (W_ERROR_EQUAL(e.out.result, WERR_INSUFFICIENT_BUFFER)) {
1695 int j;
1696 DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed);
1697 data_blob_clear(&blob);
1698 e.in.buffer = &blob;
1699 e.in.offered = needed;
1701 status = dcerpc_spoolss_EnumForms(p, tctx, &e);
1703 torture_assert(tctx, info, "No forms returned");
1705 for (j = 0; j < count; j++) {
1706 if (strequal(form_name, info[j].info1.form_name)) {
1707 found = true;
1708 break;
1712 torture_assert(tctx, found, "Newly added form not found in enum call");
1715 if (!test_DeleteForm(tctx, p, handle, form_name)) {
1716 ret = false;
1719 return ret;
1722 static bool test_EnumPorts_old(struct torture_context *tctx,
1723 struct dcerpc_pipe *p)
1725 NTSTATUS status;
1726 struct spoolss_EnumPorts r;
1727 uint32_t needed;
1728 uint32_t count;
1729 union spoolss_PortInfo *info;
1731 r.in.servername = talloc_asprintf(tctx, "\\\\%s",
1732 dcerpc_server_name(p));
1733 r.in.level = 2;
1734 r.in.buffer = NULL;
1735 r.in.offered = 0;
1736 r.out.needed = &needed;
1737 r.out.count = &count;
1738 r.out.info = &info;
1740 torture_comment(tctx, "Testing EnumPorts\n");
1742 status = dcerpc_spoolss_EnumPorts(p, tctx, &r);
1744 torture_assert_ntstatus_ok(tctx, status, "EnumPorts failed");
1746 if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
1747 DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed);
1748 data_blob_clear(&blob);
1749 r.in.buffer = &blob;
1750 r.in.offered = needed;
1752 status = dcerpc_spoolss_EnumPorts(p, tctx, &r);
1753 torture_assert_ntstatus_ok(tctx, status, "EnumPorts failed");
1754 torture_assert_werr_ok(tctx, r.out.result, "EnumPorts failed");
1756 torture_assert(tctx, info, "No ports returned");
1759 torture_assert_werr_ok(tctx, r.out.result, "EnumPorts failed");
1761 CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumPorts, info, 2, count, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
1763 return true;
1766 static bool test_AddPort(struct torture_context *tctx,
1767 struct dcerpc_pipe *p)
1769 NTSTATUS status;
1770 struct spoolss_AddPort r;
1772 r.in.server_name = talloc_asprintf(tctx, "\\\\%s",
1773 dcerpc_server_name(p));
1774 r.in.unknown = 0;
1775 r.in.monitor_name = "foo";
1777 torture_comment(tctx, "Testing AddPort\n");
1779 status = dcerpc_spoolss_AddPort(p, tctx, &r);
1781 torture_assert_ntstatus_ok(tctx, status, "AddPort failed");
1783 /* win2k3 returns WERR_NOT_SUPPORTED */
1785 #if 0
1787 if (!W_ERROR_IS_OK(r.out.result)) {
1788 printf("AddPort failed - %s\n", win_errstr(r.out.result));
1789 return false;
1792 #endif
1794 return true;
1797 static bool test_GetJob(struct torture_context *tctx,
1798 struct dcerpc_pipe *p,
1799 struct policy_handle *handle, uint32_t job_id)
1801 NTSTATUS status;
1802 struct spoolss_GetJob r;
1803 union spoolss_JobInfo info;
1804 uint32_t needed;
1805 uint32_t levels[] = {1, 2 /* 3, 4 */};
1806 uint32_t i;
1808 r.in.handle = handle;
1809 r.in.job_id = job_id;
1810 r.in.level = 0;
1811 r.in.buffer = NULL;
1812 r.in.offered = 0;
1813 r.out.needed = &needed;
1814 r.out.info = &info;
1816 torture_comment(tctx, "Testing GetJob level %d\n", r.in.level);
1818 status = dcerpc_spoolss_GetJob(p, tctx, &r);
1819 torture_assert_werr_equal(tctx, r.out.result, WERR_UNKNOWN_LEVEL, "Unexpected return code");
1821 for (i = 0; i < ARRAY_SIZE(levels); i++) {
1823 torture_comment(tctx, "Testing GetJob level %d\n", r.in.level);
1825 needed = 0;
1827 r.in.level = levels[i];
1828 r.in.offered = 0;
1829 r.in.buffer = NULL;
1831 status = dcerpc_spoolss_GetJob(p, tctx, &r);
1832 torture_assert_ntstatus_ok(tctx, status, "GetJob failed");
1834 if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
1835 DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed);
1836 data_blob_clear(&blob);
1837 r.in.buffer = &blob;
1838 r.in.offered = needed;
1840 status = dcerpc_spoolss_GetJob(p, tctx, &r);
1841 torture_assert_ntstatus_ok(tctx, status, "GetJob failed");
1844 torture_assert(tctx, r.out.info, "No job info returned");
1845 torture_assert_werr_ok(tctx, r.out.result, "GetJob failed");
1847 CHECK_NEEDED_SIZE_LEVEL(spoolss_JobInfo, r.out.info, r.in.level, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
1850 return true;
1853 static bool test_SetJob(struct torture_context *tctx,
1854 struct dcerpc_pipe *p,
1855 struct policy_handle *handle, uint32_t job_id,
1856 enum spoolss_JobControl command)
1858 NTSTATUS status;
1859 struct spoolss_SetJob r;
1861 r.in.handle = handle;
1862 r.in.job_id = job_id;
1863 r.in.ctr = NULL;
1864 r.in.command = command;
1866 switch (command) {
1867 case SPOOLSS_JOB_CONTROL_PAUSE:
1868 torture_comment(tctx, "Testing SetJob: SPOOLSS_JOB_CONTROL_PAUSE\n");
1869 break;
1870 case SPOOLSS_JOB_CONTROL_RESUME:
1871 torture_comment(tctx, "Testing SetJob: SPOOLSS_JOB_CONTROL_RESUME\n");
1872 break;
1873 case SPOOLSS_JOB_CONTROL_CANCEL:
1874 torture_comment(tctx, "Testing SetJob: SPOOLSS_JOB_CONTROL_CANCEL\n");
1875 break;
1876 case SPOOLSS_JOB_CONTROL_RESTART:
1877 torture_comment(tctx, "Testing SetJob: SPOOLSS_JOB_CONTROL_RESTART\n");
1878 break;
1879 case SPOOLSS_JOB_CONTROL_DELETE:
1880 torture_comment(tctx, "Testing SetJob: SPOOLSS_JOB_CONTROL_DELETE\n");
1881 break;
1882 case SPOOLSS_JOB_CONTROL_SEND_TO_PRINTER:
1883 torture_comment(tctx, "Testing SetJob: SPOOLSS_JOB_CONTROL_SEND_TO_PRINTER\n");
1884 break;
1885 case SPOOLSS_JOB_CONTROL_LAST_PAGE_EJECTED:
1886 torture_comment(tctx, "Testing SetJob: SPOOLSS_JOB_CONTROL_LAST_PAGE_EJECTED\n");
1887 break;
1888 case SPOOLSS_JOB_CONTROL_RETAIN:
1889 torture_comment(tctx, "Testing SetJob: SPOOLSS_JOB_CONTROL_RETAIN\n");
1890 break;
1891 case SPOOLSS_JOB_CONTROL_RELEASE:
1892 torture_comment(tctx, "Testing SetJob: SPOOLSS_JOB_CONTROL_RELEASE\n");
1893 break;
1894 default:
1895 torture_comment(tctx, "Testing SetJob\n");
1896 break;
1899 status = dcerpc_spoolss_SetJob(p, tctx, &r);
1900 torture_assert_ntstatus_ok(tctx, status, "SetJob failed");
1901 torture_assert_werr_ok(tctx, r.out.result, "SetJob failed");
1903 return true;
1906 static bool test_AddJob(struct torture_context *tctx,
1907 struct dcerpc_pipe *p,
1908 struct policy_handle *handle)
1910 NTSTATUS status;
1911 struct spoolss_AddJob r;
1912 uint32_t needed;
1914 r.in.level = 0;
1915 r.in.handle = handle;
1916 r.in.offered = 0;
1917 r.out.needed = &needed;
1918 r.in.buffer = r.out.buffer = NULL;
1920 torture_comment(tctx, "Testing AddJob\n");
1922 status = dcerpc_spoolss_AddJob(p, tctx, &r);
1923 torture_assert_werr_equal(tctx, r.out.result, WERR_UNKNOWN_LEVEL, "AddJob failed");
1925 r.in.level = 1;
1927 status = dcerpc_spoolss_AddJob(p, tctx, &r);
1928 torture_assert_werr_equal(tctx, r.out.result, WERR_INVALID_PARAM, "AddJob failed");
1930 return true;
1934 static bool test_EnumJobs(struct torture_context *tctx,
1935 struct dcerpc_pipe *p,
1936 struct policy_handle *handle)
1938 NTSTATUS status;
1939 struct spoolss_EnumJobs r;
1940 uint32_t needed;
1941 uint32_t count;
1942 union spoolss_JobInfo *info;
1944 r.in.handle = handle;
1945 r.in.firstjob = 0;
1946 r.in.numjobs = 0xffffffff;
1947 r.in.level = 1;
1948 r.in.buffer = NULL;
1949 r.in.offered = 0;
1950 r.out.needed = &needed;
1951 r.out.count = &count;
1952 r.out.info = &info;
1954 torture_comment(tctx, "Testing EnumJobs\n");
1956 status = dcerpc_spoolss_EnumJobs(p, tctx, &r);
1958 torture_assert_ntstatus_ok(tctx, status, "EnumJobs failed");
1960 if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
1961 int j;
1962 DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed);
1963 data_blob_clear(&blob);
1964 r.in.buffer = &blob;
1965 r.in.offered = needed;
1967 status = dcerpc_spoolss_EnumJobs(p, tctx, &r);
1969 torture_assert_ntstatus_ok(tctx, status, "EnumJobs failed");
1970 torture_assert_werr_ok(tctx, r.out.result, "EnumJobs failed");
1971 torture_assert(tctx, info, "No jobs returned");
1973 CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumJobs, *r.out.info, r.in.level, count, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
1975 for (j = 0; j < count; j++) {
1977 torture_assert(tctx, test_GetJob(tctx, p, handle, info[j].info1.job_id),
1978 "failed to call test_GetJob");
1980 /* FIXME - gd */
1981 if (!torture_setting_bool(tctx, "samba3", false)) {
1982 test_SetJob(tctx, p, handle, info[j].info1.job_id, SPOOLSS_JOB_CONTROL_PAUSE);
1983 test_SetJob(tctx, p, handle, info[j].info1.job_id, SPOOLSS_JOB_CONTROL_RESUME);
1987 } else {
1988 torture_assert_werr_ok(tctx, r.out.result, "EnumJobs failed");
1991 return true;
1994 static bool test_DoPrintTest(struct torture_context *tctx,
1995 struct dcerpc_pipe *p,
1996 struct policy_handle *handle)
1998 bool ret = true;
1999 NTSTATUS status;
2000 struct spoolss_StartDocPrinter s;
2001 struct spoolss_DocumentInfo1 info1;
2002 struct spoolss_StartPagePrinter sp;
2003 struct spoolss_WritePrinter w;
2004 struct spoolss_EndPagePrinter ep;
2005 struct spoolss_EndDocPrinter e;
2006 int i;
2007 uint32_t job_id;
2008 uint32_t num_written;
2010 torture_comment(tctx, "Testing StartDocPrinter\n");
2012 s.in.handle = handle;
2013 s.in.level = 1;
2014 s.in.info.info1 = &info1;
2015 s.out.job_id = &job_id;
2016 info1.document_name = "TorturePrintJob";
2017 info1.output_file = NULL;
2018 info1.datatype = "RAW";
2020 status = dcerpc_spoolss_StartDocPrinter(p, tctx, &s);
2021 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_StartDocPrinter failed");
2022 torture_assert_werr_ok(tctx, s.out.result, "StartDocPrinter failed");
2024 for (i=1; i < 4; i++) {
2025 torture_comment(tctx, "Testing StartPagePrinter: Page[%d]\n", i);
2027 sp.in.handle = handle;
2029 status = dcerpc_spoolss_StartPagePrinter(p, tctx, &sp);
2030 torture_assert_ntstatus_ok(tctx, status,
2031 "dcerpc_spoolss_StartPagePrinter failed");
2032 torture_assert_werr_ok(tctx, sp.out.result, "StartPagePrinter failed");
2034 torture_comment(tctx, "Testing WritePrinter: Page[%d]\n", i);
2036 w.in.handle = handle;
2037 w.in.data = data_blob_string_const(talloc_asprintf(tctx,"TortureTestPage: %d\nData\n",i));
2038 w.out.num_written = &num_written;
2040 status = dcerpc_spoolss_WritePrinter(p, tctx, &w);
2041 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_WritePrinter failed");
2042 torture_assert_werr_ok(tctx, w.out.result, "WritePrinter failed");
2044 torture_comment(tctx, "Testing EndPagePrinter: Page[%d]\n", i);
2046 ep.in.handle = handle;
2048 status = dcerpc_spoolss_EndPagePrinter(p, tctx, &ep);
2049 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EndPagePrinter failed");
2050 torture_assert_werr_ok(tctx, ep.out.result, "EndPagePrinter failed");
2053 torture_comment(tctx, "Testing EndDocPrinter\n");
2055 e.in.handle = handle;
2057 status = dcerpc_spoolss_EndDocPrinter(p, tctx, &e);
2058 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EndDocPrinter failed");
2059 torture_assert_werr_ok(tctx, e.out.result, "EndDocPrinter failed");
2061 ret &= test_AddJob(tctx, p, handle);
2062 ret &= test_EnumJobs(tctx, p, handle);
2064 ret &= test_SetJob(tctx, p, handle, job_id, SPOOLSS_JOB_CONTROL_DELETE);
2066 return ret;
2069 static bool test_PausePrinter(struct torture_context *tctx,
2070 struct dcerpc_pipe *p,
2071 struct policy_handle *handle)
2073 NTSTATUS status;
2074 struct spoolss_SetPrinter r;
2075 struct spoolss_SetPrinterInfoCtr info_ctr;
2076 struct spoolss_DevmodeContainer devmode_ctr;
2077 struct sec_desc_buf secdesc_ctr;
2079 info_ctr.level = 0;
2080 info_ctr.info.info0 = NULL;
2082 ZERO_STRUCT(devmode_ctr);
2083 ZERO_STRUCT(secdesc_ctr);
2085 r.in.handle = handle;
2086 r.in.info_ctr = &info_ctr;
2087 r.in.devmode_ctr = &devmode_ctr;
2088 r.in.secdesc_ctr = &secdesc_ctr;
2089 r.in.command = SPOOLSS_PRINTER_CONTROL_PAUSE;
2091 torture_comment(tctx, "Testing SetPrinter: SPOOLSS_PRINTER_CONTROL_PAUSE\n");
2093 status = dcerpc_spoolss_SetPrinter(p, tctx, &r);
2095 torture_assert_ntstatus_ok(tctx, status, "SetPrinter failed");
2097 torture_assert_werr_ok(tctx, r.out.result, "SetPrinter failed");
2099 return true;
2102 static bool test_ResumePrinter(struct torture_context *tctx,
2103 struct dcerpc_pipe *p,
2104 struct policy_handle *handle)
2106 NTSTATUS status;
2107 struct spoolss_SetPrinter r;
2108 struct spoolss_SetPrinterInfoCtr info_ctr;
2109 struct spoolss_DevmodeContainer devmode_ctr;
2110 struct sec_desc_buf secdesc_ctr;
2112 info_ctr.level = 0;
2113 info_ctr.info.info0 = NULL;
2115 ZERO_STRUCT(devmode_ctr);
2116 ZERO_STRUCT(secdesc_ctr);
2118 r.in.handle = handle;
2119 r.in.info_ctr = &info_ctr;
2120 r.in.devmode_ctr = &devmode_ctr;
2121 r.in.secdesc_ctr = &secdesc_ctr;
2122 r.in.command = SPOOLSS_PRINTER_CONTROL_RESUME;
2124 torture_comment(tctx, "Testing SetPrinter: SPOOLSS_PRINTER_CONTROL_RESUME\n");
2126 status = dcerpc_spoolss_SetPrinter(p, tctx, &r);
2128 torture_assert_ntstatus_ok(tctx, status, "SetPrinter failed");
2130 torture_assert_werr_ok(tctx, r.out.result, "SetPrinter failed");
2132 return true;
2135 static bool test_GetPrinterData(struct torture_context *tctx,
2136 struct dcerpc_pipe *p,
2137 struct policy_handle *handle,
2138 const char *value_name,
2139 enum winreg_Type *type_p,
2140 union spoolss_PrinterData *data_p)
2142 NTSTATUS status;
2143 struct spoolss_GetPrinterData r;
2144 uint32_t needed;
2145 enum winreg_Type type;
2146 union spoolss_PrinterData data;
2148 r.in.handle = handle;
2149 r.in.value_name = value_name;
2150 r.in.offered = 0;
2151 r.out.needed = &needed;
2152 r.out.type = &type;
2153 r.out.data = &data;
2155 torture_comment(tctx, "Testing GetPrinterData(%s)\n", r.in.value_name);
2157 status = dcerpc_spoolss_GetPrinterData(p, tctx, &r);
2158 torture_assert_ntstatus_ok(tctx, status, "GetPrinterData failed");
2160 if (W_ERROR_EQUAL(r.out.result, WERR_MORE_DATA)) {
2161 r.in.offered = needed;
2163 status = dcerpc_spoolss_GetPrinterData(p, tctx, &r);
2164 torture_assert_ntstatus_ok(tctx, status, "GetPrinterData failed");
2167 torture_assert_werr_ok(tctx, r.out.result,
2168 talloc_asprintf(tctx, "GetPrinterData(%s) failed", r.in.value_name));
2170 CHECK_NEEDED_SIZE_LEVEL(spoolss_PrinterData, &data, type, lp_iconv_convenience(tctx->lp_ctx), needed, 1);
2172 if (type_p) {
2173 *type_p = type;
2176 if (data_p) {
2177 *data_p = data;
2180 return true;
2183 static bool test_GetPrinterDataEx(struct torture_context *tctx,
2184 struct dcerpc_pipe *p,
2185 struct policy_handle *handle,
2186 const char *key_name,
2187 const char *value_name,
2188 enum winreg_Type *type_p,
2189 union spoolss_PrinterData *data_p)
2191 NTSTATUS status;
2192 struct spoolss_GetPrinterDataEx r;
2193 enum winreg_Type type;
2194 uint32_t needed;
2195 union spoolss_PrinterData data;
2197 r.in.handle = handle;
2198 r.in.key_name = key_name;
2199 r.in.value_name = value_name;
2200 r.in.offered = 0;
2201 r.out.type = &type;
2202 r.out.needed = &needed;
2203 r.out.data = &data;
2205 torture_comment(tctx, "Testing GetPrinterDataEx(%s - %s)\n",
2206 r.in.key_name, r.in.value_name);
2208 status = dcerpc_spoolss_GetPrinterDataEx(p, tctx, &r);
2209 if (!NT_STATUS_IS_OK(status)) {
2210 if (NT_STATUS_EQUAL(status,NT_STATUS_NET_WRITE_FAULT) &&
2211 p->last_fault_code == DCERPC_FAULT_OP_RNG_ERROR) {
2212 torture_skip(tctx, "GetPrinterDataEx not supported by server\n");
2214 torture_assert_ntstatus_ok(tctx, status, "GetPrinterDataEx failed");
2217 if (W_ERROR_EQUAL(r.out.result, WERR_MORE_DATA)) {
2218 r.in.offered = needed;
2219 status = dcerpc_spoolss_GetPrinterDataEx(p, tctx, &r);
2220 torture_assert_ntstatus_ok(tctx, status, "GetPrinterDataEx failed");
2223 torture_assert_werr_ok(tctx, r.out.result,
2224 talloc_asprintf(tctx, "GetPrinterDataEx(%s - %s) failed", r.in.key_name, r.in.value_name));
2226 CHECK_NEEDED_SIZE_LEVEL(spoolss_PrinterData, &data, type, lp_iconv_convenience(tctx->lp_ctx), needed, 1);
2228 if (type_p) {
2229 *type_p = type;
2232 if (data_p) {
2233 *data_p = data;
2236 return true;
2239 static bool test_GetPrinterData_list(struct torture_context *tctx,
2240 struct dcerpc_pipe *p,
2241 struct policy_handle *handle)
2243 const char *list[] = {
2244 "W3SvcInstalled",
2245 "BeepEnabled",
2246 "EventLog",
2247 /* "NetPopup", not on w2k8 */
2248 /* "NetPopupToComputer", not on w2k8 */
2249 "MajorVersion",
2250 "MinorVersion",
2251 "DefaultSpoolDirectory",
2252 "Architecture",
2253 "DsPresent",
2254 "OSVersion",
2255 /* "OSVersionEx", not on s3 */
2256 "DNSMachineName"
2258 int i;
2260 for (i=0; i < ARRAY_SIZE(list); i++) {
2261 enum winreg_Type type, type_ex;
2262 union spoolss_PrinterData data, data_ex;
2264 torture_assert(tctx, test_GetPrinterData(tctx, p, handle, list[i], &type, &data),
2265 talloc_asprintf(tctx, "GetPrinterData failed on %s\n", list[i]));
2266 torture_assert(tctx, test_GetPrinterDataEx(tctx, p, handle, "random_string", list[i], &type_ex, &data_ex),
2267 talloc_asprintf(tctx, "GetPrinterDataEx failed on %s\n", list[i]));
2268 torture_assert_int_equal(tctx, type, type_ex, "type mismatch");
2269 switch (type) {
2270 case REG_SZ:
2271 torture_assert_str_equal(tctx, data.string, data_ex.string, "REG_SZ mismatch");
2272 break;
2273 case REG_DWORD:
2274 torture_assert_int_equal(tctx, data.value, data_ex.value, "REG_DWORD mismatch");
2275 break;
2276 case REG_BINARY:
2277 torture_assert_data_blob_equal(tctx, data.binary, data_ex.binary, "REG_BINARY mismatch");
2278 break;
2279 default:
2280 break;
2284 return true;
2287 static bool test_EnumPrinterData(struct torture_context *tctx, struct dcerpc_pipe *p,
2288 struct policy_handle *handle)
2290 NTSTATUS status;
2291 struct spoolss_EnumPrinterData r;
2293 ZERO_STRUCT(r);
2294 r.in.handle = handle;
2295 r.in.enum_index = 0;
2297 do {
2298 uint32_t value_size = 0;
2299 uint32_t data_size = 0;
2300 enum winreg_Type type = 0;
2302 r.in.value_offered = value_size;
2303 r.out.value_needed = &value_size;
2304 r.in.data_offered = data_size;
2305 r.out.data_needed = &data_size;
2307 r.out.type = &type;
2308 r.out.data = talloc_zero_array(tctx, uint8_t, 0);
2310 torture_comment(tctx, "Testing EnumPrinterData\n");
2312 status = dcerpc_spoolss_EnumPrinterData(p, tctx, &r);
2314 torture_assert_ntstatus_ok(tctx, status, "EnumPrinterData failed");
2315 if (W_ERROR_EQUAL(r.out.result, WERR_NO_MORE_ITEMS)) {
2316 break;
2318 torture_assert_werr_ok(tctx, r.out.result, "EnumPrinterData");
2320 r.in.value_offered = value_size;
2321 r.out.value_name = talloc_zero_array(tctx, const char, value_size);
2322 r.in.data_offered = data_size;
2323 r.out.data = talloc_zero_array(tctx, uint8_t, data_size);
2325 status = dcerpc_spoolss_EnumPrinterData(p, tctx, &r);
2327 torture_assert_ntstatus_ok(tctx, status, "EnumPrinterData failed");
2328 if (W_ERROR_EQUAL(r.out.result, WERR_NO_MORE_ITEMS)) {
2329 break;
2332 torture_assert_werr_ok(tctx, r.out.result, "EnumPrinterData failed");
2334 torture_assert(tctx, test_GetPrinterData(tctx, p, handle, r.out.value_name, NULL, NULL),
2335 talloc_asprintf(tctx, "failed to call GetPrinterData for %s\n", r.out.value_name));
2337 torture_assert(tctx, test_GetPrinterDataEx(tctx, p, handle, "PrinterDriverData", r.out.value_name, NULL, NULL),
2338 talloc_asprintf(tctx, "failed to call GetPrinterDataEx on PrinterDriverData for %s\n", r.out.value_name));
2340 r.in.enum_index++;
2342 } while (W_ERROR_IS_OK(r.out.result));
2344 return true;
2347 static bool test_EnumPrinterDataEx(struct torture_context *tctx,
2348 struct dcerpc_pipe *p,
2349 struct policy_handle *handle,
2350 const char *key_name)
2352 struct spoolss_EnumPrinterDataEx r;
2353 struct spoolss_PrinterEnumValues *info;
2354 uint32_t needed;
2355 uint32_t count;
2357 r.in.handle = handle;
2358 r.in.key_name = key_name;
2359 r.in.offered = 0;
2360 r.out.needed = &needed;
2361 r.out.count = &count;
2362 r.out.info = &info;
2364 torture_comment(tctx, "Testing EnumPrinterDataEx(%s)\n", key_name);
2366 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_EnumPrinterDataEx(p, tctx, &r),
2367 "EnumPrinterDataEx failed");
2368 if (W_ERROR_EQUAL(r.out.result, WERR_MORE_DATA)) {
2369 r.in.offered = needed;
2370 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_EnumPrinterDataEx(p, tctx, &r),
2371 "EnumPrinterDataEx failed");
2374 torture_assert_werr_ok(tctx, r.out.result, "EnumPrinterDataEx failed");
2376 CHECK_NEEDED_SIZE_ENUM(spoolss_EnumPrinterDataEx, info, count, lp_iconv_convenience(tctx->lp_ctx), needed, 1);
2378 return true;
2382 static bool test_DeletePrinterData(struct torture_context *tctx,
2383 struct dcerpc_pipe *p,
2384 struct policy_handle *handle,
2385 const char *value_name)
2387 NTSTATUS status;
2388 struct spoolss_DeletePrinterData r;
2390 r.in.handle = handle;
2391 r.in.value_name = value_name;
2393 torture_comment(tctx, "Testing DeletePrinterData(%s)\n",
2394 r.in.value_name);
2396 status = dcerpc_spoolss_DeletePrinterData(p, tctx, &r);
2398 torture_assert_ntstatus_ok(tctx, status, "DeletePrinterData failed");
2399 torture_assert_werr_ok(tctx, r.out.result, "DeletePrinterData failed");
2401 return true;
2404 static bool test_DeletePrinterDataEx(struct torture_context *tctx,
2405 struct dcerpc_pipe *p,
2406 struct policy_handle *handle,
2407 const char *key_name,
2408 const char *value_name)
2410 struct spoolss_DeletePrinterDataEx r;
2412 r.in.handle = handle;
2413 r.in.key_name = key_name;
2414 r.in.value_name = value_name;
2416 torture_comment(tctx, "Testing DeletePrinterDataEx(%s - %s)\n",
2417 r.in.key_name, r.in.value_name);
2419 torture_assert_ntstatus_ok(tctx,
2420 dcerpc_spoolss_DeletePrinterDataEx(p, tctx, &r),
2421 "DeletePrinterDataEx failed");
2422 torture_assert_werr_ok(tctx, r.out.result,
2423 "DeletePrinterDataEx failed");
2425 return true;
2428 static bool test_DeletePrinterKey(struct torture_context *tctx,
2429 struct dcerpc_pipe *p,
2430 struct policy_handle *handle,
2431 const char *key_name)
2433 struct spoolss_DeletePrinterKey r;
2435 r.in.handle = handle;
2436 r.in.key_name = key_name;
2438 torture_comment(tctx, "Testing DeletePrinterKey(%s)\n", r.in.key_name);
2440 if (strequal(key_name, "") && !torture_setting_bool(tctx, "dangerous", false)) {
2441 torture_skip(tctx, "not wiping out printer registry - enable dangerous tests to use\n");
2442 return true;
2445 torture_assert_ntstatus_ok(tctx,
2446 dcerpc_spoolss_DeletePrinterKey(p, tctx, &r),
2447 "DeletePrinterKey failed");
2448 torture_assert_werr_ok(tctx, r.out.result,
2449 "DeletePrinterKey failed");
2451 return true;
2454 static bool test_SetPrinterData(struct torture_context *tctx,
2455 struct dcerpc_pipe *p,
2456 struct policy_handle *handle)
2458 NTSTATUS status;
2459 struct spoolss_SetPrinterData r;
2460 const char *values[] = {
2461 "spootyfoot",
2462 "spooty\\foot",
2463 #if 0
2464 /* FIXME: not working with s3 atm. */
2465 "spooty,foot",
2466 "spooty,fo,ot",
2467 #endif
2468 "spooty foot",
2469 #if 0
2470 /* FIXME: not working with s3 atm. */
2471 "spooty\\fo,ot",
2472 "spooty,fo\\ot"
2473 #endif
2475 int i;
2477 for (i=0; i < ARRAY_SIZE(values); i++) {
2479 enum winreg_Type type;
2480 union spoolss_PrinterData data;
2482 r.in.handle = handle;
2483 r.in.value_name = values[i];
2484 r.in.type = REG_SZ;
2485 r.in.data.string = "dog";
2487 torture_comment(tctx, "Testing SetPrinterData(%s)\n",
2488 r.in.value_name);
2490 status = dcerpc_spoolss_SetPrinterData(p, tctx, &r);
2492 torture_assert_ntstatus_ok(tctx, status, "SetPrinterData failed");
2493 torture_assert_werr_ok(tctx, r.out.result, "SetPrinterData failed");
2495 if (!test_GetPrinterData(tctx, p, handle, r.in.value_name, &type, &data)) {
2496 return false;
2499 torture_assert_int_equal(tctx, r.in.type, type, "type mismatch");
2500 torture_assert_str_equal(tctx, r.in.data.string, data.string, "data mismatch");
2502 if (!test_DeletePrinterData(tctx, p, handle, r.in.value_name)) {
2503 return false;
2507 return true;
2510 static bool test_EnumPrinterKey(struct torture_context *tctx,
2511 struct dcerpc_pipe *p,
2512 struct policy_handle *handle,
2513 const char *key_name,
2514 const char ***array);
2516 static bool test_SetPrinterDataEx(struct torture_context *tctx,
2517 struct dcerpc_pipe *p,
2518 struct policy_handle *handle)
2520 NTSTATUS status;
2521 struct spoolss_SetPrinterDataEx r;
2522 const char *value_name = "dog";
2523 const char *keys[] = {
2524 "torturedataex",
2525 "torture data ex",
2526 #if 0
2527 /* FIXME: not working with s3 atm. */
2528 "torturedataex_with_subkey\\subkey",
2529 "torturedataex_with_subkey\\subkey:0",
2530 "torturedataex_with_subkey\\subkey:1",
2531 "torturedataex_with_subkey\\subkey\\subsubkey",
2532 "torturedataex_with_subkey\\subkey\\subsubkey:0",
2533 "torturedataex_with_subkey\\subkey\\subsubkey:1",
2534 #endif
2535 "torture,data",
2536 #if 0
2537 /* FIXME: not working with s3 atm. */
2539 "torture,data,ex",
2540 "torture,data\\ex",
2541 "torture\\data,ex"
2542 #endif
2544 int i;
2545 DATA_BLOB blob = data_blob_string_const("catfoobar");
2548 for (i=0; i < ARRAY_SIZE(keys); i++) {
2550 char *c;
2551 const char *key;
2552 enum winreg_Type type;
2553 const char **subkeys;
2554 union spoolss_PrinterData data;
2556 r.in.handle = handle;
2557 r.in.key_name = keys[i];
2558 r.in.value_name = value_name;
2559 r.in.type = REG_BINARY;
2560 r.in.data.binary = blob;
2562 torture_comment(tctx, "Testing SetPrinterDataEx(%s - %s)\n", r.in.key_name, value_name);
2564 status = dcerpc_spoolss_SetPrinterDataEx(p, tctx, &r);
2566 torture_assert_ntstatus_ok(tctx, status, "SetPrinterDataEx failed");
2567 torture_assert_werr_ok(tctx, r.out.result, "SetPrinterDataEx failed");
2569 key = talloc_strdup(tctx, r.in.key_name);
2571 if (!test_GetPrinterDataEx(tctx, p, handle, r.in.key_name, value_name, &type, &data)) {
2572 return false;
2575 torture_assert_int_equal(tctx, r.in.type, type, "type mismatch");
2576 torture_assert_data_blob_equal(tctx, blob, data.binary, "data mismatch");
2578 if (!test_EnumPrinterDataEx(tctx, p, handle, r.in.key_name)) {
2579 return false;
2582 if (!test_DeletePrinterDataEx(tctx, p, handle, r.in.key_name, value_name)) {
2583 return false;
2586 c = strchr(key, '\\');
2587 if (c) {
2588 int i;
2590 /* we have subkeys */
2592 *c = 0;
2594 if (!test_EnumPrinterKey(tctx, p, handle, key, &subkeys)) {
2595 return false;
2598 for (i=0; subkeys && subkeys[i]; i++) {
2600 const char *current_key = talloc_asprintf(tctx, "%s\\%s", key, subkeys[i]);
2602 if (!test_DeletePrinterKey(tctx, p, handle, current_key)) {
2603 return false;
2607 if (!test_DeletePrinterKey(tctx, p, handle, key)) {
2608 return false;
2611 } else {
2612 if (!test_DeletePrinterKey(tctx, p, handle, key)) {
2613 return false;
2618 return true;
2622 static bool test_SecondaryClosePrinter(struct torture_context *tctx,
2623 struct dcerpc_pipe *p,
2624 struct policy_handle *handle)
2626 NTSTATUS status;
2627 struct dcerpc_binding *b;
2628 struct dcerpc_pipe *p2;
2629 struct spoolss_ClosePrinter cp;
2631 /* only makes sense on SMB */
2632 if (p->conn->transport.transport != NCACN_NP) {
2633 return true;
2636 torture_comment(tctx, "testing close on secondary pipe\n");
2638 status = dcerpc_parse_binding(tctx, p->conn->binding_string, &b);
2639 torture_assert_ntstatus_ok(tctx, status, "Failed to parse dcerpc binding");
2641 status = dcerpc_secondary_connection(p, &p2, b);
2642 torture_assert_ntstatus_ok(tctx, status, "Failed to create secondary connection");
2644 status = dcerpc_bind_auth_none(p2, &ndr_table_spoolss);
2645 torture_assert_ntstatus_ok(tctx, status, "Failed to create bind on secondary connection");
2647 cp.in.handle = handle;
2648 cp.out.handle = handle;
2650 status = dcerpc_spoolss_ClosePrinter(p2, tctx, &cp);
2651 torture_assert_ntstatus_equal(tctx, status, NT_STATUS_NET_WRITE_FAULT,
2652 "ERROR: Allowed close on secondary connection");
2654 torture_assert_int_equal(tctx, p2->last_fault_code, DCERPC_FAULT_CONTEXT_MISMATCH,
2655 "Unexpected fault code");
2657 talloc_free(p2);
2659 return true;
2662 static bool test_OpenPrinter_badname(struct torture_context *tctx,
2663 struct dcerpc_pipe *p, const char *name)
2665 NTSTATUS status;
2666 struct spoolss_OpenPrinter op;
2667 struct spoolss_OpenPrinterEx opEx;
2668 struct policy_handle handle;
2669 bool ret = true;
2671 op.in.printername = name;
2672 op.in.datatype = NULL;
2673 op.in.devmode_ctr.devmode= NULL;
2674 op.in.access_mask = 0;
2675 op.out.handle = &handle;
2677 torture_comment(tctx, "\nTesting OpenPrinter(%s) with bad name\n", op.in.printername);
2679 status = dcerpc_spoolss_OpenPrinter(p, tctx, &op);
2680 torture_assert_ntstatus_ok(tctx, status, "OpenPrinter failed");
2681 if (!W_ERROR_EQUAL(WERR_INVALID_PRINTER_NAME,op.out.result)) {
2682 torture_comment(tctx, "OpenPrinter(%s) unexpected result[%s] should be WERR_INVALID_PRINTER_NAME\n",
2683 name, win_errstr(op.out.result));
2686 if (W_ERROR_IS_OK(op.out.result)) {
2687 ret &=test_ClosePrinter(tctx, p, &handle);
2690 opEx.in.printername = name;
2691 opEx.in.datatype = NULL;
2692 opEx.in.devmode_ctr.devmode = NULL;
2693 opEx.in.access_mask = 0;
2694 opEx.in.level = 1;
2695 opEx.in.userlevel.level1 = NULL;
2696 opEx.out.handle = &handle;
2698 torture_comment(tctx, "Testing OpenPrinterEx(%s) with bad name\n", opEx.in.printername);
2700 status = dcerpc_spoolss_OpenPrinterEx(p, tctx, &opEx);
2701 torture_assert_ntstatus_ok(tctx, status, "OpenPrinterEx failed");
2702 if (!W_ERROR_EQUAL(WERR_INVALID_PARAM,opEx.out.result)) {
2703 torture_comment(tctx, "OpenPrinterEx(%s) unexpected result[%s] should be WERR_INVALID_PARAM\n",
2704 name, win_errstr(opEx.out.result));
2707 if (W_ERROR_IS_OK(opEx.out.result)) {
2708 ret &=test_ClosePrinter(tctx, p, &handle);
2711 return ret;
2714 static bool test_OpenPrinter(struct torture_context *tctx,
2715 struct dcerpc_pipe *p,
2716 const char *name)
2718 NTSTATUS status;
2719 struct spoolss_OpenPrinter r;
2720 struct policy_handle handle;
2721 bool ret = true;
2723 r.in.printername = talloc_asprintf(tctx, "\\\\%s\\%s", dcerpc_server_name(p), name);
2724 r.in.datatype = NULL;
2725 r.in.devmode_ctr.devmode= NULL;
2726 r.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
2727 r.out.handle = &handle;
2729 torture_comment(tctx, "Testing OpenPrinter(%s)\n", r.in.printername);
2731 status = dcerpc_spoolss_OpenPrinter(p, tctx, &r);
2733 torture_assert_ntstatus_ok(tctx, status, "OpenPrinter failed");
2735 torture_assert_werr_ok(tctx, r.out.result, "OpenPrinter failed");
2737 if (!test_GetPrinter(tctx, p, &handle)) {
2738 ret = false;
2741 if (!torture_setting_bool(tctx, "samba3", false)) {
2742 if (!test_SecondaryClosePrinter(tctx, p, &handle)) {
2743 ret = false;
2747 if (!test_ClosePrinter(tctx, p, &handle)) {
2748 ret = false;
2751 return ret;
2754 static bool call_OpenPrinterEx(struct torture_context *tctx,
2755 struct dcerpc_pipe *p,
2756 const char *name, struct policy_handle *handle)
2758 struct spoolss_OpenPrinterEx r;
2759 struct spoolss_UserLevel1 userlevel1;
2760 NTSTATUS status;
2762 if (name && name[0]) {
2763 r.in.printername = talloc_asprintf(tctx, "\\\\%s\\%s",
2764 dcerpc_server_name(p), name);
2765 } else {
2766 r.in.printername = talloc_asprintf(tctx, "\\\\%s",
2767 dcerpc_server_name(p));
2770 r.in.datatype = NULL;
2771 r.in.devmode_ctr.devmode= NULL;
2772 r.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
2773 r.in.level = 1;
2774 r.in.userlevel.level1 = &userlevel1;
2775 r.out.handle = handle;
2777 userlevel1.size = 1234;
2778 userlevel1.client = "hello";
2779 userlevel1.user = "spottyfoot!";
2780 userlevel1.build = 1;
2781 userlevel1.major = 2;
2782 userlevel1.minor = 3;
2783 userlevel1.processor = 4;
2785 torture_comment(tctx, "Testing OpenPrinterEx(%s)\n", r.in.printername);
2787 status = dcerpc_spoolss_OpenPrinterEx(p, tctx, &r);
2789 torture_assert_ntstatus_ok(tctx, status, "OpenPrinterEx failed");
2791 torture_assert_werr_ok(tctx, r.out.result, "OpenPrinterEx failed");
2793 return true;
2796 static bool test_OpenPrinterEx(struct torture_context *tctx,
2797 struct dcerpc_pipe *p,
2798 const char *name)
2800 struct policy_handle handle;
2801 bool ret = true;
2803 if (!call_OpenPrinterEx(tctx, p, name, &handle)) {
2804 return false;
2807 if (!test_GetPrinter(tctx, p, &handle)) {
2808 ret = false;
2811 if (!test_EnumForms(tctx, p, &handle, false)) {
2812 ret = false;
2815 if (!test_AddForm(tctx, p, &handle, false)) {
2816 ret = false;
2819 if (!test_EnumPrinterData(tctx, p, &handle)) {
2820 ret = false;
2823 if (!test_EnumPrinterDataEx(tctx, p, &handle, "PrinterDriverData")) {
2824 ret = false;
2827 if (!test_printer_keys(tctx, p, &handle)) {
2828 ret = false;
2831 if (!test_PausePrinter(tctx, p, &handle)) {
2832 ret = false;
2835 if (!test_DoPrintTest(tctx, p, &handle)) {
2836 ret = false;
2839 if (!test_ResumePrinter(tctx, p, &handle)) {
2840 ret = false;
2843 if (!test_SetPrinterData(tctx, p, &handle)) {
2844 ret = false;
2847 if (!test_SetPrinterDataEx(tctx, p, &handle)) {
2848 ret = false;
2851 if (!torture_setting_bool(tctx, "samba3", false)) {
2852 if (!test_SecondaryClosePrinter(tctx, p, &handle)) {
2853 ret = false;
2857 if (!test_ClosePrinter(tctx, p, &handle)) {
2858 ret = false;
2861 return ret;
2864 static bool test_EnumPrinters_old(struct torture_context *tctx, struct dcerpc_pipe *p)
2866 struct spoolss_EnumPrinters r;
2867 NTSTATUS status;
2868 uint16_t levels[] = {1, 2, 4, 5};
2869 int i;
2870 bool ret = true;
2872 for (i=0;i<ARRAY_SIZE(levels);i++) {
2873 union spoolss_PrinterInfo *info;
2874 int j;
2875 uint32_t needed;
2876 uint32_t count;
2878 r.in.flags = PRINTER_ENUM_LOCAL;
2879 r.in.server = "";
2880 r.in.level = levels[i];
2881 r.in.buffer = NULL;
2882 r.in.offered = 0;
2883 r.out.needed = &needed;
2884 r.out.count = &count;
2885 r.out.info = &info;
2887 torture_comment(tctx, "Testing EnumPrinters level %u\n", r.in.level);
2889 status = dcerpc_spoolss_EnumPrinters(p, tctx, &r);
2890 torture_assert_ntstatus_ok(tctx, status, "EnumPrinters failed");
2892 if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
2893 DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed);
2894 data_blob_clear(&blob);
2895 r.in.buffer = &blob;
2896 r.in.offered = needed;
2897 status = dcerpc_spoolss_EnumPrinters(p, tctx, &r);
2900 torture_assert_ntstatus_ok(tctx, status, "EnumPrinters failed");
2902 torture_assert_werr_ok(tctx, r.out.result, "EnumPrinters failed");
2904 CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumPrinters, info, r.in.level, count, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
2906 if (!info) {
2907 torture_comment(tctx, "No printers returned\n");
2908 return true;
2911 for (j=0;j<count;j++) {
2912 if (r.in.level == 1) {
2913 char *unc = talloc_strdup(tctx, info[j].info1.name);
2914 char *slash, *name;
2915 name = unc;
2916 if (unc[0] == '\\' && unc[1] == '\\') {
2917 unc +=2;
2919 slash = strchr(unc, '\\');
2920 if (slash) {
2921 slash++;
2922 name = slash;
2924 if (!test_OpenPrinter(tctx, p, name)) {
2925 ret = false;
2927 if (!test_OpenPrinterEx(tctx, p, name)) {
2928 ret = false;
2934 return ret;
2937 static bool test_GetPrinterDriver(struct torture_context *tctx,
2938 struct dcerpc_pipe *p,
2939 struct policy_handle *handle,
2940 const char *driver_name)
2942 struct spoolss_GetPrinterDriver r;
2943 uint32_t needed;
2945 r.in.handle = handle;
2946 r.in.architecture = "W32X86";
2947 r.in.level = 1;
2948 r.in.buffer = NULL;
2949 r.in.offered = 0;
2950 r.out.needed = &needed;
2952 torture_comment(tctx, "Testing GetPrinterDriver level %d\n", r.in.level);
2954 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_GetPrinterDriver(p, tctx, &r),
2955 "failed to call GetPrinterDriver");
2956 if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
2957 DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed);
2958 data_blob_clear(&blob);
2959 r.in.buffer = &blob;
2960 r.in.offered = needed;
2961 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_GetPrinterDriver(p, tctx, &r),
2962 "failed to call GetPrinterDriver");
2965 torture_assert_werr_ok(tctx, r.out.result,
2966 "failed to call GetPrinterDriver");
2968 CHECK_NEEDED_SIZE_LEVEL(spoolss_DriverInfo, r.out.info, r.in.level, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
2970 return true;
2973 static bool test_GetPrinterDriver2(struct torture_context *tctx,
2974 struct dcerpc_pipe *p,
2975 struct policy_handle *handle,
2976 const char *driver_name)
2978 struct spoolss_GetPrinterDriver2 r;
2979 uint16_t levels[] = {1, 2, 3, 4, 5, 6, 8, 101 };
2980 uint32_t needed;
2981 uint32_t server_major_version;
2982 uint32_t server_minor_version;
2983 int i;
2985 r.in.handle = handle;
2986 r.in.architecture = SPOOLSS_ARCHITECTURE_NT_X86;
2987 r.in.client_major_version = 3;
2988 r.in.client_minor_version = 0;
2989 r.out.needed = &needed;
2990 r.out.server_major_version = &server_major_version;
2991 r.out.server_minor_version = &server_minor_version;
2993 for (i=0;i<ARRAY_SIZE(levels);i++) {
2995 r.in.buffer = NULL;
2996 r.in.offered = 0;
2997 r.in.level = levels[i];
2999 torture_comment(tctx, "Testing GetPrinterDriver2(%s) level %d\n",
3000 driver_name, r.in.level);
3002 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_GetPrinterDriver2(p, tctx, &r),
3003 "failed to call GetPrinterDriver2");
3004 if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
3005 DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed);
3006 data_blob_clear(&blob);
3007 r.in.buffer = &blob;
3008 r.in.offered = needed;
3009 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_GetPrinterDriver2(p, tctx, &r),
3010 "failed to call GetPrinterDriver2");
3013 if (W_ERROR_EQUAL(r.out.result, WERR_INVALID_LEVEL)) {
3014 switch (r.in.level) {
3015 case 101:
3016 case 8:
3017 continue;
3018 default:
3019 break;
3023 torture_assert_werr_ok(tctx, r.out.result,
3024 "failed to call GetPrinterDriver2");
3026 CHECK_NEEDED_SIZE_LEVEL(spoolss_DriverInfo, r.out.info, r.in.level, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
3029 return true;
3032 static bool test_EnumPrinterDrivers_old(struct torture_context *tctx,
3033 struct dcerpc_pipe *p)
3035 struct spoolss_EnumPrinterDrivers r;
3036 NTSTATUS status;
3037 uint16_t levels[] = {1, 2, 3, 4, 5, 6};
3038 int i;
3040 for (i=0;i<ARRAY_SIZE(levels);i++) {
3042 uint32_t needed;
3043 uint32_t count;
3044 union spoolss_DriverInfo *info;
3046 r.in.server = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
3047 r.in.environment = SPOOLSS_ARCHITECTURE_NT_X86;
3048 r.in.level = levels[i];
3049 r.in.buffer = NULL;
3050 r.in.offered = 0;
3051 r.out.needed = &needed;
3052 r.out.count = &count;
3053 r.out.info = &info;
3055 torture_comment(tctx, "Testing EnumPrinterDrivers level %u\n", r.in.level);
3057 status = dcerpc_spoolss_EnumPrinterDrivers(p, tctx, &r);
3059 torture_assert_ntstatus_ok(tctx, status, "EnumPrinterDrivers failed");
3061 if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
3062 DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed);
3063 data_blob_clear(&blob);
3064 r.in.buffer = &blob;
3065 r.in.offered = needed;
3066 status = dcerpc_spoolss_EnumPrinterDrivers(p, tctx, &r);
3069 torture_assert_ntstatus_ok(tctx, status, "EnumPrinterDrivers failed");
3071 torture_assert_werr_ok(tctx, r.out.result, "EnumPrinterDrivers failed");
3073 if (!info) {
3074 torture_comment(tctx, "No printer drivers returned\n");
3075 break;
3078 CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumPrinterDrivers, info, r.in.level, count, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
3081 return true;
3084 static bool test_DeletePrinter(struct torture_context *tctx,
3085 struct dcerpc_pipe *p,
3086 struct policy_handle *handle)
3088 struct spoolss_DeletePrinter r;
3090 torture_comment(tctx, "Testing DeletePrinter\n");
3092 r.in.handle = handle;
3094 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_DeletePrinter(p, tctx, &r),
3095 "failed to delete printer");
3096 torture_assert_werr_ok(tctx, r.out.result,
3097 "failed to delete printer");
3099 return true;
3102 static bool test_EnumPrinters_findname(struct torture_context *tctx,
3103 struct dcerpc_pipe *p,
3104 uint32_t flags,
3105 uint32_t level,
3106 const char *name,
3107 bool *found)
3109 struct spoolss_EnumPrinters e;
3110 uint32_t count;
3111 union spoolss_PrinterInfo *info;
3112 uint32_t needed;
3113 int i;
3115 *found = false;
3117 e.in.flags = flags;
3118 e.in.server = NULL;
3119 e.in.level = level;
3120 e.in.buffer = NULL;
3121 e.in.offered = 0;
3122 e.out.count = &count;
3123 e.out.info = &info;
3124 e.out.needed = &needed;
3126 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_EnumPrinters(p, tctx, &e),
3127 "failed to enum printers");
3129 if (W_ERROR_EQUAL(e.out.result, WERR_INSUFFICIENT_BUFFER)) {
3130 DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed);
3131 data_blob_clear(&blob);
3132 e.in.buffer = &blob;
3133 e.in.offered = needed;
3135 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_EnumPrinters(p, tctx, &e),
3136 "failed to enum printers");
3139 torture_assert_werr_ok(tctx, e.out.result,
3140 "failed to enum printers");
3142 for (i=0; i < count; i++) {
3144 const char *current = NULL;
3146 switch (level) {
3147 case 1:
3148 current = info[i].info1.name;
3149 break;
3152 if (strequal(current, name)) {
3153 *found = true;
3154 break;
3158 return true;
3161 static bool test_AddPrinter_wellknown(struct torture_context *tctx,
3162 struct dcerpc_pipe *p,
3163 const char *printername,
3164 bool ex)
3166 WERROR result;
3167 struct spoolss_AddPrinter r;
3168 struct spoolss_AddPrinterEx rex;
3169 struct spoolss_SetPrinterInfoCtr info_ctr;
3170 struct spoolss_SetPrinterInfo1 info1;
3171 struct spoolss_DevmodeContainer devmode_ctr;
3172 struct sec_desc_buf secdesc_ctr;
3173 struct spoolss_UserLevelCtr userlevel_ctr;
3174 struct policy_handle handle;
3175 bool found = false;
3177 ZERO_STRUCT(devmode_ctr);
3178 ZERO_STRUCT(secdesc_ctr);
3179 ZERO_STRUCT(userlevel_ctr);
3180 ZERO_STRUCT(info1);
3182 torture_comment(tctx, "Testing AddPrinter%s level 1\n", ex ? "Ex":"");
3184 /* try to add printer to wellknown printer list (level 1) */
3186 userlevel_ctr.level = 1;
3188 info_ctr.info.info1 = &info1;
3189 info_ctr.level = 1;
3191 rex.in.server = NULL;
3192 rex.in.info_ctr = &info_ctr;
3193 rex.in.devmode_ctr = &devmode_ctr;
3194 rex.in.secdesc_ctr = &secdesc_ctr;
3195 rex.in.userlevel_ctr = &userlevel_ctr;
3196 rex.out.handle = &handle;
3198 r.in.server = NULL;
3199 r.in.info_ctr = &info_ctr;
3200 r.in.devmode_ctr = &devmode_ctr;
3201 r.in.secdesc_ctr = &secdesc_ctr;
3202 r.out.handle = &handle;
3204 torture_assert_ntstatus_ok(tctx, ex ? dcerpc_spoolss_AddPrinterEx(p, tctx, &rex) :
3205 dcerpc_spoolss_AddPrinter(p, tctx, &r),
3206 "failed to add printer");
3207 result = ex ? rex.out.result : r.out.result;
3208 torture_assert_werr_equal(tctx, result, WERR_INVALID_PRINTER_NAME,
3209 "unexpected result code");
3211 info1.name = printername;
3212 info1.flags = PRINTER_ATTRIBUTE_SHARED;
3214 torture_assert_ntstatus_ok(tctx, ex ? dcerpc_spoolss_AddPrinterEx(p, tctx, &rex) :
3215 dcerpc_spoolss_AddPrinter(p, tctx, &r),
3216 "failed to add printer");
3217 result = ex ? rex.out.result : r.out.result;
3218 torture_assert_werr_equal(tctx, result, WERR_PRINTER_ALREADY_EXISTS,
3219 "unexpected result code");
3221 /* bizarre protocol, WERR_PRINTER_ALREADY_EXISTS means success here,
3222 better do a real check to see the printer is really there */
3224 torture_assert(tctx, test_EnumPrinters_findname(tctx, p,
3225 PRINTER_ENUM_NETWORK, 1,
3226 printername,
3227 &found),
3228 "failed to enum printers");
3230 torture_assert(tctx, found, "failed to find newly added printer");
3232 info1.flags = 0;
3234 torture_assert_ntstatus_ok(tctx, ex ? dcerpc_spoolss_AddPrinterEx(p, tctx, &rex) :
3235 dcerpc_spoolss_AddPrinter(p, tctx, &r),
3236 "failed to add printer");
3237 result = ex ? rex.out.result : r.out.result;
3238 torture_assert_werr_equal(tctx, result, WERR_PRINTER_ALREADY_EXISTS,
3239 "unexpected result code");
3241 /* bizarre protocol, WERR_PRINTER_ALREADY_EXISTS means success here,
3242 better do a real check to see the printer has really been removed
3243 from the well known printer list */
3245 found = false;
3247 torture_assert(tctx, test_EnumPrinters_findname(tctx, p,
3248 PRINTER_ENUM_NETWORK, 1,
3249 printername,
3250 &found),
3251 "failed to enum printers");
3252 #if 0
3253 torture_assert(tctx, !found, "printer still in well known printer list");
3254 #endif
3255 return true;
3258 static bool test_AddPrinter_normal(struct torture_context *tctx,
3259 struct dcerpc_pipe *p,
3260 struct policy_handle *handle_p,
3261 const char *printername,
3262 const char *drivername,
3263 const char *portname,
3264 bool ex)
3266 WERROR result;
3267 struct spoolss_AddPrinter r;
3268 struct spoolss_AddPrinterEx rex;
3269 struct spoolss_SetPrinterInfoCtr info_ctr;
3270 struct spoolss_SetPrinterInfo2 info2;
3271 struct spoolss_DevmodeContainer devmode_ctr;
3272 struct sec_desc_buf secdesc_ctr;
3273 struct spoolss_UserLevelCtr userlevel_ctr;
3274 struct policy_handle handle;
3275 bool found = false;
3277 ZERO_STRUCT(devmode_ctr);
3278 ZERO_STRUCT(secdesc_ctr);
3279 ZERO_STRUCT(userlevel_ctr);
3281 torture_comment(tctx, "Testing AddPrinter%s level 2\n", ex ? "Ex":"");
3283 userlevel_ctr.level = 1;
3285 rex.in.server = NULL;
3286 rex.in.info_ctr = &info_ctr;
3287 rex.in.devmode_ctr = &devmode_ctr;
3288 rex.in.secdesc_ctr = &secdesc_ctr;
3289 rex.in.userlevel_ctr = &userlevel_ctr;
3290 rex.out.handle = &handle;
3292 r.in.server = NULL;
3293 r.in.info_ctr = &info_ctr;
3294 r.in.devmode_ctr = &devmode_ctr;
3295 r.in.secdesc_ctr = &secdesc_ctr;
3296 r.out.handle = &handle;
3298 again:
3300 /* try to add printer to printer list (level 2) */
3302 ZERO_STRUCT(info2);
3304 info_ctr.info.info2 = &info2;
3305 info_ctr.level = 2;
3307 torture_assert_ntstatus_ok(tctx, ex ? dcerpc_spoolss_AddPrinterEx(p, tctx, &rex) :
3308 dcerpc_spoolss_AddPrinter(p, tctx, &r),
3309 "failed to add printer");
3310 result = ex ? rex.out.result : r.out.result;
3311 torture_assert_werr_equal(tctx, result, WERR_INVALID_PRINTER_NAME,
3312 "unexpected result code");
3314 info2.printername = printername;
3316 torture_assert_ntstatus_ok(tctx, ex ? dcerpc_spoolss_AddPrinterEx(p, tctx, &rex) :
3317 dcerpc_spoolss_AddPrinter(p, tctx, &r),
3318 "failed to add printer");
3319 result = ex ? rex.out.result : r.out.result;
3321 if (W_ERROR_EQUAL(result, WERR_PRINTER_ALREADY_EXISTS)) {
3322 struct policy_handle printer_handle;
3324 torture_assert(tctx, call_OpenPrinterEx(tctx, p, printername, &printer_handle),
3325 "failed to open printer handle");
3327 torture_assert(tctx, test_DeletePrinter(tctx, p, &printer_handle),
3328 "failed to delete printer");
3330 torture_assert(tctx, test_ClosePrinter(tctx, p, &printer_handle),
3331 "failed to close server handle");
3333 goto again;
3336 torture_assert_werr_equal(tctx, result, WERR_UNKNOWN_PORT,
3337 "unexpected result code");
3339 info2.portname = portname;
3341 torture_assert_ntstatus_ok(tctx, ex ? dcerpc_spoolss_AddPrinterEx(p, tctx, &rex) :
3342 dcerpc_spoolss_AddPrinter(p, tctx, &r),
3343 "failed to add printer");
3344 result = ex ? rex.out.result : r.out.result;
3345 torture_assert_werr_equal(tctx, result, WERR_UNKNOWN_PRINTER_DRIVER,
3346 "unexpected result code");
3348 info2.drivername = drivername;
3350 torture_assert_ntstatus_ok(tctx, ex ? dcerpc_spoolss_AddPrinterEx(p, tctx, &rex) :
3351 dcerpc_spoolss_AddPrinter(p, tctx, &r),
3352 "failed to add printer");
3353 result = ex ? rex.out.result : r.out.result;
3354 torture_assert_werr_equal(tctx, result, WERR_UNKNOWN_PRINTPROCESSOR,
3355 "unexpected result code");
3357 info2.printprocessor = "winprint";
3359 torture_assert_ntstatus_ok(tctx, ex ? dcerpc_spoolss_AddPrinterEx(p, tctx, &rex) :
3360 dcerpc_spoolss_AddPrinter(p, tctx, &r),
3361 "failed to add printer");
3362 result = ex ? rex.out.result : r.out.result;
3363 torture_assert_werr_ok(tctx, result,
3364 "failed to add printer");
3366 *handle_p = handle;
3368 /* we are paranoid, really check if the printer is there now */
3370 torture_assert(tctx, test_EnumPrinters_findname(tctx, p,
3371 PRINTER_ENUM_LOCAL, 1,
3372 printername,
3373 &found),
3374 "failed to enum printers");
3375 torture_assert(tctx, found, "failed to find newly added printer");
3377 torture_assert_ntstatus_ok(tctx, ex ? dcerpc_spoolss_AddPrinterEx(p, tctx, &rex) :
3378 dcerpc_spoolss_AddPrinter(p, tctx, &r),
3379 "failed to add printer");
3380 result = ex ? rex.out.result : r.out.result;
3381 torture_assert_werr_equal(tctx, result, WERR_PRINTER_ALREADY_EXISTS,
3382 "unexpected result code");
3384 return true;
3387 static bool test_AddPrinterEx(struct torture_context *tctx,
3388 struct dcerpc_pipe *p,
3389 struct policy_handle *handle_p,
3390 const char *printername,
3391 const char *drivername,
3392 const char *portname)
3394 bool ret = true;
3396 if (!torture_setting_bool(tctx, "samba3", false)) {
3397 if (!test_AddPrinter_wellknown(tctx, p, TORTURE_WELLKNOWN_PRINTER_EX, true)) {
3398 torture_comment(tctx, "failed to add printer to well known list\n");
3399 ret = false;
3403 if (!test_AddPrinter_normal(tctx, p, handle_p,
3404 printername, drivername, portname,
3405 true)) {
3406 torture_comment(tctx, "failed to add printer to printer list\n");
3407 ret = false;
3410 return ret;
3413 static bool test_AddPrinter(struct torture_context *tctx,
3414 struct dcerpc_pipe *p,
3415 struct policy_handle *handle_p,
3416 const char *printername,
3417 const char *drivername,
3418 const char *portname)
3420 bool ret = true;
3422 if (!torture_setting_bool(tctx, "samba3", false)) {
3423 if (!test_AddPrinter_wellknown(tctx, p, TORTURE_WELLKNOWN_PRINTER, false)) {
3424 torture_comment(tctx, "failed to add printer to well known list\n");
3425 ret = false;
3429 if (!test_AddPrinter_normal(tctx, p, handle_p,
3430 printername, drivername, portname,
3431 false)) {
3432 torture_comment(tctx, "failed to add printer to printer list\n");
3433 ret = false;
3436 return ret;
3439 static bool test_printer_info(struct torture_context *tctx,
3440 struct dcerpc_pipe *p,
3441 struct policy_handle *handle)
3443 bool ret = true;
3445 if (!test_PrinterInfo(tctx, p, handle)) {
3446 ret = false;
3449 if (!test_SetPrinter_errors(tctx, p, handle)) {
3450 ret = false;
3453 return ret;
3456 static bool test_EnumPrinterKey(struct torture_context *tctx,
3457 struct dcerpc_pipe *p,
3458 struct policy_handle *handle,
3459 const char *key_name,
3460 const char ***array)
3462 struct spoolss_EnumPrinterKey r;
3463 uint32_t needed = 0;
3464 union spoolss_KeyNames key_buffer;
3465 int32_t offered[] = { 0, 1, 2, 3, 4, 5, -1, -2, -3, -4, -5, 256, 512, 1024, 2048 };
3466 uint32_t _ndr_size;
3467 int i;
3469 r.in.handle = handle;
3470 r.in.key_name = key_name;
3471 r.out.key_buffer = &key_buffer;
3472 r.out.needed = &needed;
3473 r.out._ndr_size = &_ndr_size;
3475 for (i=0; i < ARRAY_SIZE(offered); i++) {
3477 if (offered[i] < 0 && needed) {
3478 if (needed <= 4) {
3479 continue;
3481 r.in.offered = needed + offered[i];
3482 } else {
3483 r.in.offered = offered[i];
3486 ZERO_STRUCT(key_buffer);
3488 torture_comment(tctx, "Testing EnumPrinterKey(%s) with %d offered\n", r.in.key_name, r.in.offered);
3490 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_EnumPrinterKey(p, tctx, &r),
3491 "failed to call EnumPrinterKey");
3492 if (W_ERROR_EQUAL(r.out.result, WERR_MORE_DATA)) {
3494 torture_assert(tctx, (_ndr_size == r.in.offered/2),
3495 talloc_asprintf(tctx, "EnumPrinterKey size mismatch, _ndr_size %d (expected %d)",
3496 _ndr_size, r.in.offered/2));
3498 r.in.offered = needed;
3499 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_EnumPrinterKey(p, tctx, &r),
3500 "failed to call EnumPrinterKey");
3503 if (offered[i] > 0) {
3504 torture_assert_werr_ok(tctx, r.out.result,
3505 "failed to call EnumPrinterKey");
3508 torture_assert(tctx, (_ndr_size == r.in.offered/2),
3509 talloc_asprintf(tctx, "EnumPrinterKey size mismatch, _ndr_size %d (expected %d)",
3510 _ndr_size, r.in.offered/2));
3512 torture_assert(tctx, (*r.out.needed <= r.in.offered),
3513 talloc_asprintf(tctx, "EnumPrinterKey size mismatch: needed %d is not <= offered %d", *r.out.needed, r.in.offered));
3515 torture_assert(tctx, (*r.out.needed <= _ndr_size * 2),
3516 talloc_asprintf(tctx, "EnumPrinterKey size mismatch: needed %d is not <= _ndr_size %d * 2", *r.out.needed, _ndr_size));
3518 if (key_buffer.string_array) {
3519 uint32_t calc_needed = 0;
3520 int s;
3521 for (s=0; key_buffer.string_array[s]; s++) {
3522 calc_needed += strlen_m_term(key_buffer.string_array[s])*2;
3524 if (!key_buffer.string_array[0]) {
3525 calc_needed += 2;
3527 calc_needed += 2;
3529 torture_assert_int_equal(tctx, *r.out.needed, calc_needed,
3530 "EnumPrinterKey unexpected size");
3534 if (array) {
3535 *array = key_buffer.string_array;
3538 return true;
3541 bool test_printer_keys(struct torture_context *tctx,
3542 struct dcerpc_pipe *p,
3543 struct policy_handle *handle)
3545 const char **key_array = NULL;
3546 int i;
3548 torture_assert(tctx, test_EnumPrinterKey(tctx, p, handle, "", &key_array),
3549 "failed to call test_EnumPrinterKey");
3551 for (i=0; key_array && key_array[i]; i++) {
3552 torture_assert(tctx, test_EnumPrinterKey(tctx, p, handle, key_array[i], NULL),
3553 "failed to call test_EnumPrinterKey");
3555 for (i=0; key_array && key_array[i]; i++) {
3556 torture_assert(tctx, test_EnumPrinterDataEx(tctx, p, handle, key_array[i]),
3557 "failed to call test_EnumPrinterDataEx");
3560 return true;
3563 static bool test_printer(struct torture_context *tctx,
3564 struct dcerpc_pipe *p)
3566 bool ret = true;
3567 struct policy_handle handle[2];
3568 bool found = false;
3569 const char *drivername = "Microsoft XPS Document Writer";
3570 const char *portname = "LPT1:";
3572 /* test printer created via AddPrinter */
3574 if (!test_AddPrinter(tctx, p, &handle[0], TORTURE_PRINTER, drivername, portname)) {
3575 return false;
3578 if (!test_printer_info(tctx, p, &handle[0])) {
3579 ret = false;
3582 if (!test_printer_keys(tctx, p, &handle[0])) {
3583 ret = false;
3586 if (!test_DeletePrinter(tctx, p, &handle[0])) {
3587 ret = false;
3590 if (!test_EnumPrinters_findname(tctx, p, PRINTER_ENUM_LOCAL, 1,
3591 TORTURE_PRINTER, &found)) {
3592 ret = false;
3595 torture_assert(tctx, !found, "deleted printer still there");
3597 /* test printer created via AddPrinterEx */
3599 if (!test_AddPrinterEx(tctx, p, &handle[1], TORTURE_PRINTER_EX, drivername, portname)) {
3600 return false;
3603 if (!test_printer_info(tctx, p, &handle[1])) {
3604 ret = false;
3607 if (!test_printer_keys(tctx, p, &handle[1])) {
3608 ret = false;
3611 if (!test_DeletePrinter(tctx, p, &handle[1])) {
3612 ret = false;
3615 if (!test_EnumPrinters_findname(tctx, p, PRINTER_ENUM_LOCAL, 1,
3616 TORTURE_PRINTER_EX, &found)) {
3617 ret = false;
3620 torture_assert(tctx, !found, "deleted printer still there");
3622 return ret;
3625 bool torture_rpc_spoolss(struct torture_context *torture)
3627 NTSTATUS status;
3628 struct dcerpc_pipe *p;
3629 bool ret = true;
3630 struct test_spoolss_context *ctx;
3632 status = torture_rpc_connection(torture, &p, &ndr_table_spoolss);
3633 if (!NT_STATUS_IS_OK(status)) {
3634 return false;
3637 ctx = talloc_zero(torture, struct test_spoolss_context);
3639 ret &= test_OpenPrinter_server(torture, p, &ctx->server_handle);
3640 ret &= test_GetPrinterData_list(torture, p, &ctx->server_handle);
3641 ret &= test_EnumForms(torture, p, &ctx->server_handle, true);
3642 ret &= test_AddForm(torture, p, &ctx->server_handle, true);
3643 ret &= test_EnumPorts(torture, p, ctx);
3644 ret &= test_GetPrinterDriverDirectory(torture, p, ctx);
3645 ret &= test_GetPrintProcessorDirectory(torture, p, ctx);
3646 ret &= test_EnumPrinterDrivers(torture, p, ctx, SPOOLSS_ARCHITECTURE_NT_X86);
3647 ret &= test_EnumPrinterDrivers(torture, p, ctx, SPOOLSS_ARCHITECTURE_ALL);
3648 ret &= test_EnumMonitors(torture, p, ctx);
3649 ret &= test_EnumPrintProcessors(torture, p, ctx);
3650 ret &= test_EnumPrintProcDataTypes(torture, p, ctx);
3651 ret &= test_EnumPrinters(torture, p, ctx);
3652 ret &= test_OpenPrinter_badname(torture, p, "__INVALID_PRINTER__");
3653 ret &= test_OpenPrinter_badname(torture, p, "\\\\__INVALID_HOST__");
3654 ret &= test_OpenPrinter_badname(torture, p, "");
3655 ret &= test_OpenPrinter_badname(torture, p, "\\\\\\");
3656 ret &= test_OpenPrinter_badname(torture, p, "\\\\\\__INVALID_PRINTER__");
3657 ret &= test_OpenPrinter_badname(torture, p, talloc_asprintf(torture, "\\\\%s\\", dcerpc_server_name(p)));
3658 ret &= test_OpenPrinter_badname(torture, p,
3659 talloc_asprintf(torture, "\\\\%s\\__INVALID_PRINTER__", dcerpc_server_name(p)));
3662 ret &= test_AddPort(torture, p);
3663 ret &= test_EnumPorts_old(torture, p);
3664 ret &= test_EnumPrinters_old(torture, p);
3665 ret &= test_EnumPrinterDrivers_old(torture, p);
3667 return ret;
3670 struct torture_suite *torture_rpc_spoolss_printer(TALLOC_CTX *mem_ctx)
3672 struct torture_suite *suite = torture_suite_create(mem_ctx, "SPOOLSS-PRINTER");
3674 struct torture_rpc_tcase *tcase = torture_suite_add_rpc_iface_tcase(suite,
3675 "printer", &ndr_table_spoolss);
3677 torture_rpc_tcase_add_test(tcase, "printer", test_printer);
3679 return suite;