s4-smbtorture: while testing PrinterDataEx also compare Get and Enum results.
[Samba/nascimento.git] / source4 / torture / rpc / spoolss.c
blob4ff79f2631e0cc255b63ddaaf684e02ae6734884
1 /*
2 Unix SMB/CIFS implementation.
3 test suite for spoolss rpc operations
5 Copyright (C) Tim Potter 2003
6 Copyright (C) Stefan Metzmacher 2005
7 Copyright (C) Jelmer Vernooij 2007
8 Copyright (C) Guenther Deschner 2009-2010
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 3 of the License, or
13 (at your option) any later version.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program. If not, see <http://www.gnu.org/licenses/>.
24 #include "includes.h"
25 #include "torture/torture.h"
26 #include "librpc/gen_ndr/ndr_misc.h"
27 #include "librpc/gen_ndr/ndr_spoolss.h"
28 #include "librpc/gen_ndr/ndr_spoolss_c.h"
29 #include "librpc/gen_ndr/ndr_winreg_c.h"
30 #include "librpc/gen_ndr/ndr_security.h"
31 #include "libcli/security/security.h"
32 #include "torture/rpc/rpc.h"
33 #include "param/param.h"
34 #include "lib/registry/registry.h"
36 #define TORTURE_WELLKNOWN_PRINTER "torture_wkn_printer"
37 #define TORTURE_PRINTER "torture_printer"
38 #define TORTURE_WELLKNOWN_PRINTER_EX "torture_wkn_printer_ex"
39 #define TORTURE_PRINTER_EX "torture_printer_ex"
41 struct test_spoolss_context {
42 /* print server handle */
43 struct policy_handle server_handle;
45 /* for EnumPorts */
46 uint32_t port_count[3];
47 union spoolss_PortInfo *ports[3];
49 /* for EnumPrinterDrivers */
50 uint32_t driver_count[8];
51 union spoolss_DriverInfo *drivers[8];
53 /* for EnumMonitors */
54 uint32_t monitor_count[3];
55 union spoolss_MonitorInfo *monitors[3];
57 /* for EnumPrintProcessors */
58 uint32_t print_processor_count[2];
59 union spoolss_PrintProcessorInfo *print_processors[2];
61 /* for EnumPrinters */
62 uint32_t printer_count[6];
63 union spoolss_PrinterInfo *printers[6];
66 #define COMPARE_STRING(tctx, c,r,e) \
67 torture_assert_str_equal(tctx, c.e, r.e, "invalid value")
69 /* not every compiler supports __typeof__() */
70 #if (__GNUC__ >= 3)
71 #define _CHECK_FIELD_SIZE(c,r,e,type) do {\
72 if (sizeof(__typeof__(c.e)) != sizeof(type)) { \
73 torture_fail(tctx, #c "." #e "field is not " #type "\n"); \
75 if (sizeof(__typeof__(r.e)) != sizeof(type)) { \
76 torture_fail(tctx, #r "." #e "field is not " #type "\n"); \
78 } while(0)
79 #else
80 #define _CHECK_FIELD_SIZE(c,r,e,type) do {} while(0)
81 #endif
83 #define COMPARE_UINT32(tctx, c, r, e) do {\
84 _CHECK_FIELD_SIZE(c, r, e, uint32_t); \
85 torture_assert_int_equal(tctx, c.e, r.e, "invalid value"); \
86 } while(0)
88 #define COMPARE_UINT64(tctx, c, r, e) do {\
89 _CHECK_FIELD_SIZE(c, r, e, uint64_t); \
90 torture_assert_int_equal(tctx, c.e, r.e, "invalid value"); \
91 } while(0)
94 #define COMPARE_NTTIME(tctx, c, r, e) do {\
95 _CHECK_FIELD_SIZE(c, r, e, NTTIME); \
96 torture_assert_int_equal(tctx, c.e, r.e, "invalid value"); \
97 } while(0)
99 #define COMPARE_STRING_ARRAY(tctx, c,r,e) do {\
100 int __i; \
101 if (!c.e && !r.e) { \
102 break; \
104 if (c.e && !r.e) { \
105 torture_fail(tctx, #r "." #e " field is NULL and " #c "." #e " is not\n"); \
107 if (!c.e && r.e) { \
108 torture_fail(tctx, #c "." #e " field is NULL and " #r "." #e " is not\n"); \
110 for (__i=0;c.e[__i] != NULL; __i++) { \
111 torture_assert_str_equal(tctx, c.e[__i], r.e[__i], "invalid value"); \
113 } while(0)
115 #define CHECK_ALIGN(size, n) do {\
116 if (size % n) {\
117 torture_warning(tctx, "%d is *NOT* %d byte aligned, should be %d",\
118 size, n, size + n - (size % n));\
120 } while(0)
122 #define DO_ROUND(size, n) (((size)+((n)-1)) & ~((n)-1))
124 #define CHECK_NEEDED_SIZE_ENUM_LEVEL(fn, info, level, count, ic, needed, align) do { \
125 if (torture_setting_bool(tctx, "spoolss_check_size", false)) {\
126 uint32_t size = ndr_size_##fn##_info(tctx, ic, level, count, info);\
127 uint32_t round_size = DO_ROUND(size, align);\
128 if (round_size != needed) {\
129 torture_warning(tctx, __location__": "#fn" level %d (count: %d) got unexpected needed size: %d, we calculated: %d", level, count, needed, round_size);\
130 CHECK_ALIGN(size, align);\
133 } while(0)
135 #define CHECK_NEEDED_SIZE_ENUM(fn, info, count, ic, needed, align) do { \
136 if (torture_setting_bool(tctx, "spoolss_check_size", false)) {\
137 uint32_t size = ndr_size_##fn##_info(tctx, ic, count, info);\
138 uint32_t round_size = DO_ROUND(size, align);\
139 if (round_size != needed) {\
140 torture_warning(tctx, __location__": "#fn" (count: %d) got unexpected needed size: %d, we calculated: %d", count, needed, round_size);\
141 CHECK_ALIGN(size, align);\
144 } while(0)
146 #define CHECK_NEEDED_SIZE_LEVEL(fn, info, level, ic, needed, align) do { \
147 if (torture_setting_bool(tctx, "spoolss_check_size", false)) {\
148 uint32_t size = ndr_size_##fn(info, level, ic, 0);\
149 uint32_t round_size = DO_ROUND(size, align);\
150 if (round_size != needed) {\
151 torture_warning(tctx, __location__": "#fn" level %d got unexpected needed size: %d, we calculated: %d", level, needed, round_size);\
152 CHECK_ALIGN(size, align);\
155 } while(0)
157 static bool test_OpenPrinter_server(struct torture_context *tctx,
158 struct dcerpc_pipe *p,
159 struct policy_handle *server_handle)
161 NTSTATUS status;
162 struct spoolss_OpenPrinter op;
164 op.in.printername = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
165 op.in.datatype = NULL;
166 op.in.devmode_ctr.devmode= NULL;
167 op.in.access_mask = 0;
168 op.out.handle = server_handle;
170 torture_comment(tctx, "Testing OpenPrinter(%s)\n", op.in.printername);
172 status = dcerpc_spoolss_OpenPrinter(p, tctx, &op);
173 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_OpenPrinter failed");
174 torture_assert_werr_ok(tctx, op.out.result, "dcerpc_spoolss_OpenPrinter failed");
176 return true;
179 static bool test_EnumPorts(struct torture_context *tctx,
180 struct dcerpc_pipe *p,
181 struct test_spoolss_context *ctx)
183 NTSTATUS status;
184 struct spoolss_EnumPorts r;
185 uint16_t levels[] = { 1, 2 };
186 int i, j;
188 for (i=0;i<ARRAY_SIZE(levels);i++) {
189 int level = levels[i];
190 DATA_BLOB blob;
191 uint32_t needed;
192 uint32_t count;
193 union spoolss_PortInfo *info;
195 r.in.servername = "";
196 r.in.level = level;
197 r.in.buffer = NULL;
198 r.in.offered = 0;
199 r.out.needed = &needed;
200 r.out.count = &count;
201 r.out.info = &info;
203 torture_comment(tctx, "Testing EnumPorts level %u\n", r.in.level);
205 status = dcerpc_spoolss_EnumPorts(p, ctx, &r);
206 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EnumPorts failed");
207 if (W_ERROR_IS_OK(r.out.result)) {
208 /* TODO: do some more checks here */
209 continue;
211 torture_assert_werr_equal(tctx, r.out.result, WERR_INSUFFICIENT_BUFFER,
212 "EnumPorts unexpected return code");
214 blob = data_blob_talloc(ctx, NULL, needed);
215 data_blob_clear(&blob);
216 r.in.buffer = &blob;
217 r.in.offered = needed;
219 status = dcerpc_spoolss_EnumPorts(p, ctx, &r);
220 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EnumPorts failed");
222 torture_assert_werr_ok(tctx, r.out.result, "EnumPorts failed");
224 torture_assert(tctx, info, "EnumPorts returned no info");
226 CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumPorts, info, r.in.level, count, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
228 ctx->port_count[level] = count;
229 ctx->ports[level] = info;
232 for (i=1;i<ARRAY_SIZE(levels);i++) {
233 int level = levels[i];
234 int old_level = levels[i-1];
235 torture_assert_int_equal(tctx, ctx->port_count[level], ctx->port_count[old_level],
236 "EnumPorts invalid value");
238 /* if the array sizes are not the same we would maybe segfault in the following code */
240 for (i=0;i<ARRAY_SIZE(levels);i++) {
241 int level = levels[i];
242 for (j=0;j<ctx->port_count[level];j++) {
243 union spoolss_PortInfo *cur = &ctx->ports[level][j];
244 union spoolss_PortInfo *ref = &ctx->ports[2][j];
245 switch (level) {
246 case 1:
247 COMPARE_STRING(tctx, cur->info1, ref->info2, port_name);
248 break;
249 case 2:
250 /* level 2 is our reference, and it makes no sense to compare it to itself */
251 break;
256 return true;
259 static bool test_GetPrintProcessorDirectory(struct torture_context *tctx,
260 struct dcerpc_pipe *p,
261 struct test_spoolss_context *ctx,
262 const char *environment)
264 NTSTATUS status;
265 struct spoolss_GetPrintProcessorDirectory r;
266 struct {
267 uint16_t level;
268 const char *server;
269 } levels[] = {{
270 .level = 1,
271 .server = NULL
273 .level = 1,
274 .server = ""
276 .level = 78,
277 .server = ""
279 .level = 1,
280 .server = talloc_asprintf(ctx, "\\\\%s", dcerpc_server_name(p))
282 .level = 1024,
283 .server = talloc_asprintf(ctx, "\\\\%s", dcerpc_server_name(p))
286 int i;
287 uint32_t needed;
289 for (i=0;i<ARRAY_SIZE(levels);i++) {
290 int level = levels[i].level;
291 DATA_BLOB blob;
293 r.in.server = levels[i].server;
294 r.in.environment = environment;
295 r.in.level = level;
296 r.in.buffer = NULL;
297 r.in.offered = 0;
298 r.out.needed = &needed;
300 torture_comment(tctx, "Testing GetPrintProcessorDirectory level %u\n", r.in.level);
302 status = dcerpc_spoolss_GetPrintProcessorDirectory(p, ctx, &r);
303 torture_assert_ntstatus_ok(tctx, status,
304 "dcerpc_spoolss_GetPrintProcessorDirectory failed");
305 torture_assert_werr_equal(tctx, r.out.result, WERR_INSUFFICIENT_BUFFER,
306 "GetPrintProcessorDirectory unexpected return code");
308 blob = data_blob_talloc(ctx, NULL, needed);
309 data_blob_clear(&blob);
310 r.in.buffer = &blob;
311 r.in.offered = needed;
313 status = dcerpc_spoolss_GetPrintProcessorDirectory(p, ctx, &r);
314 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_GetPrintProcessorDirectory failed");
316 torture_assert_werr_ok(tctx, r.out.result, "GetPrintProcessorDirectory failed");
318 CHECK_NEEDED_SIZE_LEVEL(spoolss_PrintProcessorDirectoryInfo, r.out.info, r.in.level, lp_iconv_convenience(tctx->lp_ctx), needed, 2);
321 return true;
325 static bool test_GetPrinterDriverDirectory(struct torture_context *tctx,
326 struct dcerpc_pipe *p,
327 struct test_spoolss_context *ctx,
328 const char *environment)
330 NTSTATUS status;
331 struct spoolss_GetPrinterDriverDirectory r;
332 struct {
333 uint16_t level;
334 const char *server;
335 } levels[] = {{
336 .level = 1,
337 .server = NULL
339 .level = 1,
340 .server = ""
342 .level = 78,
343 .server = ""
345 .level = 1,
346 .server = talloc_asprintf(ctx, "\\\\%s", dcerpc_server_name(p))
348 .level = 1024,
349 .server = talloc_asprintf(ctx, "\\\\%s", dcerpc_server_name(p))
352 int i;
353 uint32_t needed;
355 for (i=0;i<ARRAY_SIZE(levels);i++) {
356 int level = levels[i].level;
357 DATA_BLOB blob;
359 r.in.server = levels[i].server;
360 r.in.environment = environment;
361 r.in.level = level;
362 r.in.buffer = NULL;
363 r.in.offered = 0;
364 r.out.needed = &needed;
366 torture_comment(tctx, "Testing GetPrinterDriverDirectory level %u\n", r.in.level);
368 status = dcerpc_spoolss_GetPrinterDriverDirectory(p, ctx, &r);
369 torture_assert_ntstatus_ok(tctx, status,
370 "dcerpc_spoolss_GetPrinterDriverDirectory failed");
371 torture_assert_werr_equal(tctx, r.out.result, WERR_INSUFFICIENT_BUFFER,
372 "GetPrinterDriverDirectory unexpected return code");
374 blob = data_blob_talloc(ctx, NULL, needed);
375 data_blob_clear(&blob);
376 r.in.buffer = &blob;
377 r.in.offered = needed;
379 status = dcerpc_spoolss_GetPrinterDriverDirectory(p, ctx, &r);
380 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_GetPrinterDriverDirectory failed");
382 torture_assert_werr_ok(tctx, r.out.result, "GetPrinterDriverDirectory failed");
384 CHECK_NEEDED_SIZE_LEVEL(spoolss_DriverDirectoryInfo, r.out.info, r.in.level, lp_iconv_convenience(tctx->lp_ctx), needed, 2);
387 return true;
390 static bool test_EnumPrinterDrivers(struct torture_context *tctx,
391 struct dcerpc_pipe *p,
392 struct test_spoolss_context *ctx,
393 const char *architecture)
395 NTSTATUS status;
396 struct spoolss_EnumPrinterDrivers r;
397 uint16_t levels[] = { 1, 2, 3, 4, 5, 6, 8 };
398 int i, j;
400 for (i=0;i<ARRAY_SIZE(levels);i++) {
401 int level = levels[i];
402 DATA_BLOB blob;
403 uint32_t needed;
404 uint32_t count;
405 union spoolss_DriverInfo *info;
407 /* FIXME: gd, come back and fix "" as server, and handle
408 * priority of returned error codes in torture test and samba 3
409 * server */
411 r.in.server = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
412 r.in.environment = architecture;
413 r.in.level = level;
414 r.in.buffer = NULL;
415 r.in.offered = 0;
416 r.out.needed = &needed;
417 r.out.count = &count;
418 r.out.info = &info;
420 torture_comment(tctx, "Testing EnumPrinterDrivers level %u (%s)\n", r.in.level, r.in.environment);
422 status = dcerpc_spoolss_EnumPrinterDrivers(p, ctx, &r);
423 torture_assert_ntstatus_ok(tctx, status,
424 "dcerpc_spoolss_EnumPrinterDrivers failed");
425 if (W_ERROR_IS_OK(r.out.result)) {
426 /* TODO: do some more checks here */
427 continue;
429 if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
430 blob = data_blob_talloc(ctx, NULL, needed);
431 data_blob_clear(&blob);
432 r.in.buffer = &blob;
433 r.in.offered = needed;
435 status = dcerpc_spoolss_EnumPrinterDrivers(p, ctx, &r);
436 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EnumPrinterDrivers failed");
439 torture_assert_werr_ok(tctx, r.out.result, "EnumPrinterDrivers failed");
441 CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumPrinterDrivers, info, r.in.level, count, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
443 ctx->driver_count[level] = count;
444 ctx->drivers[level] = info;
447 for (i=1;i<ARRAY_SIZE(levels);i++) {
448 int level = levels[i];
449 int old_level = levels[i-1];
451 torture_assert_int_equal(tctx, ctx->driver_count[level], ctx->driver_count[old_level],
452 "EnumPrinterDrivers invalid value");
455 for (i=0;i<ARRAY_SIZE(levels);i++) {
456 int level = levels[i];
458 for (j=0;j<ctx->driver_count[level];j++) {
459 union spoolss_DriverInfo *cur = &ctx->drivers[level][j];
460 union spoolss_DriverInfo *ref = &ctx->drivers[8][j];
462 switch (level) {
463 case 1:
464 COMPARE_STRING(tctx, cur->info1, ref->info8, driver_name);
465 break;
466 case 2:
467 COMPARE_UINT32(tctx, cur->info2, ref->info8, version);
468 COMPARE_STRING(tctx, cur->info2, ref->info8, driver_name);
469 COMPARE_STRING(tctx, cur->info2, ref->info8, architecture);
470 COMPARE_STRING(tctx, cur->info2, ref->info8, driver_path);
471 COMPARE_STRING(tctx, cur->info2, ref->info8, data_file);
472 COMPARE_STRING(tctx, cur->info2, ref->info8, config_file);
473 break;
474 case 3:
475 COMPARE_UINT32(tctx, cur->info3, ref->info8, version);
476 COMPARE_STRING(tctx, cur->info3, ref->info8, driver_name);
477 COMPARE_STRING(tctx, cur->info3, ref->info8, architecture);
478 COMPARE_STRING(tctx, cur->info3, ref->info8, driver_path);
479 COMPARE_STRING(tctx, cur->info3, ref->info8, data_file);
480 COMPARE_STRING(tctx, cur->info3, ref->info8, config_file);
481 COMPARE_STRING(tctx, cur->info3, ref->info8, help_file);
482 COMPARE_STRING_ARRAY(tctx, cur->info3, ref->info8, dependent_files);
483 COMPARE_STRING(tctx, cur->info3, ref->info8, monitor_name);
484 COMPARE_STRING(tctx, cur->info3, ref->info8, default_datatype);
485 break;
486 case 4:
487 COMPARE_UINT32(tctx, cur->info4, ref->info8, version);
488 COMPARE_STRING(tctx, cur->info4, ref->info8, driver_name);
489 COMPARE_STRING(tctx, cur->info4, ref->info8, architecture);
490 COMPARE_STRING(tctx, cur->info4, ref->info8, driver_path);
491 COMPARE_STRING(tctx, cur->info4, ref->info8, data_file);
492 COMPARE_STRING(tctx, cur->info4, ref->info8, config_file);
493 COMPARE_STRING(tctx, cur->info4, ref->info8, help_file);
494 COMPARE_STRING_ARRAY(tctx, cur->info4, ref->info8, dependent_files);
495 COMPARE_STRING(tctx, cur->info4, ref->info8, monitor_name);
496 COMPARE_STRING(tctx, cur->info4, ref->info8, default_datatype);
497 COMPARE_STRING_ARRAY(tctx, cur->info4, ref->info8, previous_names);
498 break;
499 case 5:
500 COMPARE_UINT32(tctx, cur->info5, ref->info8, version);
501 COMPARE_STRING(tctx, cur->info5, ref->info8, driver_name);
502 COMPARE_STRING(tctx, cur->info5, ref->info8, architecture);
503 COMPARE_STRING(tctx, cur->info5, ref->info8, driver_path);
504 COMPARE_STRING(tctx, cur->info5, ref->info8, data_file);
505 COMPARE_STRING(tctx, cur->info5, ref->info8, config_file);
506 /*COMPARE_UINT32(tctx, cur->info5, ref->info8, driver_attributes);*/
507 /*COMPARE_UINT32(tctx, cur->info5, ref->info8, config_version);*/
508 /*TODO: ! COMPARE_UINT32(tctx, cur->info5, ref->info8, driver_version); */
509 break;
510 case 6:
511 COMPARE_UINT32(tctx, cur->info6, ref->info8, version);
512 COMPARE_STRING(tctx, cur->info6, ref->info8, driver_name);
513 COMPARE_STRING(tctx, cur->info6, ref->info8, architecture);
514 COMPARE_STRING(tctx, cur->info6, ref->info8, driver_path);
515 COMPARE_STRING(tctx, cur->info6, ref->info8, data_file);
516 COMPARE_STRING(tctx, cur->info6, ref->info8, config_file);
517 COMPARE_STRING(tctx, cur->info6, ref->info8, help_file);
518 COMPARE_STRING_ARRAY(tctx, cur->info6, ref->info8, dependent_files);
519 COMPARE_STRING(tctx, cur->info6, ref->info8, monitor_name);
520 COMPARE_STRING(tctx, cur->info6, ref->info8, default_datatype);
521 COMPARE_STRING_ARRAY(tctx, cur->info6, ref->info8, previous_names);
522 COMPARE_NTTIME(tctx, cur->info6, ref->info8, driver_date);
523 COMPARE_UINT64(tctx, cur->info6, ref->info8, driver_version);
524 COMPARE_STRING(tctx, cur->info6, ref->info8, manufacturer_name);
525 COMPARE_STRING(tctx, cur->info6, ref->info8, manufacturer_url);
526 COMPARE_STRING(tctx, cur->info6, ref->info8, hardware_id);
527 COMPARE_STRING(tctx, cur->info6, ref->info8, provider);
528 break;
529 case 8:
530 /* level 8 is our reference, and it makes no sense to compare it to itself */
531 break;
536 return true;
539 static bool test_EnumMonitors(struct torture_context *tctx,
540 struct dcerpc_pipe *p,
541 struct test_spoolss_context *ctx)
543 NTSTATUS status;
544 struct spoolss_EnumMonitors r;
545 uint16_t levels[] = { 1, 2 };
546 int i, j;
548 for (i=0;i<ARRAY_SIZE(levels);i++) {
549 int level = levels[i];
550 DATA_BLOB blob;
551 uint32_t needed;
552 uint32_t count;
553 union spoolss_MonitorInfo *info;
555 r.in.servername = "";
556 r.in.level = level;
557 r.in.buffer = NULL;
558 r.in.offered = 0;
559 r.out.needed = &needed;
560 r.out.count = &count;
561 r.out.info = &info;
563 torture_comment(tctx, "Testing EnumMonitors level %u\n", r.in.level);
565 status = dcerpc_spoolss_EnumMonitors(p, ctx, &r);
566 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EnumMonitors failed");
567 if (W_ERROR_IS_OK(r.out.result)) {
568 /* TODO: do some more checks here */
569 continue;
571 torture_assert_werr_equal(tctx, r.out.result, WERR_INSUFFICIENT_BUFFER,
572 "EnumMonitors failed");
574 blob = data_blob_talloc(ctx, NULL, needed);
575 data_blob_clear(&blob);
576 r.in.buffer = &blob;
577 r.in.offered = needed;
579 status = dcerpc_spoolss_EnumMonitors(p, ctx, &r);
580 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EnumMonitors failed");
582 torture_assert_werr_ok(tctx, r.out.result, "EnumMonitors failed");
584 CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumMonitors, info, r.in.level, count, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
586 ctx->monitor_count[level] = count;
587 ctx->monitors[level] = info;
590 for (i=1;i<ARRAY_SIZE(levels);i++) {
591 int level = levels[i];
592 int old_level = levels[i-1];
593 torture_assert_int_equal(tctx, ctx->monitor_count[level], ctx->monitor_count[old_level],
594 "EnumMonitors invalid value");
597 for (i=0;i<ARRAY_SIZE(levels);i++) {
598 int level = levels[i];
599 for (j=0;j<ctx->monitor_count[level];j++) {
600 union spoolss_MonitorInfo *cur = &ctx->monitors[level][j];
601 union spoolss_MonitorInfo *ref = &ctx->monitors[2][j];
602 switch (level) {
603 case 1:
604 COMPARE_STRING(tctx, cur->info1, ref->info2, monitor_name);
605 break;
606 case 2:
607 /* level 2 is our reference, and it makes no sense to compare it to itself */
608 break;
613 return true;
616 static bool test_EnumPrintProcessors(struct torture_context *tctx,
617 struct dcerpc_pipe *p,
618 struct test_spoolss_context *ctx,
619 const char *environment)
621 NTSTATUS status;
622 struct spoolss_EnumPrintProcessors r;
623 uint16_t levels[] = { 1 };
624 int i, j;
626 for (i=0;i<ARRAY_SIZE(levels);i++) {
627 int level = levels[i];
628 DATA_BLOB blob;
629 uint32_t needed;
630 uint32_t count;
631 union spoolss_PrintProcessorInfo *info;
633 r.in.servername = "";
634 r.in.environment = environment;
635 r.in.level = level;
636 r.in.buffer = NULL;
637 r.in.offered = 0;
638 r.out.needed = &needed;
639 r.out.count = &count;
640 r.out.info = &info;
642 torture_comment(tctx, "Testing EnumPrintProcessors level %u\n", r.in.level);
644 status = dcerpc_spoolss_EnumPrintProcessors(p, ctx, &r);
645 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EnumPrintProcessors failed");
646 if (W_ERROR_IS_OK(r.out.result)) {
647 /* TODO: do some more checks here */
648 continue;
650 torture_assert_werr_equal(tctx, r.out.result, WERR_INSUFFICIENT_BUFFER,
651 "EnumPrintProcessors unexpected return code");
653 blob = data_blob_talloc(ctx, NULL, needed);
654 data_blob_clear(&blob);
655 r.in.buffer = &blob;
656 r.in.offered = needed;
658 status = dcerpc_spoolss_EnumPrintProcessors(p, ctx, &r);
659 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EnumPrintProcessors failed");
661 torture_assert_werr_ok(tctx, r.out.result, "EnumPrintProcessors failed");
663 CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumPrintProcessors, info, r.in.level, count, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
665 ctx->print_processor_count[level] = count;
666 ctx->print_processors[level] = info;
669 for (i=1;i<ARRAY_SIZE(levels);i++) {
670 int level = levels[i];
671 int old_level = levels[i-1];
672 torture_assert_int_equal(tctx, ctx->print_processor_count[level], ctx->print_processor_count[old_level],
673 "EnumPrintProcessors failed");
676 for (i=0;i<ARRAY_SIZE(levels);i++) {
677 int level = levels[i];
678 for (j=0;j<ctx->print_processor_count[level];j++) {
679 #if 0
680 union spoolss_PrintProcessorInfo *cur = &ctx->print_processors[level][j];
681 union spoolss_PrintProcessorInfo *ref = &ctx->print_processors[1][j];
682 #endif
683 switch (level) {
684 case 1:
685 /* level 1 is our reference, and it makes no sense to compare it to itself */
686 break;
691 return true;
694 static bool test_EnumPrintProcDataTypes(struct torture_context *tctx,
695 struct dcerpc_pipe *p,
696 struct test_spoolss_context *ctx)
698 NTSTATUS status;
699 struct spoolss_EnumPrintProcDataTypes r;
700 uint16_t levels[] = { 1 };
701 int i;
703 for (i=0;i<ARRAY_SIZE(levels);i++) {
704 int level = levels[i];
705 DATA_BLOB blob;
706 uint32_t needed;
707 uint32_t count;
708 union spoolss_PrintProcDataTypesInfo *info;
710 r.in.servername = "";
711 r.in.print_processor_name = "winprint";
712 r.in.level = level;
713 r.in.buffer = NULL;
714 r.in.offered = 0;
715 r.out.needed = &needed;
716 r.out.count = &count;
717 r.out.info = &info;
719 torture_comment(tctx, "Testing EnumPrintProcDataTypes level %u\n", r.in.level);
721 status = dcerpc_spoolss_EnumPrintProcDataTypes(p, ctx, &r);
722 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EnumPrintProcDataType failed");
723 if (W_ERROR_IS_OK(r.out.result)) {
724 /* TODO: do some more checks here */
725 continue;
727 torture_assert_werr_equal(tctx, r.out.result, WERR_INSUFFICIENT_BUFFER,
728 "EnumPrintProcDataTypes unexpected return code");
730 blob = data_blob_talloc(ctx, NULL, needed);
731 data_blob_clear(&blob);
732 r.in.buffer = &blob;
733 r.in.offered = needed;
735 status = dcerpc_spoolss_EnumPrintProcDataTypes(p, ctx, &r);
736 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EnumPrintProcDataTypes failed");
738 torture_assert_werr_ok(tctx, r.out.result, "EnumPrintProcDataTypes failed");
740 CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumPrintProcDataTypes, info, r.in.level, count, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
744 return true;
748 static bool test_EnumPrinters(struct torture_context *tctx,
749 struct dcerpc_pipe *p,
750 struct test_spoolss_context *ctx)
752 struct spoolss_EnumPrinters r;
753 NTSTATUS status;
754 uint16_t levels[] = { 0, 1, 2, 4, 5 };
755 int i, j;
757 for (i=0;i<ARRAY_SIZE(levels);i++) {
758 int level = levels[i];
759 DATA_BLOB blob;
760 uint32_t needed;
761 uint32_t count;
762 union spoolss_PrinterInfo *info;
764 r.in.flags = PRINTER_ENUM_LOCAL;
765 r.in.server = "";
766 r.in.level = level;
767 r.in.buffer = NULL;
768 r.in.offered = 0;
769 r.out.needed = &needed;
770 r.out.count = &count;
771 r.out.info = &info;
773 torture_comment(tctx, "Testing EnumPrinters level %u\n", r.in.level);
775 status = dcerpc_spoolss_EnumPrinters(p, ctx, &r);
776 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EnumPrinters failed");
777 if (W_ERROR_IS_OK(r.out.result)) {
778 /* TODO: do some more checks here */
779 continue;
781 torture_assert_werr_equal(tctx, r.out.result, WERR_INSUFFICIENT_BUFFER,
782 "EnumPrinters unexpected return code");
784 blob = data_blob_talloc(ctx, NULL, needed);
785 data_blob_clear(&blob);
786 r.in.buffer = &blob;
787 r.in.offered = needed;
789 status = dcerpc_spoolss_EnumPrinters(p, ctx, &r);
790 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EnumPrinters failed");
792 torture_assert_werr_ok(tctx, r.out.result, "EnumPrinters failed");
794 CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumPrinters, info, r.in.level, count, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
796 ctx->printer_count[level] = count;
797 ctx->printers[level] = info;
800 for (i=1;i<ARRAY_SIZE(levels);i++) {
801 int level = levels[i];
802 int old_level = levels[i-1];
803 torture_assert_int_equal(tctx, ctx->printer_count[level], ctx->printer_count[old_level],
804 "EnumPrinters invalid value");
807 for (i=0;i<ARRAY_SIZE(levels);i++) {
808 int level = levels[i];
809 for (j=0;j<ctx->printer_count[level];j++) {
810 union spoolss_PrinterInfo *cur = &ctx->printers[level][j];
811 union spoolss_PrinterInfo *ref = &ctx->printers[2][j];
812 switch (level) {
813 case 0:
814 COMPARE_STRING(tctx, cur->info0, ref->info2, printername);
815 COMPARE_STRING(tctx, cur->info0, ref->info2, servername);
816 COMPARE_UINT32(tctx, cur->info0, ref->info2, cjobs);
817 /*COMPARE_UINT32(tctx, cur->info0, ref->info2, total_jobs);
818 COMPARE_UINT32(tctx, cur->info0, ref->info2, total_bytes);
819 COMPARE_SPOOLSS_TIME(cur->info0, ref->info2, spoolss_Time time);
820 COMPARE_UINT32(tctx, cur->info0, ref->info2, global_counter);
821 COMPARE_UINT32(tctx, cur->info0, ref->info2, total_pages);
822 COMPARE_UINT32(tctx, cur->info0, ref->info2, version);
823 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown10);
824 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown11);
825 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown12);
826 COMPARE_UINT32(tctx, cur->info0, ref->info2, session_counter);
827 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown14);
828 COMPARE_UINT32(tctx, cur->info0, ref->info2, printer_errors);
829 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown16);
830 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown17);
831 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown18);
832 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown19);
833 COMPARE_UINT32(tctx, cur->info0, ref->info2, change_id);
834 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown21);*/
835 COMPARE_UINT32(tctx, cur->info0, ref->info2, status);
836 /*COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown23);
837 COMPARE_UINT32(tctx, cur->info0, ref->info2, c_setprinter);
838 COMPARE_UINT16(cur->info0, ref->info2, unknown25);
839 COMPARE_UINT16(cur->info0, ref->info2, unknown26);
840 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown27);
841 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown28);
842 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown29);*/
843 break;
844 case 1:
845 /*COMPARE_UINT32(tctx, cur->info1, ref->info2, flags);*/
846 /*COMPARE_STRING(tctx, cur->info1, ref->info2, name);*/
847 /*COMPARE_STRING(tctx, cur->info1, ref->info2, description);*/
848 COMPARE_STRING(tctx, cur->info1, ref->info2, comment);
849 break;
850 case 2:
851 /* level 2 is our reference, and it makes no sense to compare it to itself */
852 break;
853 case 4:
854 COMPARE_STRING(tctx, cur->info4, ref->info2, printername);
855 COMPARE_STRING(tctx, cur->info4, ref->info2, servername);
856 COMPARE_UINT32(tctx, cur->info4, ref->info2, attributes);
857 break;
858 case 5:
859 COMPARE_STRING(tctx, cur->info5, ref->info2, printername);
860 COMPARE_STRING(tctx, cur->info5, ref->info2, portname);
861 COMPARE_UINT32(tctx, cur->info5, ref->info2, attributes);
862 /*COMPARE_UINT32(tctx, cur->info5, ref->info2, device_not_selected_timeout);
863 COMPARE_UINT32(tctx, cur->info5, ref->info2, transmission_retry_timeout);*/
864 break;
869 /* TODO:
870 * - verify that the port of a printer was in the list returned by EnumPorts
873 return true;
876 static bool test_GetPrinterDriver2(struct torture_context *tctx,
877 struct dcerpc_pipe *p,
878 struct policy_handle *handle,
879 const char *driver_name,
880 const char *environment);
882 bool test_GetPrinter_level(struct torture_context *tctx,
883 struct dcerpc_pipe *p,
884 struct policy_handle *handle,
885 uint32_t level,
886 union spoolss_PrinterInfo *info)
888 struct spoolss_GetPrinter r;
889 uint32_t needed;
891 r.in.handle = handle;
892 r.in.level = level;
893 r.in.buffer = NULL;
894 r.in.offered = 0;
895 r.out.needed = &needed;
897 torture_comment(tctx, "Testing GetPrinter level %u\n", r.in.level);
899 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_GetPrinter(p, tctx, &r),
900 "GetPrinter failed");
902 if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
903 DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed);
904 data_blob_clear(&blob);
905 r.in.buffer = &blob;
906 r.in.offered = needed;
908 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_GetPrinter(p, tctx, &r),
909 "GetPrinter failed");
912 torture_assert_werr_ok(tctx, r.out.result, "GetPrinter failed");
914 CHECK_NEEDED_SIZE_LEVEL(spoolss_PrinterInfo, r.out.info, r.in.level, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
916 if (info && r.out.info) {
917 *info = *r.out.info;
920 return true;
924 static bool test_GetPrinter(struct torture_context *tctx,
925 struct dcerpc_pipe *p,
926 struct policy_handle *handle,
927 const char *environment)
929 uint32_t levels[] = {0, 1, 2, 3, 4, 5, 6, 7, 8};
930 int i;
932 for (i=0;i<ARRAY_SIZE(levels);i++) {
934 union spoolss_PrinterInfo info;
936 ZERO_STRUCT(info);
938 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, levels[i], &info),
939 "failed to call GetPrinter");
941 if ((levels[i] == 2) && info.info2.drivername && strlen(info.info2.drivername)) {
942 torture_assert(tctx,
943 test_GetPrinterDriver2(tctx, p, handle, info.info2.drivername, environment),
944 "failed to call test_GetPrinterDriver2");
948 return true;
951 static bool test_SetPrinter(struct torture_context *tctx,
952 struct dcerpc_pipe *p,
953 struct policy_handle *handle,
954 struct spoolss_SetPrinterInfoCtr *info_ctr,
955 struct spoolss_DevmodeContainer *devmode_ctr,
956 struct sec_desc_buf *secdesc_ctr,
957 enum spoolss_PrinterControl command)
959 struct spoolss_SetPrinter r;
961 r.in.handle = handle;
962 r.in.info_ctr = info_ctr;
963 r.in.devmode_ctr = devmode_ctr;
964 r.in.secdesc_ctr = secdesc_ctr;
965 r.in.command = command;
967 torture_comment(tctx, "Testing SetPrinter level %d\n", r.in.info_ctr->level);
969 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_SetPrinter(p, tctx, &r),
970 "failed to call SetPrinter");
971 torture_assert_werr_ok(tctx, r.out.result,
972 "failed to call SetPrinter");
974 return true;
977 static bool test_SetPrinter_errors(struct torture_context *tctx,
978 struct dcerpc_pipe *p,
979 struct policy_handle *handle)
981 struct spoolss_SetPrinter r;
982 uint16_t levels[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
983 int i;
985 struct spoolss_SetPrinterInfoCtr info_ctr;
986 struct spoolss_DevmodeContainer devmode_ctr;
987 struct sec_desc_buf secdesc_ctr;
989 info_ctr.level = 0;
990 info_ctr.info.info0 = NULL;
992 ZERO_STRUCT(devmode_ctr);
993 ZERO_STRUCT(secdesc_ctr);
995 r.in.handle = handle;
996 r.in.info_ctr = &info_ctr;
997 r.in.devmode_ctr = &devmode_ctr;
998 r.in.secdesc_ctr = &secdesc_ctr;
999 r.in.command = 0;
1001 torture_comment(tctx, "Testing SetPrinter all zero\n");
1003 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_SetPrinter(p, tctx, &r),
1004 "failed to call SetPrinter");
1005 torture_assert_werr_equal(tctx, r.out.result, WERR_INVALID_PARAM,
1006 "failed to call SetPrinter");
1008 again:
1009 for (i=0; i < ARRAY_SIZE(levels); i++) {
1011 struct spoolss_SetPrinterInfo0 info0;
1012 struct spoolss_SetPrinterInfo1 info1;
1013 struct spoolss_SetPrinterInfo2 info2;
1014 struct spoolss_SetPrinterInfo3 info3;
1015 struct spoolss_SetPrinterInfo4 info4;
1016 struct spoolss_SetPrinterInfo5 info5;
1017 struct spoolss_SetPrinterInfo6 info6;
1018 struct spoolss_SetPrinterInfo7 info7;
1019 struct spoolss_SetPrinterInfo8 info8;
1020 struct spoolss_SetPrinterInfo9 info9;
1023 info_ctr.level = levels[i];
1024 switch (levels[i]) {
1025 case 0:
1026 ZERO_STRUCT(info0);
1027 info_ctr.info.info0 = &info0;
1028 break;
1029 case 1:
1030 ZERO_STRUCT(info1);
1031 info_ctr.info.info1 = &info1;
1032 break;
1033 case 2:
1034 ZERO_STRUCT(info2);
1035 info_ctr.info.info2 = &info2;
1036 break;
1037 case 3:
1038 ZERO_STRUCT(info3);
1039 info_ctr.info.info3 = &info3;
1040 break;
1041 case 4:
1042 ZERO_STRUCT(info4);
1043 info_ctr.info.info4 = &info4;
1044 break;
1045 case 5:
1046 ZERO_STRUCT(info5);
1047 info_ctr.info.info5 = &info5;
1048 break;
1049 case 6:
1050 ZERO_STRUCT(info6);
1051 info_ctr.info.info6 = &info6;
1052 break;
1053 case 7:
1054 ZERO_STRUCT(info7);
1055 info_ctr.info.info7 = &info7;
1056 break;
1057 case 8:
1058 ZERO_STRUCT(info8);
1059 info_ctr.info.info8 = &info8;
1060 break;
1061 case 9:
1062 ZERO_STRUCT(info9);
1063 info_ctr.info.info9 = &info9;
1064 break;
1067 torture_comment(tctx, "Testing SetPrinter level %d, command %d\n",
1068 info_ctr.level, r.in.command);
1070 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_SetPrinter(p, tctx, &r),
1071 "failed to call SetPrinter");
1073 switch (r.in.command) {
1074 case SPOOLSS_PRINTER_CONTROL_UNPAUSE: /* 0 */
1075 /* is ignored for all levels other then 0 */
1076 if (info_ctr.level > 0) {
1077 /* ignored then */
1078 break;
1080 case SPOOLSS_PRINTER_CONTROL_PAUSE: /* 1 */
1081 case SPOOLSS_PRINTER_CONTROL_RESUME: /* 2 */
1082 case SPOOLSS_PRINTER_CONTROL_PURGE: /* 3 */
1083 if (info_ctr.level > 0) {
1084 /* is invalid for all levels other then 0 */
1085 torture_assert_werr_equal(tctx, r.out.result, WERR_INVALID_PRINTER_COMMAND,
1086 "unexpected error code returned");
1087 continue;
1088 } else {
1089 torture_assert_werr_ok(tctx, r.out.result,
1090 "failed to call SetPrinter with non 0 command");
1091 continue;
1093 break;
1095 case SPOOLSS_PRINTER_CONTROL_SET_STATUS: /* 4 */
1096 /* FIXME: gd needs further investigation */
1097 default:
1098 torture_assert_werr_equal(tctx, r.out.result, WERR_INVALID_PRINTER_COMMAND,
1099 "unexpected error code returned");
1100 continue;
1103 switch (info_ctr.level) {
1104 case 1:
1105 torture_assert_werr_equal(tctx, r.out.result, WERR_UNKNOWN_LEVEL,
1106 "unexpected error code returned");
1107 break;
1108 case 2:
1109 torture_assert_werr_equal(tctx, r.out.result, WERR_UNKNOWN_PRINTER_DRIVER,
1110 "unexpected error code returned");
1111 break;
1112 case 3:
1113 case 4:
1114 case 5:
1115 case 7:
1116 torture_assert_werr_equal(tctx, r.out.result, WERR_INVALID_PARAM,
1117 "unexpected error code returned");
1118 break;
1119 case 9:
1120 torture_assert_werr_equal(tctx, r.out.result, WERR_NOT_SUPPORTED,
1121 "unexpected error code returned");
1122 break;
1123 default:
1124 torture_assert_werr_ok(tctx, r.out.result,
1125 "failed to call SetPrinter");
1126 break;
1130 if (r.in.command < 5) {
1131 r.in.command++;
1132 goto again;
1135 return true;
1138 static void clear_info2(struct spoolss_SetPrinterInfoCtr *r)
1140 if ((r->level == 2) && (r->info.info2)) {
1141 r->info.info2->secdesc_ptr = 0;
1142 r->info.info2->devmode_ptr = 0;
1146 static bool test_PrinterInfo(struct torture_context *tctx,
1147 struct dcerpc_pipe *p,
1148 struct policy_handle *handle)
1150 NTSTATUS status;
1151 struct spoolss_SetPrinter s;
1152 struct spoolss_GetPrinter q;
1153 struct spoolss_GetPrinter q0;
1154 struct spoolss_SetPrinterInfoCtr info_ctr;
1155 union spoolss_PrinterInfo info;
1156 struct spoolss_DevmodeContainer devmode_ctr;
1157 struct sec_desc_buf secdesc_ctr;
1158 uint32_t needed;
1159 bool ret = true;
1160 int i;
1162 uint32_t status_list[] = {
1163 /* these do not stick
1164 PRINTER_STATUS_PAUSED,
1165 PRINTER_STATUS_ERROR,
1166 PRINTER_STATUS_PENDING_DELETION, */
1167 PRINTER_STATUS_PAPER_JAM,
1168 PRINTER_STATUS_PAPER_OUT,
1169 PRINTER_STATUS_MANUAL_FEED,
1170 PRINTER_STATUS_PAPER_PROBLEM,
1171 PRINTER_STATUS_OFFLINE,
1172 PRINTER_STATUS_IO_ACTIVE,
1173 PRINTER_STATUS_BUSY,
1174 PRINTER_STATUS_PRINTING,
1175 PRINTER_STATUS_OUTPUT_BIN_FULL,
1176 PRINTER_STATUS_NOT_AVAILABLE,
1177 PRINTER_STATUS_WAITING,
1178 PRINTER_STATUS_PROCESSING,
1179 PRINTER_STATUS_INITIALIZING,
1180 PRINTER_STATUS_WARMING_UP,
1181 PRINTER_STATUS_TONER_LOW,
1182 PRINTER_STATUS_NO_TONER,
1183 PRINTER_STATUS_PAGE_PUNT,
1184 PRINTER_STATUS_USER_INTERVENTION,
1185 PRINTER_STATUS_OUT_OF_MEMORY,
1186 PRINTER_STATUS_DOOR_OPEN,
1187 PRINTER_STATUS_SERVER_UNKNOWN,
1188 PRINTER_STATUS_POWER_SAVE,
1189 /* these do not stick
1190 0x02000000,
1191 0x04000000,
1192 0x08000000,
1193 0x10000000,
1194 0x20000000,
1195 0x40000000,
1196 0x80000000 */
1198 uint32_t default_attribute = PRINTER_ATTRIBUTE_LOCAL;
1199 uint32_t attribute_list[] = {
1200 PRINTER_ATTRIBUTE_QUEUED,
1201 /* fails with WERR_INVALID_DATATYPE:
1202 PRINTER_ATTRIBUTE_DIRECT, */
1203 /* does not stick
1204 PRINTER_ATTRIBUTE_DEFAULT, */
1205 PRINTER_ATTRIBUTE_SHARED,
1206 /* does not stick
1207 PRINTER_ATTRIBUTE_NETWORK, */
1208 PRINTER_ATTRIBUTE_HIDDEN,
1209 PRINTER_ATTRIBUTE_LOCAL,
1210 PRINTER_ATTRIBUTE_ENABLE_DEVQ,
1211 PRINTER_ATTRIBUTE_KEEPPRINTEDJOBS,
1212 PRINTER_ATTRIBUTE_DO_COMPLETE_FIRST,
1213 PRINTER_ATTRIBUTE_WORK_OFFLINE,
1214 /* does not stick
1215 PRINTER_ATTRIBUTE_ENABLE_BIDI, */
1216 /* fails with WERR_INVALID_DATATYPE:
1217 PRINTER_ATTRIBUTE_RAW_ONLY, */
1218 /* these do not stick
1219 PRINTER_ATTRIBUTE_PUBLISHED,
1220 PRINTER_ATTRIBUTE_FAX,
1221 PRINTER_ATTRIBUTE_TS,
1222 0x00010000,
1223 0x00020000,
1224 0x00040000,
1225 0x00080000,
1226 0x00100000,
1227 0x00200000,
1228 0x00400000,
1229 0x00800000,
1230 0x01000000,
1231 0x02000000,
1232 0x04000000,
1233 0x08000000,
1234 0x10000000,
1235 0x20000000,
1236 0x40000000,
1237 0x80000000 */
1240 ZERO_STRUCT(devmode_ctr);
1241 ZERO_STRUCT(secdesc_ctr);
1243 s.in.handle = handle;
1244 s.in.command = 0;
1245 s.in.info_ctr = &info_ctr;
1246 s.in.devmode_ctr = &devmode_ctr;
1247 s.in.secdesc_ctr = &secdesc_ctr;
1249 q.in.handle = handle;
1250 q.out.info = &info;
1251 q0 = q;
1253 #define TESTGETCALL(call, r) \
1254 r.in.buffer = NULL; \
1255 r.in.offered = 0;\
1256 r.out.needed = &needed; \
1257 status = dcerpc_spoolss_ ##call(p, tctx, &r); \
1258 if (!NT_STATUS_IS_OK(status)) { \
1259 torture_comment(tctx, #call " level %u failed - %s (%s)\n", \
1260 r.in.level, nt_errstr(status), __location__); \
1261 ret = false; \
1262 break; \
1264 if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {\
1265 DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed); \
1266 data_blob_clear(&blob); \
1267 r.in.buffer = &blob; \
1268 r.in.offered = needed; \
1270 status = dcerpc_spoolss_ ##call(p, tctx, &r); \
1271 if (!NT_STATUS_IS_OK(status)) { \
1272 torture_comment(tctx, #call " level %u failed - %s (%s)\n", \
1273 r.in.level, nt_errstr(status), __location__); \
1274 ret = false; \
1275 break; \
1277 if (!W_ERROR_IS_OK(r.out.result)) { \
1278 torture_comment(tctx, #call " level %u failed - %s (%s)\n", \
1279 r.in.level, win_errstr(r.out.result), __location__); \
1280 ret = false; \
1281 break; \
1285 #define TESTSETCALL_EXP(call, r, err) \
1286 clear_info2(&info_ctr);\
1287 status = dcerpc_spoolss_ ##call(p, tctx, &r); \
1288 if (!NT_STATUS_IS_OK(status)) { \
1289 torture_comment(tctx, #call " level %u failed - %s (%s)\n", \
1290 r.in.info_ctr->level, nt_errstr(status), __location__); \
1291 ret = false; \
1292 break; \
1294 if (!W_ERROR_IS_OK(err)) { \
1295 if (!W_ERROR_EQUAL(err, r.out.result)) { \
1296 torture_comment(tctx, #call " level %u failed - %s, expected %s (%s)\n", \
1297 r.in.info_ctr->level, win_errstr(r.out.result), win_errstr(err), __location__); \
1298 ret = false; \
1300 break; \
1302 if (!W_ERROR_IS_OK(r.out.result)) { \
1303 torture_comment(tctx, #call " level %u failed - %s (%s)\n", \
1304 r.in.info_ctr->level, win_errstr(r.out.result), __location__); \
1305 ret = false; \
1306 break; \
1309 #define TESTSETCALL(call, r) \
1310 TESTSETCALL_EXP(call, r, WERR_OK)
1312 #define STRING_EQUAL(s1, s2, field) \
1313 if ((s1 && !s2) || (s2 && !s1) || strcmp(s1, s2)) { \
1314 torture_comment(tctx, "Failed to set %s to '%s' (%s)\n", \
1315 #field, s2, __location__); \
1316 ret = false; \
1317 break; \
1320 #define MEM_EQUAL(s1, s2, length, field) \
1321 if ((s1 && !s2) || (s2 && !s1) || memcmp(s1, s2, length)) { \
1322 torture_comment(tctx, "Failed to set %s to '%s' (%s)\n", \
1323 #field, (const char *)s2, __location__); \
1324 ret = false; \
1325 break; \
1328 #define INT_EQUAL(i1, i2, field) \
1329 if (i1 != i2) { \
1330 torture_comment(tctx, "Failed to set %s to 0x%llx - got 0x%llx (%s)\n", \
1331 #field, (unsigned long long)i2, (unsigned long long)i1, __location__); \
1332 ret = false; \
1333 break; \
1336 #define SD_EQUAL(sd1, sd2, field) \
1337 if (!security_descriptor_equal(sd1, sd2)) { \
1338 torture_comment(tctx, "Failed to set %s (%s)\n", \
1339 #field, __location__); \
1340 ret = false; \
1341 break; \
1344 #define TEST_PRINTERINFO_STRING_EXP_ERR(lvl1, field1, lvl2, field2, value, err) do { \
1345 torture_comment(tctx, "field test %d/%s vs %d/%s\n", lvl1, #field1, lvl2, #field2); \
1346 q.in.level = lvl1; \
1347 TESTGETCALL(GetPrinter, q) \
1348 info_ctr.level = lvl1; \
1349 info_ctr.info.info ## lvl1 = (struct spoolss_SetPrinterInfo ## lvl1 *)&q.out.info->info ## lvl1; \
1350 info_ctr.info.info ## lvl1->field1 = value;\
1351 TESTSETCALL_EXP(SetPrinter, s, err) \
1352 info_ctr.info.info ## lvl1->field1 = ""; \
1353 TESTGETCALL(GetPrinter, q) \
1354 info_ctr.info.info ## lvl1->field1 = value; \
1355 STRING_EQUAL(info_ctr.info.info ## lvl1->field1, value, field1); \
1356 q.in.level = lvl2; \
1357 TESTGETCALL(GetPrinter, q) \
1358 info_ctr.info.info ## lvl2 = (struct spoolss_SetPrinterInfo ## lvl2 *)&q.out.info->info ## lvl2; \
1359 STRING_EQUAL(info_ctr.info.info ## lvl2->field2, value, field2); \
1360 } while (0)
1362 #define TEST_PRINTERINFO_STRING(lvl1, field1, lvl2, field2, value) do { \
1363 TEST_PRINTERINFO_STRING_EXP_ERR(lvl1, field1, lvl2, field2, value, WERR_OK); \
1364 } while (0);
1366 #define TEST_PRINTERINFO_INT_EXP(lvl1, field1, lvl2, field2, value, exp_value) do { \
1367 torture_comment(tctx, "field test %d/%s vs %d/%s\n", lvl1, #field1, lvl2, #field2); \
1368 q.in.level = lvl1; \
1369 TESTGETCALL(GetPrinter, q) \
1370 info_ctr.level = lvl1; \
1371 info_ctr.info.info ## lvl1 = (struct spoolss_SetPrinterInfo ## lvl1 *)&q.out.info->info ## lvl1; \
1372 info_ctr.info.info ## lvl1->field1 = value; \
1373 TESTSETCALL(SetPrinter, s) \
1374 info_ctr.info.info ## lvl1->field1 = 0; \
1375 TESTGETCALL(GetPrinter, q) \
1376 info_ctr.info.info ## lvl1 = (struct spoolss_SetPrinterInfo ## lvl1 *)&q.out.info->info ## lvl1; \
1377 INT_EQUAL(info_ctr.info.info ## lvl1->field1, exp_value, field1); \
1378 q.in.level = lvl2; \
1379 TESTGETCALL(GetPrinter, q) \
1380 info_ctr.info.info ## lvl2 = (struct spoolss_SetPrinterInfo ## lvl2 *)&q.out.info->info ## lvl2; \
1381 INT_EQUAL(info_ctr.info.info ## lvl2->field2, exp_value, field1); \
1382 } while (0)
1384 #define TEST_PRINTERINFO_INT(lvl1, field1, lvl2, field2, value) do { \
1385 TEST_PRINTERINFO_INT_EXP(lvl1, field1, lvl2, field2, value, value); \
1386 } while (0)
1388 q0.in.level = 0;
1389 do { TESTGETCALL(GetPrinter, q0) } while (0);
1391 TEST_PRINTERINFO_STRING(2, comment, 1, comment, "xx2-1 comment");
1392 TEST_PRINTERINFO_STRING(2, comment, 2, comment, "xx2-2 comment");
1394 /* level 0 printername does not stick */
1395 /* TEST_PRINTERINFO_STRING(2, printername, 0, printername, "xx2-0 printer"); */
1396 TEST_PRINTERINFO_STRING(2, printername, 1, name, "xx2-1 printer");
1397 TEST_PRINTERINFO_STRING(2, printername, 2, printername, "xx2-2 printer");
1398 TEST_PRINTERINFO_STRING(2, printername, 4, printername, "xx2-4 printer");
1399 TEST_PRINTERINFO_STRING(2, printername, 5, printername, "xx2-5 printer");
1400 /* TEST_PRINTERINFO_STRING(4, printername, 0, printername, "xx4-0 printer"); */
1401 TEST_PRINTERINFO_STRING(4, printername, 1, name, "xx4-1 printer");
1402 TEST_PRINTERINFO_STRING(4, printername, 2, printername, "xx4-2 printer");
1403 TEST_PRINTERINFO_STRING(4, printername, 4, printername, "xx4-4 printer");
1404 TEST_PRINTERINFO_STRING(4, printername, 5, printername, "xx4-5 printer");
1405 /* TEST_PRINTERINFO_STRING(5, printername, 0, printername, "xx5-0 printer"); */
1406 TEST_PRINTERINFO_STRING(5, printername, 1, name, "xx5-1 printer");
1407 TEST_PRINTERINFO_STRING(5, printername, 2, printername, "xx5-2 printer");
1408 TEST_PRINTERINFO_STRING(5, printername, 4, printername, "xx5-4 printer");
1409 TEST_PRINTERINFO_STRING(5, printername, 5, printername, "xx5-5 printer");
1411 /* servername can be set but does not stick
1412 TEST_PRINTERINFO_STRING(2, servername, 0, servername, "xx2-0 servername");
1413 TEST_PRINTERINFO_STRING(2, servername, 2, servername, "xx2-2 servername");
1414 TEST_PRINTERINFO_STRING(2, servername, 4, servername, "xx2-4 servername");
1417 /* passing an invalid port will result in WERR_UNKNOWN_PORT */
1418 TEST_PRINTERINFO_STRING_EXP_ERR(2, portname, 2, portname, "xx2-2 portname", WERR_UNKNOWN_PORT);
1419 TEST_PRINTERINFO_STRING_EXP_ERR(2, portname, 5, portname, "xx2-5 portname", WERR_UNKNOWN_PORT);
1420 TEST_PRINTERINFO_STRING_EXP_ERR(5, portname, 2, portname, "xx5-2 portname", WERR_UNKNOWN_PORT);
1421 TEST_PRINTERINFO_STRING_EXP_ERR(5, portname, 5, portname, "xx5-5 portname", WERR_UNKNOWN_PORT);
1423 TEST_PRINTERINFO_STRING(2, sharename, 2, sharename, "xx2-2 sharename");
1424 /* passing an invalid driver will result in WERR_UNKNOWN_PRINTER_DRIVER */
1425 TEST_PRINTERINFO_STRING_EXP_ERR(2, drivername, 2, drivername, "xx2-2 drivername", WERR_UNKNOWN_PRINTER_DRIVER);
1426 TEST_PRINTERINFO_STRING(2, location, 2, location, "xx2-2 location");
1427 /* passing an invalid sepfile will result in WERR_INVALID_SEPARATOR_FILE */
1428 TEST_PRINTERINFO_STRING_EXP_ERR(2, sepfile, 2, sepfile, "xx2-2 sepfile", WERR_INVALID_SEPARATOR_FILE);
1429 /* passing an invalid printprocessor will result in WERR_UNKNOWN_PRINTPROCESSOR */
1430 TEST_PRINTERINFO_STRING_EXP_ERR(2, printprocessor, 2, printprocessor, "xx2-2 printprocessor", WERR_UNKNOWN_PRINTPROCESSOR);
1431 TEST_PRINTERINFO_STRING(2, datatype, 2, datatype, "xx2-2 datatype");
1432 TEST_PRINTERINFO_STRING(2, parameters, 2, parameters, "xx2-2 parameters");
1434 for (i=0; i < ARRAY_SIZE(attribute_list); i++) {
1435 /* TEST_PRINTERINFO_INT_EXP(2, attributes, 1, flags,
1436 attribute_list[i],
1437 (attribute_list[i] | default_attribute)
1438 ); */
1439 TEST_PRINTERINFO_INT_EXP(2, attributes, 2, attributes,
1440 attribute_list[i],
1441 (attribute_list[i] | default_attribute)
1443 TEST_PRINTERINFO_INT_EXP(2, attributes, 4, attributes,
1444 attribute_list[i],
1445 (attribute_list[i] | default_attribute)
1447 TEST_PRINTERINFO_INT_EXP(2, attributes, 5, attributes,
1448 attribute_list[i],
1449 (attribute_list[i] | default_attribute)
1451 /* TEST_PRINTERINFO_INT_EXP(4, attributes, 1, flags,
1452 attribute_list[i],
1453 (attribute_list[i] | default_attribute)
1454 ); */
1455 TEST_PRINTERINFO_INT_EXP(4, attributes, 2, attributes,
1456 attribute_list[i],
1457 (attribute_list[i] | default_attribute)
1459 TEST_PRINTERINFO_INT_EXP(4, attributes, 4, attributes,
1460 attribute_list[i],
1461 (attribute_list[i] | default_attribute)
1463 TEST_PRINTERINFO_INT_EXP(4, attributes, 5, attributes,
1464 attribute_list[i],
1465 (attribute_list[i] | default_attribute)
1467 /* TEST_PRINTERINFO_INT_EXP(5, attributes, 1, flags,
1468 attribute_list[i],
1469 (attribute_list[i] | default_attribute)
1470 ); */
1471 TEST_PRINTERINFO_INT_EXP(5, attributes, 2, attributes,
1472 attribute_list[i],
1473 (attribute_list[i] | default_attribute)
1475 TEST_PRINTERINFO_INT_EXP(5, attributes, 4, attributes,
1476 attribute_list[i],
1477 (attribute_list[i] | default_attribute)
1479 TEST_PRINTERINFO_INT_EXP(5, attributes, 5, attributes,
1480 attribute_list[i],
1481 (attribute_list[i] | default_attribute)
1485 for (i=0; i < ARRAY_SIZE(status_list); i++) {
1486 /* level 2 sets do not stick
1487 TEST_PRINTERINFO_INT(2, status, 0, status, status_list[i]);
1488 TEST_PRINTERINFO_INT(2, status, 2, status, status_list[i]);
1489 TEST_PRINTERINFO_INT(2, status, 6, status, status_list[i]); */
1490 TEST_PRINTERINFO_INT(6, status, 0, status, status_list[i]);
1491 TEST_PRINTERINFO_INT(6, status, 2, status, status_list[i]);
1492 TEST_PRINTERINFO_INT(6, status, 6, status, status_list[i]);
1495 /* priorities need to be between 0 and 99
1496 passing an invalid priority will result in WERR_INVALID_PRIORITY */
1497 TEST_PRINTERINFO_INT(2, priority, 2, priority, 0);
1498 TEST_PRINTERINFO_INT(2, priority, 2, priority, 1);
1499 TEST_PRINTERINFO_INT(2, priority, 2, priority, 99);
1500 /* TEST_PRINTERINFO_INT(2, priority, 2, priority, 100); */
1501 TEST_PRINTERINFO_INT(2, defaultpriority,2, defaultpriority, 0);
1502 TEST_PRINTERINFO_INT(2, defaultpriority,2, defaultpriority, 1);
1503 TEST_PRINTERINFO_INT(2, defaultpriority,2, defaultpriority, 99);
1504 /* TEST_PRINTERINFO_INT(2, defaultpriority,2, defaultpriority, 100); */
1506 TEST_PRINTERINFO_INT(2, starttime, 2, starttime, __LINE__);
1507 TEST_PRINTERINFO_INT(2, untiltime, 2, untiltime, __LINE__);
1509 /* does not stick
1510 TEST_PRINTERINFO_INT(2, cjobs, 2, cjobs, __LINE__);
1511 TEST_PRINTERINFO_INT(2, averageppm, 2, averageppm, __LINE__); */
1513 /* does not stick
1514 TEST_PRINTERINFO_INT(5, device_not_selected_timeout, 5, device_not_selected_timeout, __LINE__);
1515 TEST_PRINTERINFO_INT(5, transmission_retry_timeout, 5, transmission_retry_timeout, __LINE__); */
1517 /* FIXME: gd also test devmode and secdesc behavior */
1520 /* verify composition of level 1 description field */
1521 const char *description;
1522 const char *tmp;
1524 q0.in.level = 1;
1525 do { TESTGETCALL(GetPrinter, q0) } while (0);
1527 description = talloc_strdup(tctx, q0.out.info->info1.description);
1529 q0.in.level = 2;
1530 do { TESTGETCALL(GetPrinter, q0) } while (0);
1532 tmp = talloc_asprintf(tctx, "%s,%s,%s",
1533 q0.out.info->info2.printername,
1534 q0.out.info->info2.drivername,
1535 q0.out.info->info2.location);
1537 do { STRING_EQUAL(description, tmp, "description")} while (0);
1540 return ret;
1543 #define torture_assert_sid_equal(torture_ctx,got,expected,cmt)\
1544 do { struct dom_sid *__got = (got), *__expected = (expected); \
1545 if (!dom_sid_equal(__got, __expected)) { \
1546 torture_result(torture_ctx, TORTURE_FAIL, \
1547 __location__": "#got" was %s, expected %s: %s", \
1548 dom_sid_string(torture_ctx, __got), dom_sid_string(torture_ctx, __expected), cmt); \
1549 return false; \
1551 } while(0)
1553 static bool test_security_descriptor_equal(struct torture_context *tctx,
1554 const struct security_descriptor *sd1,
1555 const struct security_descriptor *sd2)
1557 if (sd1 == sd2) {
1558 return true;
1561 if (!sd1 || !sd2) {
1562 torture_comment(tctx, "%s\n", __location__);
1563 return false;
1566 torture_assert_int_equal(tctx, sd1->revision, sd2->revision, "revision mismatch");
1567 torture_assert_int_equal(tctx, sd1->type, sd2->type, "type mismatch");
1569 torture_assert_sid_equal(tctx, sd1->owner_sid, sd2->owner_sid, "owner mismatch");
1570 torture_assert_sid_equal(tctx, sd1->group_sid, sd2->group_sid, "group mismatch");
1572 if (!security_acl_equal(sd1->sacl, sd2->sacl)) {
1573 torture_comment(tctx, "%s: sacl mismatch\n", __location__);
1574 NDR_PRINT_DEBUG(security_acl, sd1->sacl);
1575 NDR_PRINT_DEBUG(security_acl, sd2->sacl);
1576 return false;
1578 if (!security_acl_equal(sd1->dacl, sd2->dacl)) {
1579 torture_comment(tctx, "%s: dacl mismatch\n", __location__);
1580 NDR_PRINT_DEBUG(security_acl, sd1->dacl);
1581 NDR_PRINT_DEBUG(security_acl, sd2->dacl);
1582 return false;
1585 return true;
1588 static bool test_sd_set_level(struct torture_context *tctx,
1589 struct dcerpc_pipe *p,
1590 struct policy_handle *handle,
1591 uint32_t level,
1592 struct security_descriptor *sd)
1594 struct spoolss_SetPrinterInfoCtr info_ctr;
1595 struct spoolss_DevmodeContainer devmode_ctr;
1596 struct sec_desc_buf secdesc_ctr;
1598 ZERO_STRUCT(devmode_ctr);
1599 ZERO_STRUCT(secdesc_ctr);
1601 switch (level) {
1602 case 2: {
1603 union spoolss_PrinterInfo info;
1604 struct spoolss_SetPrinterInfo2 info2;
1605 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 2, &info), "");
1607 info2.servername = info.info2.servername;
1608 info2.printername = info.info2.printername;
1609 info2.sharename = info.info2.sharename;
1610 info2.portname = info.info2.portname;
1611 info2.drivername = info.info2.drivername;
1612 info2.comment = info.info2.comment;
1613 info2.location = info.info2.location;
1614 info2.devmode_ptr = 0;
1615 info2.sepfile = info.info2.sepfile;
1616 info2.printprocessor = info.info2.printprocessor;
1617 info2.datatype = info.info2.datatype;
1618 info2.parameters = info.info2.parameters;
1619 info2.secdesc_ptr = 0;
1620 info2.attributes = info.info2.attributes;
1621 info2.priority = info.info2.priority;
1622 info2.defaultpriority = info.info2.defaultpriority;
1623 info2.starttime = info.info2.starttime;
1624 info2.untiltime = info.info2.untiltime;
1625 info2.status = info.info2.status;
1626 info2.cjobs = info.info2.cjobs;
1627 info2.averageppm = info.info2.averageppm;
1629 info_ctr.level = 2;
1630 info_ctr.info.info2 = &info2;
1632 break;
1634 case 3: {
1635 struct spoolss_SetPrinterInfo3 info3;
1637 info3.sec_desc_ptr = 0;
1639 info_ctr.level = 3;
1640 info_ctr.info.info3 = &info3;
1642 break;
1644 default:
1645 return false;
1648 secdesc_ctr.sd = sd;
1650 torture_assert(tctx,
1651 test_SetPrinter(tctx, p, handle, &info_ctr, &devmode_ctr, &secdesc_ctr, 0), "");
1653 return true;
1656 static bool test_PrinterInfo_SDs(struct torture_context *tctx,
1657 struct dcerpc_pipe *p,
1658 struct policy_handle *handle)
1660 union spoolss_PrinterInfo info;
1661 struct security_descriptor *sd1, *sd2;
1662 int i;
1664 /* just compare level 2 and level 3 */
1666 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 2, &info), "");
1668 sd1 = info.info2.secdesc;
1670 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 3, &info), "");
1672 sd2 = info.info3.secdesc;
1674 torture_assert(tctx, test_security_descriptor_equal(tctx, sd1, sd2),
1675 "SD level 2 != SD level 3");
1678 /* query level 2, set level 2, query level 2 */
1680 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 2, &info), "");
1682 sd1 = info.info2.secdesc;
1684 torture_assert(tctx, test_sd_set_level(tctx, p, handle, 2, sd1), "");
1686 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 2, &info), "");
1688 sd2 = info.info2.secdesc;
1689 if (sd1->type & SEC_DESC_DACL_DEFAULTED) {
1690 torture_comment(tctx, "removing SEC_DESC_DACL_DEFAULTED\n");
1691 sd1->type &= ~SEC_DESC_DACL_DEFAULTED;
1694 torture_assert(tctx, test_security_descriptor_equal(tctx, sd1, sd2),
1695 "SD level 2 != SD level 2 after SD has been set via level 2");
1698 /* query level 2, set level 3, query level 2 */
1700 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 2, &info), "");
1702 sd1 = info.info2.secdesc;
1704 torture_assert(tctx, test_sd_set_level(tctx, p, handle, 3, sd1), "");
1706 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 2, &info), "");
1708 sd2 = info.info2.secdesc;
1710 torture_assert(tctx, test_security_descriptor_equal(tctx, sd1, sd2),
1711 "SD level 2 != SD level 2 after SD has been set via level 3");
1713 /* set modified sd level 3, query level 2 */
1715 for (i=0; i < 93; i++) {
1716 struct security_ace a;
1717 const char *sid_string = talloc_asprintf(tctx, "S-1-5-32-9999%i", i);
1718 a.type = SEC_ACE_TYPE_ACCESS_ALLOWED;
1719 a.flags = 0;
1720 a.size = 0; /* autogenerated */
1721 a.access_mask = 0;
1722 a.trustee = *dom_sid_parse_talloc(tctx, sid_string);
1723 torture_assert_ntstatus_ok(tctx, security_descriptor_dacl_add(sd1, &a), "");
1726 torture_assert(tctx, test_sd_set_level(tctx, p, handle, 3, sd1), "");
1728 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 2, &info), "");
1729 sd2 = info.info2.secdesc;
1731 if (sd1->type & SEC_DESC_DACL_DEFAULTED) {
1732 torture_comment(tctx, "removing SEC_DESC_DACL_DEFAULTED\n");
1733 sd1->type &= ~SEC_DESC_DACL_DEFAULTED;
1736 torture_assert(tctx, test_security_descriptor_equal(tctx, sd1, sd2),
1737 "modified SD level 2 != SD level 2 after SD has been set via level 3");
1740 return true;
1744 * wrapper call that saves original sd, runs tests, and restores sd
1747 static bool test_PrinterInfo_SD(struct torture_context *tctx,
1748 struct dcerpc_pipe *p,
1749 struct policy_handle *handle)
1751 union spoolss_PrinterInfo info;
1752 struct security_descriptor *sd;
1753 bool ret = true;
1755 torture_comment(tctx, "\nTesting Printer Security Descriptors\n");
1757 /* save original sd */
1759 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 2, &info),
1760 "failed to get initial security descriptor");
1762 sd = security_descriptor_copy(tctx, info.info2.secdesc);
1764 /* run tests */
1766 ret = test_PrinterInfo_SDs(tctx, p, handle);
1768 /* restore original sd */
1770 torture_assert(tctx, test_sd_set_level(tctx, p, handle, 3, sd),
1771 "failed to restore initial security descriptor");
1773 torture_comment(tctx, "Printer Security Descriptors test %s\n",
1774 ret ? "succeeded" : "failed");
1777 return ret;
1780 static bool test_devmode_set_level(struct torture_context *tctx,
1781 struct dcerpc_pipe *p,
1782 struct policy_handle *handle,
1783 uint32_t level,
1784 struct spoolss_DeviceMode *devmode)
1786 struct spoolss_SetPrinterInfoCtr info_ctr;
1787 struct spoolss_DevmodeContainer devmode_ctr;
1788 struct sec_desc_buf secdesc_ctr;
1790 ZERO_STRUCT(devmode_ctr);
1791 ZERO_STRUCT(secdesc_ctr);
1793 switch (level) {
1794 case 2: {
1795 union spoolss_PrinterInfo info;
1796 struct spoolss_SetPrinterInfo2 info2;
1797 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 2, &info), "");
1799 info2.servername = info.info2.servername;
1800 info2.printername = info.info2.printername;
1801 info2.sharename = info.info2.sharename;
1802 info2.portname = info.info2.portname;
1803 info2.drivername = info.info2.drivername;
1804 info2.comment = info.info2.comment;
1805 info2.location = info.info2.location;
1806 info2.devmode_ptr = 0;
1807 info2.sepfile = info.info2.sepfile;
1808 info2.printprocessor = info.info2.printprocessor;
1809 info2.datatype = info.info2.datatype;
1810 info2.parameters = info.info2.parameters;
1811 info2.secdesc_ptr = 0;
1812 info2.attributes = info.info2.attributes;
1813 info2.priority = info.info2.priority;
1814 info2.defaultpriority = info.info2.defaultpriority;
1815 info2.starttime = info.info2.starttime;
1816 info2.untiltime = info.info2.untiltime;
1817 info2.status = info.info2.status;
1818 info2.cjobs = info.info2.cjobs;
1819 info2.averageppm = info.info2.averageppm;
1821 info_ctr.level = 2;
1822 info_ctr.info.info2 = &info2;
1824 break;
1826 case 8: {
1827 struct spoolss_SetPrinterInfo8 info8;
1829 info8.devmode_ptr = 0;
1831 info_ctr.level = 8;
1832 info_ctr.info.info8 = &info8;
1834 break;
1836 default:
1837 return false;
1840 devmode_ctr.devmode = devmode;
1842 torture_assert(tctx,
1843 test_SetPrinter(tctx, p, handle, &info_ctr, &devmode_ctr, &secdesc_ctr, 0), "");
1845 return true;
1849 static bool test_devicemode_equal(struct torture_context *tctx,
1850 const struct spoolss_DeviceMode *d1,
1851 const struct spoolss_DeviceMode *d2)
1853 if (d1 == d2) {
1854 return true;
1857 if (!d1 || !d2) {
1858 torture_comment(tctx, "%s\n", __location__);
1859 return false;
1861 torture_assert_str_equal(tctx, d1->devicename, d2->devicename, "devicename mismatch");
1862 torture_assert_int_equal(tctx, d1->specversion, d2->specversion, "specversion mismatch");
1863 torture_assert_int_equal(tctx, d1->driverversion, d2->driverversion, "driverversion mismatch");
1864 torture_assert_int_equal(tctx, d1->size, d2->size, "size mismatch");
1865 torture_assert_int_equal(tctx, d1->__driverextra_length, d2->__driverextra_length, "__driverextra_length mismatch");
1866 torture_assert_int_equal(tctx, d1->fields, d2->fields, "fields mismatch");
1867 torture_assert_int_equal(tctx, d1->orientation, d2->orientation, "orientation mismatch");
1868 torture_assert_int_equal(tctx, d1->papersize, d2->papersize, "papersize mismatch");
1869 torture_assert_int_equal(tctx, d1->paperlength, d2->paperlength, "paperlength mismatch");
1870 torture_assert_int_equal(tctx, d1->paperwidth, d2->paperwidth, "paperwidth mismatch");
1871 torture_assert_int_equal(tctx, d1->scale, d2->scale, "scale mismatch");
1872 torture_assert_int_equal(tctx, d1->copies, d2->copies, "copies mismatch");
1873 torture_assert_int_equal(tctx, d1->defaultsource, d2->defaultsource, "defaultsource mismatch");
1874 torture_assert_int_equal(tctx, d1->printquality, d2->printquality, "printquality mismatch");
1875 torture_assert_int_equal(tctx, d1->color, d2->color, "color mismatch");
1876 torture_assert_int_equal(tctx, d1->duplex, d2->duplex, "duplex mismatch");
1877 torture_assert_int_equal(tctx, d1->yresolution, d2->yresolution, "yresolution mismatch");
1878 torture_assert_int_equal(tctx, d1->ttoption, d2->ttoption, "ttoption mismatch");
1879 torture_assert_int_equal(tctx, d1->collate, d2->collate, "collate mismatch");
1880 torture_assert_str_equal(tctx, d1->formname, d2->formname, "formname mismatch");
1881 torture_assert_int_equal(tctx, d1->logpixels, d2->logpixels, "logpixels mismatch");
1882 torture_assert_int_equal(tctx, d1->bitsperpel, d2->bitsperpel, "bitsperpel mismatch");
1883 torture_assert_int_equal(tctx, d1->pelswidth, d2->pelswidth, "pelswidth mismatch");
1884 torture_assert_int_equal(tctx, d1->pelsheight, d2->pelsheight, "pelsheight mismatch");
1885 torture_assert_int_equal(tctx, d1->displayflags, d2->displayflags, "displayflags mismatch");
1886 torture_assert_int_equal(tctx, d1->displayfrequency, d2->displayfrequency, "displayfrequency mismatch");
1887 torture_assert_int_equal(tctx, d1->icmmethod, d2->icmmethod, "icmmethod mismatch");
1888 torture_assert_int_equal(tctx, d1->icmintent, d2->icmintent, "icmintent mismatch");
1889 torture_assert_int_equal(tctx, d1->mediatype, d2->mediatype, "mediatype mismatch");
1890 torture_assert_int_equal(tctx, d1->dithertype, d2->dithertype, "dithertype mismatch");
1891 torture_assert_int_equal(tctx, d1->reserved1, d2->reserved1, "reserved1 mismatch");
1892 torture_assert_int_equal(tctx, d1->reserved2, d2->reserved2, "reserved2 mismatch");
1893 torture_assert_int_equal(tctx, d1->panningwidth, d2->panningwidth, "panningwidth mismatch");
1894 torture_assert_int_equal(tctx, d1->panningheight, d2->panningheight, "panningheight mismatch");
1895 torture_assert_data_blob_equal(tctx, d1->driverextra_data, d2->driverextra_data, "driverextra_data mismatch");
1897 return true;
1900 static bool test_devicemode_full(struct torture_context *tctx,
1901 struct dcerpc_pipe *p,
1902 struct policy_handle *handle)
1904 struct spoolss_SetPrinter s;
1905 struct spoolss_GetPrinter q;
1906 struct spoolss_GetPrinter q0;
1907 struct spoolss_SetPrinterInfoCtr info_ctr;
1908 struct spoolss_SetPrinterInfo8 info8;
1909 union spoolss_PrinterInfo info;
1910 struct spoolss_DevmodeContainer devmode_ctr;
1911 struct sec_desc_buf secdesc_ctr;
1912 uint32_t needed;
1913 bool ret = true;
1914 NTSTATUS status;
1916 #define TEST_DEVMODE_INT_EXP(lvl1, field1, lvl2, field2, value, exp_value) do { \
1917 torture_comment(tctx, "field test %d/%s vs %d/%s\n", lvl1, #field1, lvl2, #field2); \
1918 q.in.level = lvl1; \
1919 TESTGETCALL(GetPrinter, q) \
1920 info_ctr.level = lvl1; \
1921 if (lvl1 == 2) {\
1922 info_ctr.info.info ## lvl1 = (struct spoolss_SetPrinterInfo ## lvl1 *)&q.out.info->info ## lvl1; \
1923 } else if (lvl1 == 8) {\
1924 info_ctr.info.info ## lvl1 = &info8; \
1926 devmode_ctr.devmode = q.out.info->info ## lvl1.devmode; \
1927 devmode_ctr.devmode->field1 = value; \
1928 TESTSETCALL(SetPrinter, s) \
1929 TESTGETCALL(GetPrinter, q) \
1930 INT_EQUAL(q.out.info->info ## lvl1.devmode->field1, exp_value, field1); \
1931 q.in.level = lvl2; \
1932 TESTGETCALL(GetPrinter, q) \
1933 INT_EQUAL(q.out.info->info ## lvl2.devmode->field2, exp_value, field1); \
1934 } while (0)
1936 #define TEST_DEVMODE_INT(lvl1, field1, lvl2, field2, value) do { \
1937 TEST_DEVMODE_INT_EXP(lvl1, field1, lvl2, field2, value, value); \
1938 } while (0)
1940 ZERO_STRUCT(devmode_ctr);
1941 ZERO_STRUCT(secdesc_ctr);
1942 ZERO_STRUCT(info8);
1944 s.in.handle = handle;
1945 s.in.command = 0;
1946 s.in.info_ctr = &info_ctr;
1947 s.in.devmode_ctr = &devmode_ctr;
1948 s.in.secdesc_ctr = &secdesc_ctr;
1950 q.in.handle = handle;
1951 q.out.info = &info;
1952 q0 = q;
1954 #if 0
1955 const char *devicename;/* [charset(UTF16)] */
1956 enum spoolss_DeviceModeSpecVersion specversion;
1957 uint16_t driverversion;
1958 uint16_t size;
1959 uint16_t __driverextra_length;/* [value(r->driverextra_data.length)] */
1960 uint32_t fields;
1961 #endif
1963 TEST_DEVMODE_INT(8, orientation, 8, orientation, __LINE__);
1964 TEST_DEVMODE_INT(8, papersize, 8, papersize, __LINE__);
1965 TEST_DEVMODE_INT(8, paperlength, 8, paperlength, __LINE__);
1966 TEST_DEVMODE_INT(8, paperwidth, 8, paperwidth, __LINE__);
1967 TEST_DEVMODE_INT(8, scale, 8, scale, __LINE__);
1968 TEST_DEVMODE_INT(8, copies, 8, copies, __LINE__);
1969 TEST_DEVMODE_INT(8, defaultsource, 8, defaultsource, __LINE__);
1970 TEST_DEVMODE_INT(8, printquality, 8, printquality, __LINE__);
1971 TEST_DEVMODE_INT(8, color, 8, color, __LINE__);
1972 TEST_DEVMODE_INT(8, duplex, 8, duplex, __LINE__);
1973 TEST_DEVMODE_INT(8, yresolution, 8, yresolution, __LINE__);
1974 TEST_DEVMODE_INT(8, ttoption, 8, ttoption, __LINE__);
1975 TEST_DEVMODE_INT(8, collate, 8, collate, __LINE__);
1976 #if 0
1977 const char *formname;/* [charset(UTF16)] */
1978 #endif
1979 TEST_DEVMODE_INT(8, logpixels, 8, logpixels, __LINE__);
1980 TEST_DEVMODE_INT(8, bitsperpel, 8, bitsperpel, __LINE__);
1981 TEST_DEVMODE_INT(8, pelswidth, 8, pelswidth, __LINE__);
1982 TEST_DEVMODE_INT(8, pelsheight, 8, pelsheight, __LINE__);
1983 TEST_DEVMODE_INT(8, displayflags, 8, displayflags, __LINE__);
1984 TEST_DEVMODE_INT(8, displayfrequency, 8, displayfrequency, __LINE__);
1985 TEST_DEVMODE_INT(8, icmmethod, 8, icmmethod, __LINE__);
1986 TEST_DEVMODE_INT(8, icmintent, 8, icmintent, __LINE__);
1987 TEST_DEVMODE_INT(8, mediatype, 8, mediatype, __LINE__);
1988 TEST_DEVMODE_INT(8, dithertype, 8, dithertype, __LINE__);
1989 TEST_DEVMODE_INT(8, reserved1, 8, reserved1, __LINE__);
1990 TEST_DEVMODE_INT(8, reserved2, 8, reserved2, __LINE__);
1991 TEST_DEVMODE_INT(8, panningwidth, 8, panningwidth, __LINE__);
1992 TEST_DEVMODE_INT(8, panningheight, 8, panningheight, __LINE__);
1994 return ret;
1997 static bool call_OpenPrinterEx(struct torture_context *tctx,
1998 struct dcerpc_pipe *p,
1999 const char *name,
2000 struct spoolss_DeviceMode *devmode,
2001 struct policy_handle *handle);
2003 static bool test_ClosePrinter(struct torture_context *tctx,
2004 struct dcerpc_pipe *p,
2005 struct policy_handle *handle);
2007 static bool test_PrinterInfo_DevModes(struct torture_context *tctx,
2008 struct dcerpc_pipe *p,
2009 struct policy_handle *handle,
2010 const char *name)
2012 union spoolss_PrinterInfo info;
2013 struct spoolss_DeviceMode *devmode;
2014 struct spoolss_DeviceMode *devmode2;
2015 struct policy_handle handle_devmode;
2017 /* simply compare level8 and level2 devmode */
2019 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 8, &info), "");
2021 devmode = info.info8.devmode;
2023 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 2, &info), "");
2025 devmode2 = info.info2.devmode;
2027 torture_assert(tctx, test_devicemode_equal(tctx, devmode, devmode2),
2028 "DM level 8 != DM level 2");
2031 /* set devicemode level 8 and see if it persists */
2033 devmode->copies = 93;
2034 devmode->formname = talloc_strdup(tctx, "Legal");
2036 torture_assert(tctx, test_devmode_set_level(tctx, p, handle, 8, devmode), "");
2038 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 8, &info), "");
2040 devmode2 = info.info8.devmode;
2042 torture_assert(tctx, test_devicemode_equal(tctx, devmode, devmode2),
2043 "modified DM level 8 != DM level 8 after DM has been set via level 8");
2045 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 2, &info), "");
2047 devmode2 = info.info2.devmode;
2049 torture_assert(tctx, test_devicemode_equal(tctx, devmode, devmode2),
2050 "modified DM level 8 != DM level 2");
2053 /* set devicemode level 2 and see if it persists */
2055 devmode->copies = 39;
2056 devmode->formname = talloc_strdup(tctx, "Executive");
2058 torture_assert(tctx, test_devmode_set_level(tctx, p, handle, 2, devmode), "");
2060 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 8, &info), "");
2062 devmode2 = info.info8.devmode;
2064 torture_assert(tctx, test_devicemode_equal(tctx, devmode, devmode2),
2065 "modified DM level 8 != DM level 8 after DM has been set via level 2");
2067 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 2, &info), "");
2069 devmode2 = info.info2.devmode;
2071 torture_assert(tctx, test_devicemode_equal(tctx, devmode, devmode2),
2072 "modified DM level 8 != DM level 2");
2075 /* check every single bit in public part of devicemode */
2077 torture_assert(tctx, test_devicemode_full(tctx, p, handle),
2078 "failed to set every single devicemode component");
2081 /* change formname upon open and see if it persists in getprinter calls */
2083 devmode->formname = talloc_strdup(tctx, "A4");
2084 devmode->copies = 42;
2086 torture_assert(tctx, call_OpenPrinterEx(tctx, p, name, devmode, &handle_devmode),
2087 "failed to open printer handle");
2089 torture_assert(tctx, test_GetPrinter_level(tctx, p, &handle_devmode, 8, &info), "");
2091 devmode2 = info.info8.devmode;
2093 if (strequal(devmode->devicename, devmode2->devicename)) {
2094 torture_comment(tctx, "devicenames are the same\n");
2095 } else {
2096 torture_comment(tctx, "devicename passed in for open: %s\n", devmode->devicename);
2097 torture_comment(tctx, "devicename after level 8 get: %s\n", devmode2->devicename);
2100 if (strequal(devmode->formname, devmode2->formname)) {
2101 torture_warning(tctx, "formname are the same\n");
2102 } else {
2103 torture_comment(tctx, "formname passed in for open: %s\n", devmode->formname);
2104 torture_comment(tctx, "formname after level 8 get: %s\n", devmode2->formname);
2107 if (devmode->copies == devmode2->copies) {
2108 torture_warning(tctx, "copies are the same\n");
2109 } else {
2110 torture_comment(tctx, "copies passed in for open: %d\n", devmode->copies);
2111 torture_comment(tctx, "copies after level 8 get: %d\n", devmode2->copies);
2114 torture_assert(tctx, test_GetPrinter_level(tctx, p, &handle_devmode, 2, &info), "");
2116 devmode2 = info.info2.devmode;
2118 if (strequal(devmode->devicename, devmode2->devicename)) {
2119 torture_comment(tctx, "devicenames are the same\n");
2120 } else {
2121 torture_comment(tctx, "devicename passed in for open: %s\n", devmode->devicename);
2122 torture_comment(tctx, "devicename after level 2 get: %s\n", devmode2->devicename);
2125 if (strequal(devmode->formname, devmode2->formname)) {
2126 torture_warning(tctx, "formname is the same\n");
2127 } else {
2128 torture_comment(tctx, "formname passed in for open: %s\n", devmode->formname);
2129 torture_comment(tctx, "formname after level 2 get: %s\n", devmode2->formname);
2132 if (devmode->copies == devmode2->copies) {
2133 torture_warning(tctx, "copies are the same\n");
2134 } else {
2135 torture_comment(tctx, "copies passed in for open: %d\n", devmode->copies);
2136 torture_comment(tctx, "copies after level 2 get: %d\n", devmode2->copies);
2139 test_ClosePrinter(tctx, p, &handle_devmode);
2141 return true;
2145 * wrapper call that saves original devmode, runs tests, and restores devmode
2148 static bool test_PrinterInfo_DevMode(struct torture_context *tctx,
2149 struct dcerpc_pipe *p,
2150 struct policy_handle *handle,
2151 const char *name)
2153 union spoolss_PrinterInfo info;
2154 struct spoolss_DeviceMode *devmode;
2155 bool ret = true;
2157 torture_comment(tctx, "\nTesting Printer Devicemodes\n");
2159 /* save original devmode */
2161 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 8, &info),
2162 "failed to get initial global devicemode");
2164 devmode = info.info8.devmode;
2166 /* run tests */
2168 ret = test_PrinterInfo_DevModes(tctx, p, handle, name);
2170 /* restore original devmode */
2172 torture_assert(tctx, test_devmode_set_level(tctx, p, handle, 8, devmode),
2173 "failed to restore initial global device mode");
2175 torture_comment(tctx, "Printer Devicemodes test %s\n",
2176 ret ? "succeeded" : "failed");
2179 return ret;
2182 static bool test_ClosePrinter(struct torture_context *tctx,
2183 struct dcerpc_pipe *p,
2184 struct policy_handle *handle)
2186 NTSTATUS status;
2187 struct spoolss_ClosePrinter r;
2189 r.in.handle = handle;
2190 r.out.handle = handle;
2192 torture_comment(tctx, "Testing ClosePrinter\n");
2194 status = dcerpc_spoolss_ClosePrinter(p, tctx, &r);
2195 torture_assert_ntstatus_ok(tctx, status, "ClosePrinter failed");
2196 torture_assert_werr_ok(tctx, r.out.result, "ClosePrinter failed");
2198 return true;
2201 static bool test_GetForm(struct torture_context *tctx,
2202 struct dcerpc_pipe *p,
2203 struct policy_handle *handle,
2204 const char *form_name,
2205 uint32_t level)
2207 NTSTATUS status;
2208 struct spoolss_GetForm r;
2209 uint32_t needed;
2211 r.in.handle = handle;
2212 r.in.form_name = form_name;
2213 r.in.level = level;
2214 r.in.buffer = NULL;
2215 r.in.offered = 0;
2216 r.out.needed = &needed;
2218 torture_comment(tctx, "Testing GetForm level %d\n", r.in.level);
2220 status = dcerpc_spoolss_GetForm(p, tctx, &r);
2221 torture_assert_ntstatus_ok(tctx, status, "GetForm failed");
2223 if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
2224 DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed);
2225 data_blob_clear(&blob);
2226 r.in.buffer = &blob;
2227 r.in.offered = needed;
2228 status = dcerpc_spoolss_GetForm(p, tctx, &r);
2229 torture_assert_ntstatus_ok(tctx, status, "GetForm failed");
2231 torture_assert_werr_ok(tctx, r.out.result, "GetForm failed");
2233 torture_assert(tctx, r.out.info, "No form info returned");
2236 torture_assert_werr_ok(tctx, r.out.result, "GetForm failed");
2238 CHECK_NEEDED_SIZE_LEVEL(spoolss_FormInfo, r.out.info, r.in.level, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
2240 return true;
2243 static bool test_EnumForms(struct torture_context *tctx,
2244 struct dcerpc_pipe *p,
2245 struct policy_handle *handle, bool print_server)
2247 NTSTATUS status;
2248 struct spoolss_EnumForms r;
2249 bool ret = true;
2250 uint32_t needed;
2251 uint32_t count;
2252 uint32_t levels[] = { 1, 2 };
2253 int i;
2255 for (i=0; i<ARRAY_SIZE(levels); i++) {
2257 union spoolss_FormInfo *info;
2259 r.in.handle = handle;
2260 r.in.level = levels[i];
2261 r.in.buffer = NULL;
2262 r.in.offered = 0;
2263 r.out.needed = &needed;
2264 r.out.count = &count;
2265 r.out.info = &info;
2267 torture_comment(tctx, "Testing EnumForms level %d\n", levels[i]);
2269 status = dcerpc_spoolss_EnumForms(p, tctx, &r);
2270 torture_assert_ntstatus_ok(tctx, status, "EnumForms failed");
2272 if ((r.in.level == 2) && (W_ERROR_EQUAL(r.out.result, WERR_UNKNOWN_LEVEL))) {
2273 break;
2276 if (print_server && W_ERROR_EQUAL(r.out.result, WERR_BADFID))
2277 torture_fail(tctx, "EnumForms on the PrintServer isn't supported by test server (NT4)");
2279 if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
2280 int j;
2281 DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed);
2282 data_blob_clear(&blob);
2283 r.in.buffer = &blob;
2284 r.in.offered = needed;
2286 status = dcerpc_spoolss_EnumForms(p, tctx, &r);
2288 torture_assert(tctx, info, "No forms returned");
2290 for (j = 0; j < count; j++) {
2291 if (!print_server)
2292 ret &= test_GetForm(tctx, p, handle, info[j].info1.form_name, levels[i]);
2296 torture_assert_ntstatus_ok(tctx, status, "EnumForms failed");
2298 torture_assert_werr_ok(tctx, r.out.result, "EnumForms failed");
2300 CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumForms, info, r.in.level, count, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
2303 return true;
2306 static bool test_DeleteForm(struct torture_context *tctx,
2307 struct dcerpc_pipe *p,
2308 struct policy_handle *handle,
2309 const char *form_name)
2311 NTSTATUS status;
2312 struct spoolss_DeleteForm r;
2314 r.in.handle = handle;
2315 r.in.form_name = form_name;
2317 status = dcerpc_spoolss_DeleteForm(p, tctx, &r);
2319 torture_assert_ntstatus_ok(tctx, status, "DeleteForm failed");
2321 torture_assert_werr_ok(tctx, r.out.result, "DeleteForm failed");
2323 return true;
2326 static bool test_AddForm(struct torture_context *tctx,
2327 struct dcerpc_pipe *p,
2328 struct policy_handle *handle, bool print_server)
2330 struct spoolss_AddForm r;
2331 struct spoolss_AddFormInfo1 addform;
2332 const char *form_name = "testform3";
2333 NTSTATUS status;
2334 bool ret = true;
2336 r.in.handle = handle;
2337 r.in.level = 1;
2338 r.in.info.info1 = &addform;
2339 addform.flags = SPOOLSS_FORM_USER;
2340 addform.form_name = form_name;
2341 addform.size.width = 50;
2342 addform.size.height = 25;
2343 addform.area.left = 5;
2344 addform.area.top = 10;
2345 addform.area.right = 45;
2346 addform.area.bottom = 15;
2348 status = dcerpc_spoolss_AddForm(p, tctx, &r);
2350 torture_assert_ntstatus_ok(tctx, status, "AddForm failed");
2352 torture_assert_werr_ok(tctx, r.out.result, "AddForm failed");
2354 if (!print_server) ret &= test_GetForm(tctx, p, handle, form_name, 1);
2357 struct spoolss_SetForm sf;
2358 struct spoolss_AddFormInfo1 setform;
2360 sf.in.handle = handle;
2361 sf.in.form_name = form_name;
2362 sf.in.level = 1;
2363 sf.in.info.info1= &setform;
2364 setform.flags = addform.flags;
2365 setform.form_name = addform.form_name;
2366 setform.size = addform.size;
2367 setform.area = addform.area;
2369 setform.size.width = 1234;
2371 status = dcerpc_spoolss_SetForm(p, tctx, &sf);
2373 torture_assert_ntstatus_ok(tctx, status, "SetForm failed");
2375 torture_assert_werr_ok(tctx, r.out.result, "SetForm failed");
2378 if (!print_server) ret &= test_GetForm(tctx, p, handle, form_name, 1);
2381 struct spoolss_EnumForms e;
2382 union spoolss_FormInfo *info;
2383 uint32_t needed;
2384 uint32_t count;
2385 bool found = false;
2387 e.in.handle = handle;
2388 e.in.level = 1;
2389 e.in.buffer = NULL;
2390 e.in.offered = 0;
2391 e.out.needed = &needed;
2392 e.out.count = &count;
2393 e.out.info = &info;
2395 torture_comment(tctx, "Testing EnumForms level 1\n");
2397 status = dcerpc_spoolss_EnumForms(p, tctx, &e);
2398 torture_assert_ntstatus_ok(tctx, status, "EnumForms failed");
2400 if (print_server && W_ERROR_EQUAL(e.out.result, WERR_BADFID))
2401 torture_fail(tctx, "EnumForms on the PrintServer isn't supported by test server (NT4)");
2403 if (W_ERROR_EQUAL(e.out.result, WERR_INSUFFICIENT_BUFFER)) {
2404 int j;
2405 DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed);
2406 data_blob_clear(&blob);
2407 e.in.buffer = &blob;
2408 e.in.offered = needed;
2410 status = dcerpc_spoolss_EnumForms(p, tctx, &e);
2412 torture_assert(tctx, info, "No forms returned");
2414 for (j = 0; j < count; j++) {
2415 if (strequal(form_name, info[j].info1.form_name)) {
2416 found = true;
2417 break;
2421 torture_assert(tctx, found, "Newly added form not found in enum call");
2424 if (!test_DeleteForm(tctx, p, handle, form_name)) {
2425 ret = false;
2428 return ret;
2431 static bool test_EnumPorts_old(struct torture_context *tctx,
2432 struct dcerpc_pipe *p)
2434 NTSTATUS status;
2435 struct spoolss_EnumPorts r;
2436 uint32_t needed;
2437 uint32_t count;
2438 union spoolss_PortInfo *info;
2440 r.in.servername = talloc_asprintf(tctx, "\\\\%s",
2441 dcerpc_server_name(p));
2442 r.in.level = 2;
2443 r.in.buffer = NULL;
2444 r.in.offered = 0;
2445 r.out.needed = &needed;
2446 r.out.count = &count;
2447 r.out.info = &info;
2449 torture_comment(tctx, "Testing EnumPorts\n");
2451 status = dcerpc_spoolss_EnumPorts(p, tctx, &r);
2453 torture_assert_ntstatus_ok(tctx, status, "EnumPorts failed");
2455 if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
2456 DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed);
2457 data_blob_clear(&blob);
2458 r.in.buffer = &blob;
2459 r.in.offered = needed;
2461 status = dcerpc_spoolss_EnumPorts(p, tctx, &r);
2462 torture_assert_ntstatus_ok(tctx, status, "EnumPorts failed");
2463 torture_assert_werr_ok(tctx, r.out.result, "EnumPorts failed");
2465 torture_assert(tctx, info, "No ports returned");
2468 torture_assert_werr_ok(tctx, r.out.result, "EnumPorts failed");
2470 CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumPorts, info, 2, count, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
2472 return true;
2475 static bool test_AddPort(struct torture_context *tctx,
2476 struct dcerpc_pipe *p)
2478 NTSTATUS status;
2479 struct spoolss_AddPort r;
2481 r.in.server_name = talloc_asprintf(tctx, "\\\\%s",
2482 dcerpc_server_name(p));
2483 r.in.unknown = 0;
2484 r.in.monitor_name = "foo";
2486 torture_comment(tctx, "Testing AddPort\n");
2488 status = dcerpc_spoolss_AddPort(p, tctx, &r);
2490 torture_assert_ntstatus_ok(tctx, status, "AddPort failed");
2492 /* win2k3 returns WERR_NOT_SUPPORTED */
2494 #if 0
2496 if (!W_ERROR_IS_OK(r.out.result)) {
2497 printf("AddPort failed - %s\n", win_errstr(r.out.result));
2498 return false;
2501 #endif
2503 return true;
2506 static bool test_GetJob(struct torture_context *tctx,
2507 struct dcerpc_pipe *p,
2508 struct policy_handle *handle, uint32_t job_id)
2510 NTSTATUS status;
2511 struct spoolss_GetJob r;
2512 union spoolss_JobInfo info;
2513 uint32_t needed;
2514 uint32_t levels[] = {1, 2 /* 3, 4 */};
2515 uint32_t i;
2517 r.in.handle = handle;
2518 r.in.job_id = job_id;
2519 r.in.level = 0;
2520 r.in.buffer = NULL;
2521 r.in.offered = 0;
2522 r.out.needed = &needed;
2523 r.out.info = &info;
2525 torture_comment(tctx, "Testing GetJob level %d\n", r.in.level);
2527 status = dcerpc_spoolss_GetJob(p, tctx, &r);
2528 torture_assert_werr_equal(tctx, r.out.result, WERR_UNKNOWN_LEVEL, "Unexpected return code");
2530 for (i = 0; i < ARRAY_SIZE(levels); i++) {
2532 torture_comment(tctx, "Testing GetJob level %d\n", r.in.level);
2534 needed = 0;
2536 r.in.level = levels[i];
2537 r.in.offered = 0;
2538 r.in.buffer = NULL;
2540 status = dcerpc_spoolss_GetJob(p, tctx, &r);
2541 torture_assert_ntstatus_ok(tctx, status, "GetJob failed");
2543 if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
2544 DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed);
2545 data_blob_clear(&blob);
2546 r.in.buffer = &blob;
2547 r.in.offered = needed;
2549 status = dcerpc_spoolss_GetJob(p, tctx, &r);
2550 torture_assert_ntstatus_ok(tctx, status, "GetJob failed");
2553 torture_assert(tctx, r.out.info, "No job info returned");
2554 torture_assert_werr_ok(tctx, r.out.result, "GetJob failed");
2556 CHECK_NEEDED_SIZE_LEVEL(spoolss_JobInfo, r.out.info, r.in.level, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
2559 return true;
2562 static bool test_SetJob(struct torture_context *tctx,
2563 struct dcerpc_pipe *p,
2564 struct policy_handle *handle, uint32_t job_id,
2565 enum spoolss_JobControl command)
2567 NTSTATUS status;
2568 struct spoolss_SetJob r;
2570 r.in.handle = handle;
2571 r.in.job_id = job_id;
2572 r.in.ctr = NULL;
2573 r.in.command = command;
2575 switch (command) {
2576 case SPOOLSS_JOB_CONTROL_PAUSE:
2577 torture_comment(tctx, "Testing SetJob: SPOOLSS_JOB_CONTROL_PAUSE\n");
2578 break;
2579 case SPOOLSS_JOB_CONTROL_RESUME:
2580 torture_comment(tctx, "Testing SetJob: SPOOLSS_JOB_CONTROL_RESUME\n");
2581 break;
2582 case SPOOLSS_JOB_CONTROL_CANCEL:
2583 torture_comment(tctx, "Testing SetJob: SPOOLSS_JOB_CONTROL_CANCEL\n");
2584 break;
2585 case SPOOLSS_JOB_CONTROL_RESTART:
2586 torture_comment(tctx, "Testing SetJob: SPOOLSS_JOB_CONTROL_RESTART\n");
2587 break;
2588 case SPOOLSS_JOB_CONTROL_DELETE:
2589 torture_comment(tctx, "Testing SetJob: SPOOLSS_JOB_CONTROL_DELETE\n");
2590 break;
2591 case SPOOLSS_JOB_CONTROL_SEND_TO_PRINTER:
2592 torture_comment(tctx, "Testing SetJob: SPOOLSS_JOB_CONTROL_SEND_TO_PRINTER\n");
2593 break;
2594 case SPOOLSS_JOB_CONTROL_LAST_PAGE_EJECTED:
2595 torture_comment(tctx, "Testing SetJob: SPOOLSS_JOB_CONTROL_LAST_PAGE_EJECTED\n");
2596 break;
2597 case SPOOLSS_JOB_CONTROL_RETAIN:
2598 torture_comment(tctx, "Testing SetJob: SPOOLSS_JOB_CONTROL_RETAIN\n");
2599 break;
2600 case SPOOLSS_JOB_CONTROL_RELEASE:
2601 torture_comment(tctx, "Testing SetJob: SPOOLSS_JOB_CONTROL_RELEASE\n");
2602 break;
2603 default:
2604 torture_comment(tctx, "Testing SetJob\n");
2605 break;
2608 status = dcerpc_spoolss_SetJob(p, tctx, &r);
2609 torture_assert_ntstatus_ok(tctx, status, "SetJob failed");
2610 torture_assert_werr_ok(tctx, r.out.result, "SetJob failed");
2612 return true;
2615 static bool test_AddJob(struct torture_context *tctx,
2616 struct dcerpc_pipe *p,
2617 struct policy_handle *handle)
2619 NTSTATUS status;
2620 struct spoolss_AddJob r;
2621 uint32_t needed;
2623 r.in.level = 0;
2624 r.in.handle = handle;
2625 r.in.offered = 0;
2626 r.out.needed = &needed;
2627 r.in.buffer = r.out.buffer = NULL;
2629 torture_comment(tctx, "Testing AddJob\n");
2631 status = dcerpc_spoolss_AddJob(p, tctx, &r);
2632 torture_assert_werr_equal(tctx, r.out.result, WERR_UNKNOWN_LEVEL, "AddJob failed");
2634 r.in.level = 1;
2636 status = dcerpc_spoolss_AddJob(p, tctx, &r);
2637 torture_assert_werr_equal(tctx, r.out.result, WERR_INVALID_PARAM, "AddJob failed");
2639 return true;
2643 static bool test_EnumJobs(struct torture_context *tctx,
2644 struct dcerpc_pipe *p,
2645 struct policy_handle *handle)
2647 NTSTATUS status;
2648 struct spoolss_EnumJobs r;
2649 uint32_t needed;
2650 uint32_t count;
2651 union spoolss_JobInfo *info;
2653 r.in.handle = handle;
2654 r.in.firstjob = 0;
2655 r.in.numjobs = 0xffffffff;
2656 r.in.level = 1;
2657 r.in.buffer = NULL;
2658 r.in.offered = 0;
2659 r.out.needed = &needed;
2660 r.out.count = &count;
2661 r.out.info = &info;
2663 torture_comment(tctx, "Testing EnumJobs\n");
2665 status = dcerpc_spoolss_EnumJobs(p, tctx, &r);
2667 torture_assert_ntstatus_ok(tctx, status, "EnumJobs failed");
2669 if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
2670 int j;
2671 DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed);
2672 data_blob_clear(&blob);
2673 r.in.buffer = &blob;
2674 r.in.offered = needed;
2676 status = dcerpc_spoolss_EnumJobs(p, tctx, &r);
2678 torture_assert_ntstatus_ok(tctx, status, "EnumJobs failed");
2679 torture_assert_werr_ok(tctx, r.out.result, "EnumJobs failed");
2680 torture_assert(tctx, info, "No jobs returned");
2682 CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumJobs, *r.out.info, r.in.level, count, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
2684 for (j = 0; j < count; j++) {
2686 torture_assert(tctx, test_GetJob(tctx, p, handle, info[j].info1.job_id),
2687 "failed to call test_GetJob");
2689 /* FIXME - gd */
2690 if (!torture_setting_bool(tctx, "samba3", false)) {
2691 test_SetJob(tctx, p, handle, info[j].info1.job_id, SPOOLSS_JOB_CONTROL_PAUSE);
2692 test_SetJob(tctx, p, handle, info[j].info1.job_id, SPOOLSS_JOB_CONTROL_RESUME);
2696 } else {
2697 torture_assert_werr_ok(tctx, r.out.result, "EnumJobs failed");
2700 return true;
2703 static bool test_DoPrintTest(struct torture_context *tctx,
2704 struct dcerpc_pipe *p,
2705 struct policy_handle *handle)
2707 bool ret = true;
2708 NTSTATUS status;
2709 struct spoolss_StartDocPrinter s;
2710 struct spoolss_DocumentInfo1 info1;
2711 struct spoolss_StartPagePrinter sp;
2712 struct spoolss_WritePrinter w;
2713 struct spoolss_EndPagePrinter ep;
2714 struct spoolss_EndDocPrinter e;
2715 int i;
2716 uint32_t job_id;
2717 uint32_t num_written;
2719 torture_comment(tctx, "Testing StartDocPrinter\n");
2721 s.in.handle = handle;
2722 s.in.level = 1;
2723 s.in.info.info1 = &info1;
2724 s.out.job_id = &job_id;
2725 info1.document_name = "TorturePrintJob";
2726 info1.output_file = NULL;
2727 info1.datatype = "RAW";
2729 status = dcerpc_spoolss_StartDocPrinter(p, tctx, &s);
2730 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_StartDocPrinter failed");
2731 torture_assert_werr_ok(tctx, s.out.result, "StartDocPrinter failed");
2733 for (i=1; i < 4; i++) {
2734 torture_comment(tctx, "Testing StartPagePrinter: Page[%d]\n", i);
2736 sp.in.handle = handle;
2738 status = dcerpc_spoolss_StartPagePrinter(p, tctx, &sp);
2739 torture_assert_ntstatus_ok(tctx, status,
2740 "dcerpc_spoolss_StartPagePrinter failed");
2741 torture_assert_werr_ok(tctx, sp.out.result, "StartPagePrinter failed");
2743 torture_comment(tctx, "Testing WritePrinter: Page[%d]\n", i);
2745 w.in.handle = handle;
2746 w.in.data = data_blob_string_const(talloc_asprintf(tctx,"TortureTestPage: %d\nData\n",i));
2747 w.out.num_written = &num_written;
2749 status = dcerpc_spoolss_WritePrinter(p, tctx, &w);
2750 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_WritePrinter failed");
2751 torture_assert_werr_ok(tctx, w.out.result, "WritePrinter failed");
2753 torture_comment(tctx, "Testing EndPagePrinter: Page[%d]\n", i);
2755 ep.in.handle = handle;
2757 status = dcerpc_spoolss_EndPagePrinter(p, tctx, &ep);
2758 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EndPagePrinter failed");
2759 torture_assert_werr_ok(tctx, ep.out.result, "EndPagePrinter failed");
2762 torture_comment(tctx, "Testing EndDocPrinter\n");
2764 e.in.handle = handle;
2766 status = dcerpc_spoolss_EndDocPrinter(p, tctx, &e);
2767 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EndDocPrinter failed");
2768 torture_assert_werr_ok(tctx, e.out.result, "EndDocPrinter failed");
2770 ret &= test_AddJob(tctx, p, handle);
2771 ret &= test_EnumJobs(tctx, p, handle);
2773 ret &= test_SetJob(tctx, p, handle, job_id, SPOOLSS_JOB_CONTROL_DELETE);
2775 return ret;
2778 static bool test_PausePrinter(struct torture_context *tctx,
2779 struct dcerpc_pipe *p,
2780 struct policy_handle *handle)
2782 NTSTATUS status;
2783 struct spoolss_SetPrinter r;
2784 struct spoolss_SetPrinterInfoCtr info_ctr;
2785 struct spoolss_DevmodeContainer devmode_ctr;
2786 struct sec_desc_buf secdesc_ctr;
2788 info_ctr.level = 0;
2789 info_ctr.info.info0 = NULL;
2791 ZERO_STRUCT(devmode_ctr);
2792 ZERO_STRUCT(secdesc_ctr);
2794 r.in.handle = handle;
2795 r.in.info_ctr = &info_ctr;
2796 r.in.devmode_ctr = &devmode_ctr;
2797 r.in.secdesc_ctr = &secdesc_ctr;
2798 r.in.command = SPOOLSS_PRINTER_CONTROL_PAUSE;
2800 torture_comment(tctx, "Testing SetPrinter: SPOOLSS_PRINTER_CONTROL_PAUSE\n");
2802 status = dcerpc_spoolss_SetPrinter(p, tctx, &r);
2804 torture_assert_ntstatus_ok(tctx, status, "SetPrinter failed");
2806 torture_assert_werr_ok(tctx, r.out.result, "SetPrinter failed");
2808 return true;
2811 static bool test_ResumePrinter(struct torture_context *tctx,
2812 struct dcerpc_pipe *p,
2813 struct policy_handle *handle)
2815 NTSTATUS status;
2816 struct spoolss_SetPrinter r;
2817 struct spoolss_SetPrinterInfoCtr info_ctr;
2818 struct spoolss_DevmodeContainer devmode_ctr;
2819 struct sec_desc_buf secdesc_ctr;
2821 info_ctr.level = 0;
2822 info_ctr.info.info0 = NULL;
2824 ZERO_STRUCT(devmode_ctr);
2825 ZERO_STRUCT(secdesc_ctr);
2827 r.in.handle = handle;
2828 r.in.info_ctr = &info_ctr;
2829 r.in.devmode_ctr = &devmode_ctr;
2830 r.in.secdesc_ctr = &secdesc_ctr;
2831 r.in.command = SPOOLSS_PRINTER_CONTROL_RESUME;
2833 torture_comment(tctx, "Testing SetPrinter: SPOOLSS_PRINTER_CONTROL_RESUME\n");
2835 status = dcerpc_spoolss_SetPrinter(p, tctx, &r);
2837 torture_assert_ntstatus_ok(tctx, status, "SetPrinter failed");
2839 torture_assert_werr_ok(tctx, r.out.result, "SetPrinter failed");
2841 return true;
2844 static bool test_GetPrinterData(struct torture_context *tctx,
2845 struct dcerpc_pipe *p,
2846 struct policy_handle *handle,
2847 const char *value_name,
2848 enum winreg_Type *type_p,
2849 uint8_t **data_p,
2850 uint32_t *needed_p)
2852 NTSTATUS status;
2853 struct spoolss_GetPrinterData r;
2854 uint32_t needed;
2855 enum winreg_Type type;
2856 union spoolss_PrinterData data;
2858 r.in.handle = handle;
2859 r.in.value_name = value_name;
2860 r.in.offered = 0;
2861 r.out.needed = &needed;
2862 r.out.type = &type;
2863 r.out.data = talloc_zero_array(tctx, uint8_t, r.in.offered);
2865 torture_comment(tctx, "Testing GetPrinterData(%s)\n", r.in.value_name);
2867 status = dcerpc_spoolss_GetPrinterData(p, tctx, &r);
2868 torture_assert_ntstatus_ok(tctx, status, "GetPrinterData failed");
2870 if (W_ERROR_EQUAL(r.out.result, WERR_MORE_DATA)) {
2871 r.in.offered = needed;
2872 r.out.data = talloc_zero_array(tctx, uint8_t, r.in.offered);
2873 status = dcerpc_spoolss_GetPrinterData(p, tctx, &r);
2874 torture_assert_ntstatus_ok(tctx, status, "GetPrinterData failed");
2877 torture_assert_werr_ok(tctx, r.out.result,
2878 talloc_asprintf(tctx, "GetPrinterData(%s) failed", r.in.value_name));
2880 CHECK_NEEDED_SIZE_LEVEL(spoolss_PrinterData, &data, type, lp_iconv_convenience(tctx->lp_ctx), needed, 1);
2882 if (type_p) {
2883 *type_p = type;
2886 if (data_p) {
2887 *data_p = r.out.data;
2890 if (needed_p) {
2891 *needed_p = needed;
2894 return true;
2897 static bool test_GetPrinterDataEx(struct torture_context *tctx,
2898 struct dcerpc_pipe *p,
2899 struct policy_handle *handle,
2900 const char *key_name,
2901 const char *value_name,
2902 enum winreg_Type *type_p,
2903 uint8_t **data_p,
2904 uint32_t *needed_p)
2906 NTSTATUS status;
2907 struct spoolss_GetPrinterDataEx r;
2908 enum winreg_Type type;
2909 uint32_t needed;
2910 union spoolss_PrinterData data;
2912 r.in.handle = handle;
2913 r.in.key_name = key_name;
2914 r.in.value_name = value_name;
2915 r.in.offered = 0;
2916 r.out.type = &type;
2917 r.out.needed = &needed;
2918 r.out.data = talloc_zero_array(tctx, uint8_t, r.in.offered);
2920 torture_comment(tctx, "Testing GetPrinterDataEx(%s - %s)\n",
2921 r.in.key_name, r.in.value_name);
2923 status = dcerpc_spoolss_GetPrinterDataEx(p, tctx, &r);
2924 if (!NT_STATUS_IS_OK(status)) {
2925 if (NT_STATUS_EQUAL(status,NT_STATUS_NET_WRITE_FAULT) &&
2926 p->last_fault_code == DCERPC_FAULT_OP_RNG_ERROR) {
2927 torture_skip(tctx, "GetPrinterDataEx not supported by server\n");
2929 torture_assert_ntstatus_ok(tctx, status, "GetPrinterDataEx failed");
2932 if (W_ERROR_EQUAL(r.out.result, WERR_MORE_DATA)) {
2933 r.in.offered = needed;
2934 r.out.data = talloc_zero_array(tctx, uint8_t, r.in.offered);
2935 status = dcerpc_spoolss_GetPrinterDataEx(p, tctx, &r);
2936 torture_assert_ntstatus_ok(tctx, status, "GetPrinterDataEx failed");
2939 torture_assert_werr_ok(tctx, r.out.result,
2940 talloc_asprintf(tctx, "GetPrinterDataEx(%s - %s) failed", r.in.key_name, r.in.value_name));
2942 CHECK_NEEDED_SIZE_LEVEL(spoolss_PrinterData, &data, type, lp_iconv_convenience(tctx->lp_ctx), needed, 1);
2944 if (type_p) {
2945 *type_p = type;
2948 if (data_p) {
2949 *data_p = r.out.data;
2952 if (needed_p) {
2953 *needed_p = needed;
2956 return true;
2959 static bool test_GetPrinterData_list(struct torture_context *tctx,
2960 struct dcerpc_pipe *p,
2961 struct policy_handle *handle)
2963 const char *list[] = {
2964 "W3SvcInstalled",
2965 "BeepEnabled",
2966 "EventLog",
2967 /* "NetPopup", not on w2k8 */
2968 /* "NetPopupToComputer", not on w2k8 */
2969 "MajorVersion",
2970 "MinorVersion",
2971 "DefaultSpoolDirectory",
2972 "Architecture",
2973 "DsPresent",
2974 "OSVersion",
2975 /* "OSVersionEx", not on s3 */
2976 "DNSMachineName"
2978 int i;
2980 for (i=0; i < ARRAY_SIZE(list); i++) {
2981 enum winreg_Type type, type_ex;
2982 uint8_t *data, *data_ex;
2983 uint32_t needed, needed_ex;
2985 torture_assert(tctx, test_GetPrinterData(tctx, p, handle, list[i], &type, &data, &needed),
2986 talloc_asprintf(tctx, "GetPrinterData failed on %s\n", list[i]));
2987 torture_assert(tctx, test_GetPrinterDataEx(tctx, p, handle, "random_string", list[i], &type_ex, &data_ex, &needed_ex),
2988 talloc_asprintf(tctx, "GetPrinterDataEx failed on %s\n", list[i]));
2989 torture_assert_int_equal(tctx, type, type_ex, "type mismatch");
2990 torture_assert_int_equal(tctx, needed, needed_ex, "needed mismatch");
2991 torture_assert_mem_equal(tctx, data, data_ex, needed, "data mismatch");
2994 return true;
2997 static bool test_EnumPrinterData(struct torture_context *tctx, struct dcerpc_pipe *p,
2998 struct policy_handle *handle)
3000 NTSTATUS status;
3001 struct spoolss_EnumPrinterData r;
3003 ZERO_STRUCT(r);
3004 r.in.handle = handle;
3005 r.in.enum_index = 0;
3007 do {
3008 uint32_t value_size = 0;
3009 uint32_t data_size = 0;
3010 enum winreg_Type type = 0;
3012 r.in.value_offered = value_size;
3013 r.out.value_needed = &value_size;
3014 r.in.data_offered = data_size;
3015 r.out.data_needed = &data_size;
3017 r.out.type = &type;
3018 r.out.data = talloc_zero_array(tctx, uint8_t, 0);
3020 torture_comment(tctx, "Testing EnumPrinterData\n");
3022 status = dcerpc_spoolss_EnumPrinterData(p, tctx, &r);
3024 torture_assert_ntstatus_ok(tctx, status, "EnumPrinterData failed");
3025 if (W_ERROR_EQUAL(r.out.result, WERR_NO_MORE_ITEMS)) {
3026 break;
3028 torture_assert_werr_ok(tctx, r.out.result, "EnumPrinterData");
3030 r.in.value_offered = value_size;
3031 r.out.value_name = talloc_zero_array(tctx, const char, value_size);
3032 r.in.data_offered = data_size;
3033 r.out.data = talloc_zero_array(tctx, uint8_t, data_size);
3035 status = dcerpc_spoolss_EnumPrinterData(p, tctx, &r);
3037 torture_assert_ntstatus_ok(tctx, status, "EnumPrinterData failed");
3038 if (W_ERROR_EQUAL(r.out.result, WERR_NO_MORE_ITEMS)) {
3039 break;
3042 torture_assert_werr_ok(tctx, r.out.result, "EnumPrinterData failed");
3044 torture_assert(tctx, test_GetPrinterData(tctx, p, handle, r.out.value_name, NULL, NULL, NULL),
3045 talloc_asprintf(tctx, "failed to call GetPrinterData for %s\n", r.out.value_name));
3047 torture_assert(tctx, test_GetPrinterDataEx(tctx, p, handle, "PrinterDriverData", r.out.value_name, NULL, NULL, NULL),
3048 talloc_asprintf(tctx, "failed to call GetPrinterDataEx on PrinterDriverData for %s\n", r.out.value_name));
3050 r.in.enum_index++;
3052 } while (W_ERROR_IS_OK(r.out.result));
3054 return true;
3057 static bool test_EnumPrinterDataEx(struct torture_context *tctx,
3058 struct dcerpc_pipe *p,
3059 struct policy_handle *handle,
3060 const char *key_name,
3061 uint32_t *count_p,
3062 struct spoolss_PrinterEnumValues **info_p)
3064 struct spoolss_EnumPrinterDataEx r;
3065 struct spoolss_PrinterEnumValues *info;
3066 uint32_t needed;
3067 uint32_t count;
3069 r.in.handle = handle;
3070 r.in.key_name = key_name;
3071 r.in.offered = 0;
3072 r.out.needed = &needed;
3073 r.out.count = &count;
3074 r.out.info = &info;
3076 torture_comment(tctx, "Testing EnumPrinterDataEx(%s)\n", key_name);
3078 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_EnumPrinterDataEx(p, tctx, &r),
3079 "EnumPrinterDataEx failed");
3080 if (W_ERROR_EQUAL(r.out.result, WERR_MORE_DATA)) {
3081 r.in.offered = needed;
3082 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_EnumPrinterDataEx(p, tctx, &r),
3083 "EnumPrinterDataEx failed");
3086 torture_assert_werr_ok(tctx, r.out.result, "EnumPrinterDataEx failed");
3088 CHECK_NEEDED_SIZE_ENUM(spoolss_EnumPrinterDataEx, info, count, lp_iconv_convenience(tctx->lp_ctx), needed, 1);
3090 if (count_p) {
3091 *count_p = count;
3093 if (info_p) {
3094 *info_p = info;
3097 return true;
3101 static bool test_DeletePrinterData(struct torture_context *tctx,
3102 struct dcerpc_pipe *p,
3103 struct policy_handle *handle,
3104 const char *value_name)
3106 NTSTATUS status;
3107 struct spoolss_DeletePrinterData r;
3109 r.in.handle = handle;
3110 r.in.value_name = value_name;
3112 torture_comment(tctx, "Testing DeletePrinterData(%s)\n",
3113 r.in.value_name);
3115 status = dcerpc_spoolss_DeletePrinterData(p, tctx, &r);
3117 torture_assert_ntstatus_ok(tctx, status, "DeletePrinterData failed");
3118 torture_assert_werr_ok(tctx, r.out.result, "DeletePrinterData failed");
3120 return true;
3123 static bool test_DeletePrinterDataEx(struct torture_context *tctx,
3124 struct dcerpc_pipe *p,
3125 struct policy_handle *handle,
3126 const char *key_name,
3127 const char *value_name)
3129 struct spoolss_DeletePrinterDataEx r;
3131 r.in.handle = handle;
3132 r.in.key_name = key_name;
3133 r.in.value_name = value_name;
3135 torture_comment(tctx, "Testing DeletePrinterDataEx(%s - %s)\n",
3136 r.in.key_name, r.in.value_name);
3138 torture_assert_ntstatus_ok(tctx,
3139 dcerpc_spoolss_DeletePrinterDataEx(p, tctx, &r),
3140 "DeletePrinterDataEx failed");
3141 torture_assert_werr_ok(tctx, r.out.result,
3142 "DeletePrinterDataEx failed");
3144 return true;
3147 static bool test_DeletePrinterKey(struct torture_context *tctx,
3148 struct dcerpc_pipe *p,
3149 struct policy_handle *handle,
3150 const char *key_name)
3152 struct spoolss_DeletePrinterKey r;
3154 r.in.handle = handle;
3155 r.in.key_name = key_name;
3157 torture_comment(tctx, "Testing DeletePrinterKey(%s)\n", r.in.key_name);
3159 if (strequal(key_name, "") && !torture_setting_bool(tctx, "dangerous", false)) {
3160 torture_skip(tctx, "not wiping out printer registry - enable dangerous tests to use\n");
3161 return true;
3164 torture_assert_ntstatus_ok(tctx,
3165 dcerpc_spoolss_DeletePrinterKey(p, tctx, &r),
3166 "DeletePrinterKey failed");
3167 torture_assert_werr_ok(tctx, r.out.result,
3168 "DeletePrinterKey failed");
3170 return true;
3173 static bool test_SetPrinterData(struct torture_context *tctx,
3174 struct dcerpc_pipe *p,
3175 struct policy_handle *handle)
3177 NTSTATUS status;
3178 struct spoolss_SetPrinterData r;
3179 const char *values[] = {
3180 "spootyfoot",
3181 "spooty\\foot",
3182 #if 0
3183 /* FIXME: not working with s3 atm. */
3184 "spooty,foot",
3185 "spooty,fo,ot",
3186 #endif
3187 "spooty foot",
3188 #if 0
3189 /* FIXME: not working with s3 atm. */
3190 "spooty\\fo,ot",
3191 "spooty,fo\\ot"
3192 #endif
3194 int i;
3196 for (i=0; i < ARRAY_SIZE(values); i++) {
3198 enum winreg_Type type;
3199 uint8_t *data;
3200 DATA_BLOB blob;
3201 uint32_t needed;
3203 torture_assert(tctx,
3204 reg_string_to_val(tctx, lp_iconv_convenience(tctx->lp_ctx),
3205 "REG_SZ", "dog", &r.in.type, &blob), "");
3207 r.in.handle = handle;
3208 r.in.value_name = values[i];
3209 r.in.data = blob.data;
3210 r.in.offered = blob.length;
3212 torture_comment(tctx, "Testing SetPrinterData(%s)\n",
3213 r.in.value_name);
3215 status = dcerpc_spoolss_SetPrinterData(p, tctx, &r);
3217 torture_assert_ntstatus_ok(tctx, status, "SetPrinterData failed");
3218 torture_assert_werr_ok(tctx, r.out.result, "SetPrinterData failed");
3220 if (!test_GetPrinterData(tctx, p, handle, r.in.value_name, &type, &data, &needed)) {
3221 return false;
3224 torture_assert_int_equal(tctx, r.in.type, type, "type mismatch");
3225 torture_assert_int_equal(tctx, r.in.offered, needed, "size mismatch");
3226 torture_assert_mem_equal(tctx, blob.data, data, needed, "buffer mismatch");
3228 if (!test_DeletePrinterData(tctx, p, handle, r.in.value_name)) {
3229 return false;
3233 return true;
3236 static bool test_EnumPrinterKey(struct torture_context *tctx,
3237 struct dcerpc_pipe *p,
3238 struct policy_handle *handle,
3239 const char *key_name,
3240 const char ***array);
3242 static bool test_SetPrinterDataEx(struct torture_context *tctx,
3243 struct dcerpc_pipe *p,
3244 struct policy_handle *handle,
3245 const char *key_name,
3246 const char *value_name,
3247 enum winreg_Type type,
3248 uint8_t *data,
3249 uint32_t offered)
3251 NTSTATUS status;
3252 struct spoolss_SetPrinterDataEx r;
3254 r.in.handle = handle;
3255 r.in.key_name = key_name;
3256 r.in.value_name = value_name;
3257 r.in.type = type;
3258 r.in.data = data;
3259 r.in.offered = offered;
3261 torture_comment(tctx, "Testing SetPrinterDataEx(%s - %s) type: %s, offered: 0x%08x\n",
3262 r.in.key_name, r.in.value_name, str_regtype(r.in.type), r.in.offered);
3264 status = dcerpc_spoolss_SetPrinterDataEx(p, tctx, &r);
3266 torture_assert_ntstatus_ok(tctx, status, "SetPrinterDataEx failed");
3267 torture_assert_werr_ok(tctx, r.out.result, "SetPrinterDataEx failed");
3269 return true;
3272 #define TOP_LEVEL_PRINTER_KEY "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Print\\Printers"
3274 static bool test_winreg_OpenHKLM(struct torture_context *tctx,
3275 struct dcerpc_pipe *p,
3276 struct policy_handle *handle)
3278 struct winreg_OpenHKLM r;
3280 r.in.system_name = NULL;
3281 r.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
3282 r.out.handle = handle;
3284 torture_comment(tctx, "Testing winreg_OpenHKLM\n");
3286 torture_assert_ntstatus_ok(tctx, dcerpc_winreg_OpenHKLM(p, tctx, &r), "OpenHKLM failed");
3287 torture_assert_werr_ok(tctx, r.out.result, "OpenHKLM failed");
3289 return true;
3292 static void init_winreg_String(struct winreg_String *name, const char *s)
3294 name->name = s;
3295 if (s) {
3296 name->name_len = 2 * (strlen_m(s) + 1);
3297 name->name_size = name->name_len;
3298 } else {
3299 name->name_len = 0;
3300 name->name_size = 0;
3304 static bool test_winreg_OpenKey(struct torture_context *tctx,
3305 struct dcerpc_pipe *p,
3306 struct policy_handle *hive_handle,
3307 const char *keyname,
3308 struct policy_handle *key_handle)
3310 struct winreg_OpenKey r;
3312 r.in.parent_handle = hive_handle;
3313 init_winreg_String(&r.in.keyname, keyname);
3314 r.in.unknown = 0x00000000;
3315 r.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
3316 r.out.handle = key_handle;
3318 torture_comment(tctx, "Testing winreg_OpenKey(%s)\n", keyname);
3320 torture_assert_ntstatus_ok(tctx, dcerpc_winreg_OpenKey(p, tctx, &r), "OpenKey failed");
3321 torture_assert_werr_ok(tctx, r.out.result, "OpenKey failed");
3323 return true;
3326 static bool test_winreg_CloseKey(struct torture_context *tctx,
3327 struct dcerpc_pipe *p,
3328 struct policy_handle *handle)
3330 struct winreg_CloseKey r;
3332 r.in.handle = handle;
3333 r.out.handle = handle;
3335 torture_comment(tctx, "Testing winreg_CloseKey\n");
3337 torture_assert_ntstatus_ok(tctx, dcerpc_winreg_CloseKey(p, tctx, &r), "CloseKey failed");
3338 torture_assert_werr_ok(tctx, r.out.result, "CloseKey failed");
3340 return true;
3343 static bool test_winreg_QueryValue(struct torture_context *tctx,
3344 struct dcerpc_pipe *p,
3345 struct policy_handle *handle,
3346 const char *value_name,
3347 enum winreg_Type *type_p,
3348 uint32_t *data_size_p,
3349 uint32_t *data_length_p,
3350 uint8_t **data_p)
3352 struct winreg_QueryValue r;
3353 enum winreg_Type type = REG_NONE;
3354 uint32_t data_size = 0;
3355 uint32_t data_length = 0;
3356 struct winreg_String valuename;
3357 uint8_t *data = NULL;
3359 init_winreg_String(&valuename, value_name);
3361 data = talloc_zero_array(tctx, uint8_t, 0);
3363 r.in.handle = handle;
3364 r.in.value_name = &valuename;
3365 r.in.type = &type;
3366 r.in.data_size = &data_size;
3367 r.in.data_length = &data_length;
3368 r.in.data = data;
3369 r.out.type = &type;
3370 r.out.data = data;
3371 r.out.data_size = &data_size;
3372 r.out.data_length = &data_length;
3374 torture_comment(tctx, "Testing winreg_QueryValue(%s)\n", value_name);
3376 torture_assert_ntstatus_ok(tctx, dcerpc_winreg_QueryValue(p, tctx, &r), "QueryValue failed");
3377 if (W_ERROR_EQUAL(r.out.result, WERR_MORE_DATA)) {
3378 *r.in.data_size = *r.out.data_size;
3379 data = talloc_zero_array(tctx, uint8_t, *r.in.data_size);
3380 r.in.data = data;
3381 r.out.data = data;
3382 torture_assert_ntstatus_ok(tctx, dcerpc_winreg_QueryValue(p, tctx, &r), "QueryValue failed");
3384 torture_assert_werr_ok(tctx, r.out.result, "QueryValue failed");
3386 if (type_p) {
3387 *type_p = *r.out.type;
3389 if (data_size_p) {
3390 *data_size_p = *r.out.data_size;
3392 if (data_length_p) {
3393 *data_length_p = *r.out.data_length;
3395 if (data_p) {
3396 *data_p = r.out.data;
3399 return true;
3402 static bool test_SetPrinterDataEx_matrix(struct torture_context *tctx,
3403 struct dcerpc_pipe *p,
3404 struct policy_handle *handle,
3405 const char *printername,
3406 struct dcerpc_pipe *winreg_pipe,
3407 struct policy_handle *hive_handle)
3409 const char *value_name = "dog";
3410 const char *keys[] = {
3411 "torturedataex",
3412 "torture data ex",
3413 #if 0
3414 /* FIXME: not working with s3 atm. */
3415 "torturedataex_with_subkey\\subkey",
3416 "torturedataex_with_subkey\\subkey:0",
3417 "torturedataex_with_subkey\\subkey:1",
3418 "torturedataex_with_subkey\\subkey\\subsubkey",
3419 "torturedataex_with_subkey\\subkey\\subsubkey:0",
3420 "torturedataex_with_subkey\\subkey\\subsubkey:1",
3421 #endif
3422 "torture,data",
3423 #if 0
3424 /* FIXME: not working with s3 atm. */
3426 "torture,data,ex",
3427 "torture,data\\ex",
3428 "torture\\data,ex"
3429 #endif
3431 enum winreg_Type types[] = {
3432 REG_SZ,
3433 REG_DWORD,
3434 REG_BINARY
3436 const char *str = "abcdefghijklmnopqrstuvwxzy";
3437 int i, t, s;
3440 for (i=0; i < ARRAY_SIZE(keys); i++) {
3441 for (t=0; t < ARRAY_SIZE(types); t++) {
3442 for (s=0; s < strlen(str); s++) {
3444 char *c;
3445 const char *key;
3446 enum winreg_Type type;
3447 const char *string = talloc_strndup(tctx, str, s);
3448 DATA_BLOB blob = data_blob_string_const(string);
3449 const char **subkeys;
3450 DATA_BLOB data;
3451 uint8_t *data_out;
3452 uint32_t needed, offered = 0;
3453 uint32_t ecount;
3454 struct spoolss_PrinterEnumValues *einfo;
3456 switch (types[t]) {
3457 case REG_BINARY:
3458 case REG_DWORD:
3459 data = blob;
3460 offered = blob.length;
3461 break;
3462 case REG_SZ:
3463 torture_assert(tctx,
3464 reg_string_to_val(tctx, lp_iconv_convenience(tctx->lp_ctx),
3465 "REG_SZ", string, &type, &data), "");
3466 offered = data.length;
3467 /*strlen_m_term(data.string)*2;*/
3468 break;
3469 default:
3470 torture_fail(tctx, talloc_asprintf(tctx, "type %d untested\n", types[t]));
3473 torture_assert(tctx,
3474 test_SetPrinterDataEx(tctx, p, handle, keys[i], value_name, types[t], data.data, offered),
3475 "failed to call SetPrinterDataEx");
3477 torture_assert(tctx,
3478 test_GetPrinterDataEx(tctx, p, handle, keys[i], value_name, &type, &data_out, &needed),
3479 "failed to call GetPrinterDataEx");
3481 torture_assert(tctx,
3482 test_EnumPrinterDataEx(tctx, p, handle, keys[i], &ecount, &einfo),
3483 "failed to call EnumPrinterDataEx");
3485 torture_assert_int_equal(tctx, types[t], type, "type mismatch");
3486 torture_assert_int_equal(tctx, needed, offered, "size mismatch");
3487 torture_assert_mem_equal(tctx, data_out, data.data, offered, "buffer mismatch");
3489 torture_assert_int_equal(tctx, ecount, 1, "unexpected enum count");
3490 torture_assert_str_equal(tctx, einfo[0].value_name, value_name, "value_name mismatch");
3491 torture_assert_int_equal(tctx, einfo[0].value_name_len, strlen_m_term(value_name)*2, "unexpected value_name_len");
3492 torture_assert_int_equal(tctx, einfo[0].type, types[t], "type mismatch");
3493 torture_assert_int_equal(tctx, einfo[0].data_length, offered, "size mismatch");
3494 torture_assert_mem_equal(tctx, einfo[0].data->data, data.data, offered, "buffer mismatch");
3496 if (winreg_pipe && hive_handle) {
3497 const char *printer_key;
3498 struct policy_handle key_handle;
3499 enum winreg_Type w_type;
3500 uint32_t w_size, w_length;
3501 uint8_t *w_data;
3503 printer_key = talloc_asprintf(tctx, "%s\\%s\\%s",
3504 TOP_LEVEL_PRINTER_KEY, printername, keys[i]);
3506 torture_assert(tctx, test_winreg_OpenKey(tctx, winreg_pipe, hive_handle, printer_key, &key_handle), "");
3508 torture_assert(tctx,
3509 test_winreg_QueryValue(tctx, winreg_pipe, &key_handle, value_name, &w_type, &w_size, &w_length, &w_data), "");
3511 test_winreg_CloseKey(tctx, winreg_pipe, &key_handle);
3513 torture_assert_int_equal(tctx, w_type, types[t], "winreg type mismatch");
3514 torture_assert_int_equal(tctx, w_size, offered, "winreg size mismatch");
3515 torture_assert_mem_equal(tctx, w_data, data.data, offered, "winreg buffer mismatch");
3518 key = talloc_strdup(tctx, keys[i]);
3520 if (!test_DeletePrinterDataEx(tctx, p, handle, keys[i], value_name)) {
3521 return false;
3524 c = strchr(key, '\\');
3525 if (c) {
3526 int k;
3528 /* we have subkeys */
3530 *c = 0;
3532 if (!test_EnumPrinterKey(tctx, p, handle, key, &subkeys)) {
3533 return false;
3536 for (k=0; subkeys && subkeys[k]; k++) {
3538 const char *current_key = talloc_asprintf(tctx, "%s\\%s", key, subkeys[k]);
3540 if (!test_DeletePrinterKey(tctx, p, handle, current_key)) {
3541 return false;
3545 if (!test_DeletePrinterKey(tctx, p, handle, key)) {
3546 return false;
3549 } else {
3550 if (!test_DeletePrinterKey(tctx, p, handle, key)) {
3551 return false;
3558 return true;
3561 static bool test_PrinterData_winreg(struct torture_context *tctx,
3562 struct dcerpc_pipe *p,
3563 struct policy_handle *handle,
3564 const char *printer_name)
3566 struct dcerpc_pipe *p2;
3567 bool ret = true;
3568 struct policy_handle hive_handle;
3570 torture_assert_ntstatus_ok(tctx,
3571 torture_rpc_connection(tctx, &p2, &ndr_table_winreg),
3572 "could not open winreg pipe");
3574 torture_assert(tctx, test_winreg_OpenHKLM(tctx, p2, &hive_handle), "");
3576 ret = test_SetPrinterDataEx_matrix(tctx, p, handle, printer_name, p2, &hive_handle);
3578 test_winreg_CloseKey(tctx, p2, &hive_handle);
3580 talloc_free(p2);
3582 return ret;
3585 static bool test_GetChangeID_PrinterData(struct torture_context *tctx,
3586 struct dcerpc_pipe *p,
3587 struct policy_handle *handle,
3588 uint32_t *change_id)
3590 enum winreg_Type type;
3591 uint8_t *data;
3592 uint32_t needed;
3594 torture_assert(tctx,
3595 test_GetPrinterData(tctx, p, handle, "ChangeID", &type, &data, &needed),
3596 "failed to call GetPrinterData");
3598 torture_assert(tctx, type == REG_DWORD, "unexpected type");
3599 torture_assert_int_equal(tctx, needed, 4, "unexpected size");
3601 *change_id = IVAL(data, 0);
3603 return true;
3606 static bool test_GetChangeID_PrinterDataEx(struct torture_context *tctx,
3607 struct dcerpc_pipe *p,
3608 struct policy_handle *handle,
3609 uint32_t *change_id)
3611 enum winreg_Type type;
3612 uint8_t *data;
3613 uint32_t needed;
3615 torture_assert(tctx,
3616 test_GetPrinterDataEx(tctx, p, handle, "PrinterDriverData", "ChangeID", &type, &data, &needed),
3617 "failed to call GetPrinterData");
3619 torture_assert(tctx, type == REG_DWORD, "unexpected type");
3620 torture_assert_int_equal(tctx, needed, 4, "unexpected size");
3622 *change_id = IVAL(data, 0);
3624 return true;
3627 static bool test_GetChangeID_PrinterInfo(struct torture_context *tctx,
3628 struct dcerpc_pipe *p,
3629 struct policy_handle *handle,
3630 uint32_t *change_id)
3632 union spoolss_PrinterInfo info;
3634 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 0, &info),
3635 "failed to query Printer level 0");
3637 *change_id = info.info0.change_id;
3639 return true;
3642 static bool test_ChangeID(struct torture_context *tctx,
3643 struct dcerpc_pipe *p,
3644 struct policy_handle *handle)
3646 uint32_t change_id, change_id_ex, change_id_info;
3647 uint32_t change_id2, change_id_ex2, change_id_info2;
3648 union spoolss_PrinterInfo info;
3649 const char *comment;
3652 torture_comment(tctx, "Testing ChangeID: id change test #1\n");
3654 torture_assert(tctx, test_GetChangeID_PrinterData(tctx, p, handle, &change_id),
3655 "failed to query for ChangeID");
3656 torture_assert(tctx, test_GetChangeID_PrinterDataEx(tctx, p, handle, &change_id_ex),
3657 "failed to query for ChangeID");
3658 torture_assert(tctx, test_GetChangeID_PrinterInfo(tctx, p, handle, &change_id_info),
3659 "failed to query for ChangeID");
3661 torture_assert_int_equal(tctx, change_id, change_id_ex,
3662 "change_ids should all be equal");
3663 torture_assert_int_equal(tctx, change_id_ex, change_id_info,
3664 "change_ids should all be equal");
3667 torture_comment(tctx, "Testing ChangeID: id change test #2\n");
3669 torture_assert(tctx, test_GetChangeID_PrinterData(tctx, p, handle, &change_id),
3670 "failed to query for ChangeID");
3671 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 2, &info),
3672 "failed to query Printer level 2");
3673 torture_assert(tctx, test_GetChangeID_PrinterDataEx(tctx, p, handle, &change_id_ex),
3674 "failed to query for ChangeID");
3675 torture_assert(tctx, test_GetChangeID_PrinterInfo(tctx, p, handle, &change_id_info),
3676 "failed to query for ChangeID");
3677 torture_assert_int_equal(tctx, change_id, change_id_ex,
3678 "change_id should not have changed");
3679 torture_assert_int_equal(tctx, change_id_ex, change_id_info,
3680 "change_id should not have changed");
3683 torture_comment(tctx, "Testing ChangeID: id change test #3\n");
3685 torture_assert(tctx, test_GetChangeID_PrinterData(tctx, p, handle, &change_id),
3686 "failed to query for ChangeID");
3687 torture_assert(tctx, test_GetChangeID_PrinterDataEx(tctx, p, handle, &change_id_ex),
3688 "failed to query for ChangeID");
3689 torture_assert(tctx, test_GetChangeID_PrinterInfo(tctx, p, handle, &change_id_info),
3690 "failed to query for ChangeID");
3691 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 2, &info),
3692 "failed to query Printer level 2");
3693 comment = talloc_strdup(tctx, info.info2.comment);
3696 struct spoolss_SetPrinterInfoCtr info_ctr;
3697 struct spoolss_DevmodeContainer devmode_ctr;
3698 struct sec_desc_buf secdesc_ctr;
3699 struct spoolss_SetPrinterInfo2 info2;
3701 ZERO_STRUCT(info_ctr);
3702 ZERO_STRUCT(devmode_ctr);
3703 ZERO_STRUCT(secdesc_ctr);
3705 info2.servername = info.info2.servername;
3706 info2.printername = info.info2.printername;
3707 info2.sharename = info.info2.sharename;
3708 info2.portname = info.info2.portname;
3709 info2.drivername = info.info2.drivername;
3710 info2.comment = "torture_comment";
3711 info2.location = info.info2.location;
3712 info2.devmode_ptr = 0;
3713 info2.sepfile = info.info2.sepfile;
3714 info2.printprocessor = info.info2.printprocessor;
3715 info2.datatype = info.info2.datatype;
3716 info2.parameters = info.info2.parameters;
3717 info2.secdesc_ptr = 0;
3718 info2.attributes = info.info2.attributes;
3719 info2.priority = info.info2.priority;
3720 info2.defaultpriority = info.info2.defaultpriority;
3721 info2.starttime = info.info2.starttime;
3722 info2.untiltime = info.info2.untiltime;
3723 info2.status = info.info2.status;
3724 info2.cjobs = info.info2.cjobs;
3725 info2.averageppm = info.info2.averageppm;
3727 info_ctr.level = 2;
3728 info_ctr.info.info2 = &info2;
3730 torture_assert(tctx, test_SetPrinter(tctx, p, handle, &info_ctr, &devmode_ctr, &secdesc_ctr, 0),
3731 "failed to call SetPrinter");
3733 info2.comment = comment;
3735 torture_assert(tctx, test_SetPrinter(tctx, p, handle, &info_ctr, &devmode_ctr, &secdesc_ctr, 0),
3736 "failed to call SetPrinter");
3740 torture_assert(tctx, test_GetChangeID_PrinterData(tctx, p, handle, &change_id2),
3741 "failed to query for ChangeID");
3742 torture_assert(tctx, test_GetChangeID_PrinterDataEx(tctx, p, handle, &change_id_ex2),
3743 "failed to query for ChangeID");
3744 torture_assert(tctx, test_GetChangeID_PrinterInfo(tctx, p, handle, &change_id_info2),
3745 "failed to query for ChangeID");
3747 torture_assert_int_equal(tctx, change_id2, change_id_ex2,
3748 "change_ids should all be equal");
3749 torture_assert_int_equal(tctx, change_id_ex2, change_id_info2,
3750 "change_ids should all be equal");
3752 torture_assert(tctx, (change_id < change_id2),
3753 talloc_asprintf(tctx, "change_id %d needs to be larger than change_id %d",
3754 change_id2, change_id));
3755 torture_assert(tctx, (change_id_ex < change_id_ex2),
3756 talloc_asprintf(tctx, "change_id %d needs to be larger than change_id %d",
3757 change_id_ex2, change_id_ex));
3758 torture_assert(tctx, (change_id_info < change_id_info2),
3759 talloc_asprintf(tctx, "change_id %d needs to be larger than change_id %d",
3760 change_id_info2, change_id_info));
3762 return true;
3765 static bool test_SecondaryClosePrinter(struct torture_context *tctx,
3766 struct dcerpc_pipe *p,
3767 struct policy_handle *handle)
3769 NTSTATUS status;
3770 struct dcerpc_binding *b;
3771 struct dcerpc_pipe *p2;
3772 struct spoolss_ClosePrinter cp;
3774 /* only makes sense on SMB */
3775 if (p->conn->transport.transport != NCACN_NP) {
3776 return true;
3779 torture_comment(tctx, "testing close on secondary pipe\n");
3781 status = dcerpc_parse_binding(tctx, p->conn->binding_string, &b);
3782 torture_assert_ntstatus_ok(tctx, status, "Failed to parse dcerpc binding");
3784 status = dcerpc_secondary_connection(p, &p2, b);
3785 torture_assert_ntstatus_ok(tctx, status, "Failed to create secondary connection");
3787 status = dcerpc_bind_auth_none(p2, &ndr_table_spoolss);
3788 torture_assert_ntstatus_ok(tctx, status, "Failed to create bind on secondary connection");
3790 cp.in.handle = handle;
3791 cp.out.handle = handle;
3793 status = dcerpc_spoolss_ClosePrinter(p2, tctx, &cp);
3794 torture_assert_ntstatus_equal(tctx, status, NT_STATUS_NET_WRITE_FAULT,
3795 "ERROR: Allowed close on secondary connection");
3797 torture_assert_int_equal(tctx, p2->last_fault_code, DCERPC_FAULT_CONTEXT_MISMATCH,
3798 "Unexpected fault code");
3800 talloc_free(p2);
3802 return true;
3805 static bool test_OpenPrinter_badname(struct torture_context *tctx,
3806 struct dcerpc_pipe *p, const char *name)
3808 NTSTATUS status;
3809 struct spoolss_OpenPrinter op;
3810 struct spoolss_OpenPrinterEx opEx;
3811 struct policy_handle handle;
3812 bool ret = true;
3814 op.in.printername = name;
3815 op.in.datatype = NULL;
3816 op.in.devmode_ctr.devmode= NULL;
3817 op.in.access_mask = 0;
3818 op.out.handle = &handle;
3820 torture_comment(tctx, "\nTesting OpenPrinter(%s) with bad name\n", op.in.printername);
3822 status = dcerpc_spoolss_OpenPrinter(p, tctx, &op);
3823 torture_assert_ntstatus_ok(tctx, status, "OpenPrinter failed");
3824 if (!W_ERROR_EQUAL(WERR_INVALID_PRINTER_NAME,op.out.result)) {
3825 torture_comment(tctx, "OpenPrinter(%s) unexpected result[%s] should be WERR_INVALID_PRINTER_NAME\n",
3826 name, win_errstr(op.out.result));
3829 if (W_ERROR_IS_OK(op.out.result)) {
3830 ret &=test_ClosePrinter(tctx, p, &handle);
3833 opEx.in.printername = name;
3834 opEx.in.datatype = NULL;
3835 opEx.in.devmode_ctr.devmode = NULL;
3836 opEx.in.access_mask = 0;
3837 opEx.in.level = 1;
3838 opEx.in.userlevel.level1 = NULL;
3839 opEx.out.handle = &handle;
3841 torture_comment(tctx, "Testing OpenPrinterEx(%s) with bad name\n", opEx.in.printername);
3843 status = dcerpc_spoolss_OpenPrinterEx(p, tctx, &opEx);
3844 torture_assert_ntstatus_ok(tctx, status, "OpenPrinterEx failed");
3845 if (!W_ERROR_EQUAL(WERR_INVALID_PARAM,opEx.out.result)) {
3846 torture_comment(tctx, "OpenPrinterEx(%s) unexpected result[%s] should be WERR_INVALID_PARAM\n",
3847 name, win_errstr(opEx.out.result));
3850 if (W_ERROR_IS_OK(opEx.out.result)) {
3851 ret &=test_ClosePrinter(tctx, p, &handle);
3854 return ret;
3857 static bool test_OpenPrinter(struct torture_context *tctx,
3858 struct dcerpc_pipe *p,
3859 const char *name,
3860 const char *environment)
3862 NTSTATUS status;
3863 struct spoolss_OpenPrinter r;
3864 struct policy_handle handle;
3865 bool ret = true;
3867 r.in.printername = talloc_asprintf(tctx, "\\\\%s\\%s", dcerpc_server_name(p), name);
3868 r.in.datatype = NULL;
3869 r.in.devmode_ctr.devmode= NULL;
3870 r.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
3871 r.out.handle = &handle;
3873 torture_comment(tctx, "Testing OpenPrinter(%s)\n", r.in.printername);
3875 status = dcerpc_spoolss_OpenPrinter(p, tctx, &r);
3877 torture_assert_ntstatus_ok(tctx, status, "OpenPrinter failed");
3879 torture_assert_werr_ok(tctx, r.out.result, "OpenPrinter failed");
3881 if (!test_GetPrinter(tctx, p, &handle, environment)) {
3882 ret = false;
3885 if (!torture_setting_bool(tctx, "samba3", false)) {
3886 if (!test_SecondaryClosePrinter(tctx, p, &handle)) {
3887 ret = false;
3891 if (!test_ClosePrinter(tctx, p, &handle)) {
3892 ret = false;
3895 return ret;
3898 static bool call_OpenPrinterEx(struct torture_context *tctx,
3899 struct dcerpc_pipe *p,
3900 const char *name,
3901 struct spoolss_DeviceMode *devmode,
3902 struct policy_handle *handle)
3904 struct spoolss_OpenPrinterEx r;
3905 struct spoolss_UserLevel1 userlevel1;
3906 NTSTATUS status;
3908 if (name && name[0]) {
3909 r.in.printername = talloc_asprintf(tctx, "\\\\%s\\%s",
3910 dcerpc_server_name(p), name);
3911 } else {
3912 r.in.printername = talloc_asprintf(tctx, "\\\\%s",
3913 dcerpc_server_name(p));
3916 r.in.datatype = NULL;
3917 r.in.devmode_ctr.devmode= devmode;
3918 r.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
3919 r.in.level = 1;
3920 r.in.userlevel.level1 = &userlevel1;
3921 r.out.handle = handle;
3923 userlevel1.size = 1234;
3924 userlevel1.client = "hello";
3925 userlevel1.user = "spottyfoot!";
3926 userlevel1.build = 1;
3927 userlevel1.major = 2;
3928 userlevel1.minor = 3;
3929 userlevel1.processor = 4;
3931 torture_comment(tctx, "Testing OpenPrinterEx(%s)\n", r.in.printername);
3933 status = dcerpc_spoolss_OpenPrinterEx(p, tctx, &r);
3935 torture_assert_ntstatus_ok(tctx, status, "OpenPrinterEx failed");
3937 torture_assert_werr_ok(tctx, r.out.result, "OpenPrinterEx failed");
3939 return true;
3942 static bool test_OpenPrinterEx(struct torture_context *tctx,
3943 struct dcerpc_pipe *p,
3944 const char *name,
3945 const char *environment)
3947 struct policy_handle handle;
3948 bool ret = true;
3950 if (!call_OpenPrinterEx(tctx, p, name, NULL, &handle)) {
3951 return false;
3954 if (!test_PrinterInfo_SD(tctx, p, &handle)) {
3955 ret = false;
3958 if (!test_GetPrinter(tctx, p, &handle, environment)) {
3959 ret = false;
3962 if (!test_EnumForms(tctx, p, &handle, false)) {
3963 ret = false;
3966 if (!test_AddForm(tctx, p, &handle, false)) {
3967 ret = false;
3970 if (!test_EnumPrinterData(tctx, p, &handle)) {
3971 ret = false;
3974 if (!test_EnumPrinterDataEx(tctx, p, &handle, "PrinterDriverData", NULL, NULL)) {
3975 ret = false;
3978 if (!test_printer_keys(tctx, p, &handle)) {
3979 ret = false;
3982 if (!test_PausePrinter(tctx, p, &handle)) {
3983 ret = false;
3986 if (!test_DoPrintTest(tctx, p, &handle)) {
3987 ret = false;
3990 if (!test_ResumePrinter(tctx, p, &handle)) {
3991 ret = false;
3994 if (!test_SetPrinterData(tctx, p, &handle)) {
3995 ret = false;
3998 if (!test_SetPrinterDataEx_matrix(tctx, p, &handle, name, NULL, NULL)) {
3999 ret = false;
4002 if (!torture_setting_bool(tctx, "samba3", false)) {
4003 if (!test_SecondaryClosePrinter(tctx, p, &handle)) {
4004 ret = false;
4008 if (!test_ClosePrinter(tctx, p, &handle)) {
4009 ret = false;
4012 return ret;
4015 static bool test_EnumPrinters_old(struct torture_context *tctx,
4016 struct dcerpc_pipe *p,
4017 const char *environment)
4019 struct spoolss_EnumPrinters r;
4020 NTSTATUS status;
4021 uint16_t levels[] = {1, 2, 4, 5};
4022 int i;
4023 bool ret = true;
4025 for (i=0;i<ARRAY_SIZE(levels);i++) {
4026 union spoolss_PrinterInfo *info;
4027 int j;
4028 uint32_t needed;
4029 uint32_t count;
4031 r.in.flags = PRINTER_ENUM_LOCAL;
4032 r.in.server = "";
4033 r.in.level = levels[i];
4034 r.in.buffer = NULL;
4035 r.in.offered = 0;
4036 r.out.needed = &needed;
4037 r.out.count = &count;
4038 r.out.info = &info;
4040 torture_comment(tctx, "Testing EnumPrinters level %u\n", r.in.level);
4042 status = dcerpc_spoolss_EnumPrinters(p, tctx, &r);
4043 torture_assert_ntstatus_ok(tctx, status, "EnumPrinters failed");
4045 if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
4046 DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed);
4047 data_blob_clear(&blob);
4048 r.in.buffer = &blob;
4049 r.in.offered = needed;
4050 status = dcerpc_spoolss_EnumPrinters(p, tctx, &r);
4053 torture_assert_ntstatus_ok(tctx, status, "EnumPrinters failed");
4055 torture_assert_werr_ok(tctx, r.out.result, "EnumPrinters failed");
4057 CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumPrinters, info, r.in.level, count, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
4059 if (!info) {
4060 torture_comment(tctx, "No printers returned\n");
4061 return true;
4064 for (j=0;j<count;j++) {
4065 if (r.in.level == 1) {
4066 char *unc = talloc_strdup(tctx, info[j].info1.name);
4067 char *slash, *name;
4068 name = unc;
4069 if (unc[0] == '\\' && unc[1] == '\\') {
4070 unc +=2;
4072 slash = strchr(unc, '\\');
4073 if (slash) {
4074 slash++;
4075 name = slash;
4077 if (!test_OpenPrinter(tctx, p, name, environment)) {
4078 ret = false;
4080 if (!test_OpenPrinterEx(tctx, p, name, environment)) {
4081 ret = false;
4087 return ret;
4090 static bool test_GetPrinterDriver(struct torture_context *tctx,
4091 struct dcerpc_pipe *p,
4092 struct policy_handle *handle,
4093 const char *driver_name)
4095 struct spoolss_GetPrinterDriver r;
4096 uint32_t needed;
4098 r.in.handle = handle;
4099 r.in.architecture = "W32X86";
4100 r.in.level = 1;
4101 r.in.buffer = NULL;
4102 r.in.offered = 0;
4103 r.out.needed = &needed;
4105 torture_comment(tctx, "Testing GetPrinterDriver level %d\n", r.in.level);
4107 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_GetPrinterDriver(p, tctx, &r),
4108 "failed to call GetPrinterDriver");
4109 if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
4110 DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed);
4111 data_blob_clear(&blob);
4112 r.in.buffer = &blob;
4113 r.in.offered = needed;
4114 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_GetPrinterDriver(p, tctx, &r),
4115 "failed to call GetPrinterDriver");
4118 torture_assert_werr_ok(tctx, r.out.result,
4119 "failed to call GetPrinterDriver");
4121 CHECK_NEEDED_SIZE_LEVEL(spoolss_DriverInfo, r.out.info, r.in.level, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
4123 return true;
4126 static bool test_GetPrinterDriver2(struct torture_context *tctx,
4127 struct dcerpc_pipe *p,
4128 struct policy_handle *handle,
4129 const char *driver_name,
4130 const char *architecture)
4132 struct spoolss_GetPrinterDriver2 r;
4133 uint16_t levels[] = {1, 2, 3, 4, 5, 6, 8, 101 };
4134 uint32_t needed;
4135 uint32_t server_major_version;
4136 uint32_t server_minor_version;
4137 int i;
4139 r.in.handle = handle;
4140 r.in.architecture = architecture;
4141 r.in.client_major_version = 3;
4142 r.in.client_minor_version = 0;
4143 r.out.needed = &needed;
4144 r.out.server_major_version = &server_major_version;
4145 r.out.server_minor_version = &server_minor_version;
4147 for (i=0;i<ARRAY_SIZE(levels);i++) {
4149 r.in.buffer = NULL;
4150 r.in.offered = 0;
4151 r.in.level = levels[i];
4153 torture_comment(tctx, "Testing GetPrinterDriver2(%s) level %d\n",
4154 driver_name, r.in.level);
4156 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_GetPrinterDriver2(p, tctx, &r),
4157 "failed to call GetPrinterDriver2");
4158 if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
4159 DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed);
4160 data_blob_clear(&blob);
4161 r.in.buffer = &blob;
4162 r.in.offered = needed;
4163 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_GetPrinterDriver2(p, tctx, &r),
4164 "failed to call GetPrinterDriver2");
4167 if (W_ERROR_EQUAL(r.out.result, WERR_INVALID_LEVEL)) {
4168 switch (r.in.level) {
4169 case 101:
4170 case 8:
4171 continue;
4172 default:
4173 break;
4177 torture_assert_werr_ok(tctx, r.out.result,
4178 "failed to call GetPrinterDriver2");
4180 CHECK_NEEDED_SIZE_LEVEL(spoolss_DriverInfo, r.out.info, r.in.level, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
4183 return true;
4186 static bool test_EnumPrinterDrivers_old(struct torture_context *tctx,
4187 struct dcerpc_pipe *p,
4188 const char *environment)
4190 struct spoolss_EnumPrinterDrivers r;
4191 NTSTATUS status;
4192 uint16_t levels[] = {1, 2, 3, 4, 5, 6};
4193 int i;
4195 for (i=0;i<ARRAY_SIZE(levels);i++) {
4197 uint32_t needed;
4198 uint32_t count;
4199 union spoolss_DriverInfo *info;
4201 r.in.server = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
4202 r.in.environment = environment;
4203 r.in.level = levels[i];
4204 r.in.buffer = NULL;
4205 r.in.offered = 0;
4206 r.out.needed = &needed;
4207 r.out.count = &count;
4208 r.out.info = &info;
4210 torture_comment(tctx, "Testing EnumPrinterDrivers level %u\n", r.in.level);
4212 status = dcerpc_spoolss_EnumPrinterDrivers(p, tctx, &r);
4214 torture_assert_ntstatus_ok(tctx, status, "EnumPrinterDrivers failed");
4216 if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
4217 DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed);
4218 data_blob_clear(&blob);
4219 r.in.buffer = &blob;
4220 r.in.offered = needed;
4221 status = dcerpc_spoolss_EnumPrinterDrivers(p, tctx, &r);
4224 torture_assert_ntstatus_ok(tctx, status, "EnumPrinterDrivers failed");
4226 torture_assert_werr_ok(tctx, r.out.result, "EnumPrinterDrivers failed");
4228 if (!info) {
4229 torture_comment(tctx, "No printer drivers returned\n");
4230 break;
4233 CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumPrinterDrivers, info, r.in.level, count, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
4236 return true;
4239 static bool test_DeletePrinter(struct torture_context *tctx,
4240 struct dcerpc_pipe *p,
4241 struct policy_handle *handle)
4243 struct spoolss_DeletePrinter r;
4245 torture_comment(tctx, "Testing DeletePrinter\n");
4247 r.in.handle = handle;
4249 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_DeletePrinter(p, tctx, &r),
4250 "failed to delete printer");
4251 torture_assert_werr_ok(tctx, r.out.result,
4252 "failed to delete printer");
4254 return true;
4257 static bool test_EnumPrinters_findname(struct torture_context *tctx,
4258 struct dcerpc_pipe *p,
4259 uint32_t flags,
4260 uint32_t level,
4261 const char *name,
4262 bool *found)
4264 struct spoolss_EnumPrinters e;
4265 uint32_t count;
4266 union spoolss_PrinterInfo *info;
4267 uint32_t needed;
4268 int i;
4270 *found = false;
4272 e.in.flags = flags;
4273 e.in.server = NULL;
4274 e.in.level = level;
4275 e.in.buffer = NULL;
4276 e.in.offered = 0;
4277 e.out.count = &count;
4278 e.out.info = &info;
4279 e.out.needed = &needed;
4281 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_EnumPrinters(p, tctx, &e),
4282 "failed to enum printers");
4284 if (W_ERROR_EQUAL(e.out.result, WERR_INSUFFICIENT_BUFFER)) {
4285 DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed);
4286 data_blob_clear(&blob);
4287 e.in.buffer = &blob;
4288 e.in.offered = needed;
4290 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_EnumPrinters(p, tctx, &e),
4291 "failed to enum printers");
4294 torture_assert_werr_ok(tctx, e.out.result,
4295 "failed to enum printers");
4297 for (i=0; i < count; i++) {
4299 const char *current = NULL;
4300 const char *q;
4302 switch (level) {
4303 case 1:
4304 current = info[i].info1.name;
4305 break;
4308 if (strequal(current, name)) {
4309 *found = true;
4310 break;
4313 q = strrchr(current, '\\');
4314 if (q) {
4315 if (!e.in.server) {
4316 torture_warning(tctx,
4317 "server returns printername %s incl. servername although we did not set servername", current);
4319 q++;
4320 if (strequal(q, name)) {
4321 *found = true;
4322 break;
4327 return true;
4330 static bool test_AddPrinter_wellknown(struct torture_context *tctx,
4331 struct dcerpc_pipe *p,
4332 const char *printername,
4333 bool ex)
4335 WERROR result;
4336 struct spoolss_AddPrinter r;
4337 struct spoolss_AddPrinterEx rex;
4338 struct spoolss_SetPrinterInfoCtr info_ctr;
4339 struct spoolss_SetPrinterInfo1 info1;
4340 struct spoolss_DevmodeContainer devmode_ctr;
4341 struct sec_desc_buf secdesc_ctr;
4342 struct spoolss_UserLevelCtr userlevel_ctr;
4343 struct policy_handle handle;
4344 bool found = false;
4346 ZERO_STRUCT(devmode_ctr);
4347 ZERO_STRUCT(secdesc_ctr);
4348 ZERO_STRUCT(userlevel_ctr);
4349 ZERO_STRUCT(info1);
4351 torture_comment(tctx, "Testing AddPrinter%s level 1\n", ex ? "Ex":"");
4353 /* try to add printer to wellknown printer list (level 1) */
4355 userlevel_ctr.level = 1;
4357 info_ctr.info.info1 = &info1;
4358 info_ctr.level = 1;
4360 rex.in.server = NULL;
4361 rex.in.info_ctr = &info_ctr;
4362 rex.in.devmode_ctr = &devmode_ctr;
4363 rex.in.secdesc_ctr = &secdesc_ctr;
4364 rex.in.userlevel_ctr = &userlevel_ctr;
4365 rex.out.handle = &handle;
4367 r.in.server = NULL;
4368 r.in.info_ctr = &info_ctr;
4369 r.in.devmode_ctr = &devmode_ctr;
4370 r.in.secdesc_ctr = &secdesc_ctr;
4371 r.out.handle = &handle;
4373 torture_assert_ntstatus_ok(tctx, ex ? dcerpc_spoolss_AddPrinterEx(p, tctx, &rex) :
4374 dcerpc_spoolss_AddPrinter(p, tctx, &r),
4375 "failed to add printer");
4376 result = ex ? rex.out.result : r.out.result;
4377 torture_assert_werr_equal(tctx, result, WERR_INVALID_PRINTER_NAME,
4378 "unexpected result code");
4380 info1.name = printername;
4381 info1.flags = PRINTER_ATTRIBUTE_SHARED;
4383 torture_assert_ntstatus_ok(tctx, ex ? dcerpc_spoolss_AddPrinterEx(p, tctx, &rex) :
4384 dcerpc_spoolss_AddPrinter(p, tctx, &r),
4385 "failed to add printer");
4386 result = ex ? rex.out.result : r.out.result;
4387 torture_assert_werr_equal(tctx, result, WERR_PRINTER_ALREADY_EXISTS,
4388 "unexpected result code");
4390 /* bizarre protocol, WERR_PRINTER_ALREADY_EXISTS means success here,
4391 better do a real check to see the printer is really there */
4393 torture_assert(tctx, test_EnumPrinters_findname(tctx, p,
4394 PRINTER_ENUM_NETWORK, 1,
4395 printername,
4396 &found),
4397 "failed to enum printers");
4399 torture_assert(tctx, found, "failed to find newly added printer");
4401 info1.flags = 0;
4403 torture_assert_ntstatus_ok(tctx, ex ? dcerpc_spoolss_AddPrinterEx(p, tctx, &rex) :
4404 dcerpc_spoolss_AddPrinter(p, tctx, &r),
4405 "failed to add printer");
4406 result = ex ? rex.out.result : r.out.result;
4407 torture_assert_werr_equal(tctx, result, WERR_PRINTER_ALREADY_EXISTS,
4408 "unexpected result code");
4410 /* bizarre protocol, WERR_PRINTER_ALREADY_EXISTS means success here,
4411 better do a real check to see the printer has really been removed
4412 from the well known printer list */
4414 found = false;
4416 torture_assert(tctx, test_EnumPrinters_findname(tctx, p,
4417 PRINTER_ENUM_NETWORK, 1,
4418 printername,
4419 &found),
4420 "failed to enum printers");
4421 #if 0
4422 torture_assert(tctx, !found, "printer still in well known printer list");
4423 #endif
4424 return true;
4427 static bool test_AddPrinter_normal(struct torture_context *tctx,
4428 struct dcerpc_pipe *p,
4429 struct policy_handle *handle_p,
4430 const char *printername,
4431 const char *drivername,
4432 const char *portname,
4433 bool ex)
4435 WERROR result;
4436 struct spoolss_AddPrinter r;
4437 struct spoolss_AddPrinterEx rex;
4438 struct spoolss_SetPrinterInfoCtr info_ctr;
4439 struct spoolss_SetPrinterInfo2 info2;
4440 struct spoolss_DevmodeContainer devmode_ctr;
4441 struct sec_desc_buf secdesc_ctr;
4442 struct spoolss_UserLevelCtr userlevel_ctr;
4443 struct policy_handle handle;
4444 bool found = false;
4445 bool existing_printer_deleted = false;
4447 ZERO_STRUCT(devmode_ctr);
4448 ZERO_STRUCT(secdesc_ctr);
4449 ZERO_STRUCT(userlevel_ctr);
4451 torture_comment(tctx, "Testing AddPrinter%s level 2\n", ex ? "Ex":"");
4453 userlevel_ctr.level = 1;
4455 rex.in.server = NULL;
4456 rex.in.info_ctr = &info_ctr;
4457 rex.in.devmode_ctr = &devmode_ctr;
4458 rex.in.secdesc_ctr = &secdesc_ctr;
4459 rex.in.userlevel_ctr = &userlevel_ctr;
4460 rex.out.handle = &handle;
4462 r.in.server = NULL;
4463 r.in.info_ctr = &info_ctr;
4464 r.in.devmode_ctr = &devmode_ctr;
4465 r.in.secdesc_ctr = &secdesc_ctr;
4466 r.out.handle = &handle;
4468 again:
4470 /* try to add printer to printer list (level 2) */
4472 ZERO_STRUCT(info2);
4474 info_ctr.info.info2 = &info2;
4475 info_ctr.level = 2;
4477 torture_assert_ntstatus_ok(tctx, ex ? dcerpc_spoolss_AddPrinterEx(p, tctx, &rex) :
4478 dcerpc_spoolss_AddPrinter(p, tctx, &r),
4479 "failed to add printer");
4480 result = ex ? rex.out.result : r.out.result;
4481 torture_assert_werr_equal(tctx, result, WERR_INVALID_PRINTER_NAME,
4482 "unexpected result code");
4484 info2.printername = printername;
4486 torture_assert_ntstatus_ok(tctx, ex ? dcerpc_spoolss_AddPrinterEx(p, tctx, &rex) :
4487 dcerpc_spoolss_AddPrinter(p, tctx, &r),
4488 "failed to add printer");
4489 result = ex ? rex.out.result : r.out.result;
4491 if (W_ERROR_EQUAL(result, WERR_PRINTER_ALREADY_EXISTS)) {
4492 struct policy_handle printer_handle;
4494 if (existing_printer_deleted) {
4495 torture_fail(tctx, "already deleted printer still existing?");
4498 torture_assert(tctx, call_OpenPrinterEx(tctx, p, printername, NULL, &printer_handle),
4499 "failed to open printer handle");
4501 torture_assert(tctx, test_DeletePrinter(tctx, p, &printer_handle),
4502 "failed to delete printer");
4504 torture_assert(tctx, test_ClosePrinter(tctx, p, &printer_handle),
4505 "failed to close server handle");
4507 existing_printer_deleted = true;
4509 goto again;
4512 torture_assert_werr_equal(tctx, result, WERR_UNKNOWN_PORT,
4513 "unexpected result code");
4515 info2.portname = portname;
4517 torture_assert_ntstatus_ok(tctx, ex ? dcerpc_spoolss_AddPrinterEx(p, tctx, &rex) :
4518 dcerpc_spoolss_AddPrinter(p, tctx, &r),
4519 "failed to add printer");
4520 result = ex ? rex.out.result : r.out.result;
4521 torture_assert_werr_equal(tctx, result, WERR_UNKNOWN_PRINTER_DRIVER,
4522 "unexpected result code");
4524 info2.drivername = drivername;
4526 torture_assert_ntstatus_ok(tctx, ex ? dcerpc_spoolss_AddPrinterEx(p, tctx, &rex) :
4527 dcerpc_spoolss_AddPrinter(p, tctx, &r),
4528 "failed to add printer");
4529 result = ex ? rex.out.result : r.out.result;
4531 /* w2k8r2 allows to add printer w/o defining printprocessor */
4533 if (!W_ERROR_IS_OK(result)) {
4534 torture_assert_werr_equal(tctx, result, WERR_UNKNOWN_PRINTPROCESSOR,
4535 "unexpected result code");
4537 info2.printprocessor = "winprint";
4539 torture_assert_ntstatus_ok(tctx, ex ? dcerpc_spoolss_AddPrinterEx(p, tctx, &rex) :
4540 dcerpc_spoolss_AddPrinter(p, tctx, &r),
4541 "failed to add printer");
4542 result = ex ? rex.out.result : r.out.result;
4543 torture_assert_werr_ok(tctx, result,
4544 "failed to add printer");
4547 *handle_p = handle;
4549 /* we are paranoid, really check if the printer is there now */
4551 torture_assert(tctx, test_EnumPrinters_findname(tctx, p,
4552 PRINTER_ENUM_LOCAL, 1,
4553 printername,
4554 &found),
4555 "failed to enum printers");
4556 torture_assert(tctx, found, "failed to find newly added printer");
4558 torture_assert_ntstatus_ok(tctx, ex ? dcerpc_spoolss_AddPrinterEx(p, tctx, &rex) :
4559 dcerpc_spoolss_AddPrinter(p, tctx, &r),
4560 "failed to add printer");
4561 result = ex ? rex.out.result : r.out.result;
4562 torture_assert_werr_equal(tctx, result, WERR_PRINTER_ALREADY_EXISTS,
4563 "unexpected result code");
4565 return true;
4568 static bool test_AddPrinterEx(struct torture_context *tctx,
4569 struct dcerpc_pipe *p,
4570 struct policy_handle *handle_p,
4571 const char *printername,
4572 const char *drivername,
4573 const char *portname)
4575 bool ret = true;
4577 if (!torture_setting_bool(tctx, "samba3", false)) {
4578 if (!test_AddPrinter_wellknown(tctx, p, TORTURE_WELLKNOWN_PRINTER_EX, true)) {
4579 torture_comment(tctx, "failed to add printer to well known list\n");
4580 ret = false;
4584 if (!test_AddPrinter_normal(tctx, p, handle_p,
4585 printername, drivername, portname,
4586 true)) {
4587 torture_comment(tctx, "failed to add printer to printer list\n");
4588 ret = false;
4591 return ret;
4594 static bool test_AddPrinter(struct torture_context *tctx,
4595 struct dcerpc_pipe *p,
4596 struct policy_handle *handle_p,
4597 const char *printername,
4598 const char *drivername,
4599 const char *portname)
4601 bool ret = true;
4603 if (!torture_setting_bool(tctx, "samba3", false)) {
4604 if (!test_AddPrinter_wellknown(tctx, p, TORTURE_WELLKNOWN_PRINTER, false)) {
4605 torture_comment(tctx, "failed to add printer to well known list\n");
4606 ret = false;
4610 if (!test_AddPrinter_normal(tctx, p, handle_p,
4611 printername, drivername, portname,
4612 false)) {
4613 torture_comment(tctx, "failed to add printer to printer list\n");
4614 ret = false;
4617 return ret;
4620 static bool test_printer_info(struct torture_context *tctx,
4621 struct dcerpc_pipe *p,
4622 struct policy_handle *handle)
4624 bool ret = true;
4626 if (torture_setting_bool(tctx, "samba3", false)) {
4627 torture_skip(tctx, "skipping printer info cross tests against samba 3");
4630 if (!test_PrinterInfo(tctx, p, handle)) {
4631 ret = false;
4634 if (!test_SetPrinter_errors(tctx, p, handle)) {
4635 ret = false;
4638 return ret;
4641 static bool test_EnumPrinterKey(struct torture_context *tctx,
4642 struct dcerpc_pipe *p,
4643 struct policy_handle *handle,
4644 const char *key_name,
4645 const char ***array)
4647 struct spoolss_EnumPrinterKey r;
4648 uint32_t needed = 0;
4649 union spoolss_KeyNames key_buffer;
4650 int32_t offered[] = { 0, 1, 2, 3, 4, 5, -1, -2, -3, -4, -5, 256, 512, 1024, 2048 };
4651 uint32_t _ndr_size;
4652 int i;
4654 r.in.handle = handle;
4655 r.in.key_name = key_name;
4656 r.out.key_buffer = &key_buffer;
4657 r.out.needed = &needed;
4658 r.out._ndr_size = &_ndr_size;
4660 for (i=0; i < ARRAY_SIZE(offered); i++) {
4662 if (offered[i] < 0 && needed) {
4663 if (needed <= 4) {
4664 continue;
4666 r.in.offered = needed + offered[i];
4667 } else {
4668 r.in.offered = offered[i];
4671 ZERO_STRUCT(key_buffer);
4673 torture_comment(tctx, "Testing EnumPrinterKey(%s) with %d offered\n", r.in.key_name, r.in.offered);
4675 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_EnumPrinterKey(p, tctx, &r),
4676 "failed to call EnumPrinterKey");
4677 if (W_ERROR_EQUAL(r.out.result, WERR_MORE_DATA)) {
4679 torture_assert(tctx, (_ndr_size == r.in.offered/2),
4680 talloc_asprintf(tctx, "EnumPrinterKey size mismatch, _ndr_size %d (expected %d)",
4681 _ndr_size, r.in.offered/2));
4683 r.in.offered = needed;
4684 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_EnumPrinterKey(p, tctx, &r),
4685 "failed to call EnumPrinterKey");
4688 if (offered[i] > 0) {
4689 torture_assert_werr_ok(tctx, r.out.result,
4690 "failed to call EnumPrinterKey");
4693 torture_assert(tctx, (_ndr_size == r.in.offered/2),
4694 talloc_asprintf(tctx, "EnumPrinterKey size mismatch, _ndr_size %d (expected %d)",
4695 _ndr_size, r.in.offered/2));
4697 torture_assert(tctx, (*r.out.needed <= r.in.offered),
4698 talloc_asprintf(tctx, "EnumPrinterKey size mismatch: needed %d is not <= offered %d", *r.out.needed, r.in.offered));
4700 torture_assert(tctx, (*r.out.needed <= _ndr_size * 2),
4701 talloc_asprintf(tctx, "EnumPrinterKey size mismatch: needed %d is not <= _ndr_size %d * 2", *r.out.needed, _ndr_size));
4703 if (key_buffer.string_array) {
4704 uint32_t calc_needed = 0;
4705 int s;
4706 for (s=0; key_buffer.string_array[s]; s++) {
4707 calc_needed += strlen_m_term(key_buffer.string_array[s])*2;
4709 if (!key_buffer.string_array[0]) {
4710 calc_needed += 2;
4712 calc_needed += 2;
4714 torture_assert_int_equal(tctx, *r.out.needed, calc_needed,
4715 "EnumPrinterKey unexpected size");
4719 if (array) {
4720 *array = key_buffer.string_array;
4723 return true;
4726 bool test_printer_keys(struct torture_context *tctx,
4727 struct dcerpc_pipe *p,
4728 struct policy_handle *handle)
4730 const char **key_array = NULL;
4731 int i;
4733 torture_comment(tctx, "\nTesting Printer Keys\n");
4735 torture_assert(tctx, test_EnumPrinterKey(tctx, p, handle, "", &key_array),
4736 "failed to call test_EnumPrinterKey");
4738 for (i=0; key_array && key_array[i]; i++) {
4739 torture_assert(tctx, test_EnumPrinterKey(tctx, p, handle, key_array[i], NULL),
4740 "failed to call test_EnumPrinterKey");
4742 for (i=0; key_array && key_array[i]; i++) {
4743 torture_assert(tctx, test_EnumPrinterDataEx(tctx, p, handle, key_array[i], NULL, NULL),
4744 "failed to call test_EnumPrinterDataEx");
4747 return true;
4750 static bool test_one_printer(struct torture_context *tctx,
4751 struct dcerpc_pipe *p,
4752 struct policy_handle *handle,
4753 const char *name)
4755 bool ret = true;
4757 if (!test_printer_info(tctx, p, handle)) {
4758 ret = false;
4761 if (!test_PrinterInfo_SD(tctx, p, handle)) {
4762 ret = false;
4765 if (!test_PrinterInfo_DevMode(tctx, p, handle, name)) {
4766 ret = false;
4769 if (!test_ChangeID(tctx, p, handle)) {
4770 ret = false;
4773 if (!test_printer_keys(tctx, p, handle)) {
4774 ret = false;
4777 if (!test_SetPrinterDataEx_matrix(tctx, p, handle, name, NULL, NULL)) {
4778 ret = false;
4781 if (!test_PrinterData_winreg(tctx, p, handle, name)) {
4782 ret = false;
4785 return ret;
4788 static bool test_printer(struct torture_context *tctx,
4789 struct dcerpc_pipe *p)
4791 bool ret = true;
4792 struct policy_handle handle[2];
4793 bool found = false;
4794 const char *drivername = "Microsoft XPS Document Writer";
4795 const char *portname = "LPT1:";
4797 /* test printer created via AddPrinter */
4799 if (!test_AddPrinter(tctx, p, &handle[0], TORTURE_PRINTER, drivername, portname)) {
4800 return false;
4803 if (!test_one_printer(tctx, p, &handle[0], TORTURE_PRINTER)) {
4804 ret = false;
4807 if (!test_DeletePrinter(tctx, p, &handle[0])) {
4808 ret = false;
4811 if (!test_EnumPrinters_findname(tctx, p, PRINTER_ENUM_LOCAL, 1,
4812 TORTURE_PRINTER, &found)) {
4813 ret = false;
4816 torture_assert(tctx, !found, "deleted printer still there");
4818 /* test printer created via AddPrinterEx */
4820 if (!test_AddPrinterEx(tctx, p, &handle[1], TORTURE_PRINTER_EX, drivername, portname)) {
4821 return false;
4824 if (!test_one_printer(tctx, p, &handle[1], TORTURE_PRINTER_EX)) {
4825 ret = false;
4828 if (!test_DeletePrinter(tctx, p, &handle[1])) {
4829 ret = false;
4832 if (!test_EnumPrinters_findname(tctx, p, PRINTER_ENUM_LOCAL, 1,
4833 TORTURE_PRINTER_EX, &found)) {
4834 ret = false;
4837 torture_assert(tctx, !found, "deleted printer still there");
4839 return ret;
4842 static bool test_architecture_buffer(struct torture_context *tctx,
4843 struct dcerpc_pipe *p)
4845 struct spoolss_OpenPrinterEx r;
4846 struct spoolss_UserLevel1 u1;
4847 struct policy_handle handle;
4848 uint32_t architectures[] = {
4849 PROCESSOR_ARCHITECTURE_INTEL,
4850 PROCESSOR_ARCHITECTURE_IA64,
4851 PROCESSOR_ARCHITECTURE_AMD64
4853 uint32_t needed[3];
4854 int i;
4856 for (i=0; i < ARRAY_SIZE(architectures); i++) {
4858 torture_comment(tctx, "Testing OpenPrinterEx with architecture %d\n", architectures[i]);
4860 u1.size = 0;
4861 u1.client = NULL;
4862 u1.user = NULL;
4863 u1.build = 0;
4864 u1.major = 3;
4865 u1.minor = 0;
4866 u1.processor = architectures[i];
4868 r.in.printername = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
4869 r.in.datatype = NULL;
4870 r.in.devmode_ctr.devmode= NULL;
4871 r.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
4872 r.in.level = 1;
4873 r.in.userlevel.level1 = &u1;
4874 r.out.handle = &handle;
4876 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_OpenPrinterEx(p, tctx, &r), "");
4877 torture_assert_werr_ok(tctx, r.out.result, "");
4880 struct spoolss_EnumPrinters e;
4881 uint32_t count;
4882 union spoolss_PrinterInfo *info;
4884 e.in.flags = PRINTER_ENUM_LOCAL;
4885 e.in.server = NULL;
4886 e.in.level = 2;
4887 e.in.buffer = NULL;
4888 e.in.offered = 0;
4889 e.out.count = &count;
4890 e.out.info = &info;
4891 e.out.needed = &needed[i];
4893 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_EnumPrinters(p, tctx, &e), "");
4894 #if 0
4895 torture_comment(tctx, "needed was %d\n", needed[i]);
4896 #endif
4899 torture_assert(tctx, test_ClosePrinter(tctx, p, &handle), "");
4902 for (i=1; i < ARRAY_SIZE(architectures); i++) {
4903 if (needed[i-1] != needed[i]) {
4904 torture_fail(tctx,
4905 talloc_asprintf(tctx, "needed size %d for architecture %d != needed size %d for architecture %d\n",
4906 needed[i-1], architectures[i-1], needed[i], architectures[i]));
4910 return true;
4913 bool torture_rpc_spoolss(struct torture_context *torture)
4915 NTSTATUS status;
4916 struct dcerpc_pipe *p;
4917 bool ret = true;
4918 struct test_spoolss_context *ctx;
4919 const char *environment = SPOOLSS_ARCHITECTURE_NT_X86;
4921 status = torture_rpc_connection(torture, &p, &ndr_table_spoolss);
4922 if (!NT_STATUS_IS_OK(status)) {
4923 return false;
4926 ctx = talloc_zero(torture, struct test_spoolss_context);
4928 ret &= test_OpenPrinter_server(torture, p, &ctx->server_handle);
4929 ret &= test_GetPrinterData_list(torture, p, &ctx->server_handle);
4930 ret &= test_EnumForms(torture, p, &ctx->server_handle, true);
4931 ret &= test_AddForm(torture, p, &ctx->server_handle, true);
4932 ret &= test_EnumPorts(torture, p, ctx);
4933 ret &= test_GetPrinterDriverDirectory(torture, p, ctx, environment);
4934 ret &= test_GetPrintProcessorDirectory(torture, p, ctx, environment);
4935 ret &= test_EnumPrinterDrivers(torture, p, ctx, environment);
4936 ret &= test_EnumPrinterDrivers(torture, p, ctx, SPOOLSS_ARCHITECTURE_ALL);
4937 ret &= test_EnumMonitors(torture, p, ctx);
4938 ret &= test_EnumPrintProcessors(torture, p, ctx, environment);
4939 ret &= test_EnumPrintProcDataTypes(torture, p, ctx);
4940 ret &= test_EnumPrinters(torture, p, ctx);
4941 ret &= test_OpenPrinter_badname(torture, p, "__INVALID_PRINTER__");
4942 ret &= test_OpenPrinter_badname(torture, p, "\\\\__INVALID_HOST__");
4943 ret &= test_OpenPrinter_badname(torture, p, "");
4944 ret &= test_OpenPrinter_badname(torture, p, "\\\\\\");
4945 ret &= test_OpenPrinter_badname(torture, p, "\\\\\\__INVALID_PRINTER__");
4946 ret &= test_OpenPrinter_badname(torture, p, talloc_asprintf(torture, "\\\\%s\\", dcerpc_server_name(p)));
4947 ret &= test_OpenPrinter_badname(torture, p,
4948 talloc_asprintf(torture, "\\\\%s\\__INVALID_PRINTER__", dcerpc_server_name(p)));
4951 ret &= test_AddPort(torture, p);
4952 ret &= test_EnumPorts_old(torture, p);
4953 ret &= test_EnumPrinters_old(torture, p, environment);
4954 ret &= test_EnumPrinterDrivers_old(torture, p, environment);
4955 ret &= test_architecture_buffer(torture, p);
4957 return ret;
4960 struct torture_suite *torture_rpc_spoolss_printer(TALLOC_CTX *mem_ctx)
4962 struct torture_suite *suite = torture_suite_create(mem_ctx, "SPOOLSS-PRINTER");
4964 struct torture_rpc_tcase *tcase = torture_suite_add_rpc_iface_tcase(suite,
4965 "printer", &ndr_table_spoolss);
4967 torture_rpc_tcase_add_test(tcase, "printer", test_printer);
4969 return suite;