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/>.
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_security.h"
30 #include "libcli/security/security.h"
31 #include "torture/rpc/rpc.h"
32 #include "param/param.h"
34 #define TORTURE_WELLKNOWN_PRINTER "torture_wkn_printer"
35 #define TORTURE_PRINTER "torture_printer"
36 #define TORTURE_WELLKNOWN_PRINTER_EX "torture_wkn_printer_ex"
37 #define TORTURE_PRINTER_EX "torture_printer_ex"
39 struct test_spoolss_context
{
40 /* print server handle */
41 struct policy_handle server_handle
;
44 uint32_t port_count
[3];
45 union spoolss_PortInfo
*ports
[3];
47 /* for EnumPrinterDrivers */
48 uint32_t driver_count
[8];
49 union spoolss_DriverInfo
*drivers
[8];
51 /* for EnumMonitors */
52 uint32_t monitor_count
[3];
53 union spoolss_MonitorInfo
*monitors
[3];
55 /* for EnumPrintProcessors */
56 uint32_t print_processor_count
[2];
57 union spoolss_PrintProcessorInfo
*print_processors
[2];
59 /* for EnumPrinters */
60 uint32_t printer_count
[6];
61 union spoolss_PrinterInfo
*printers
[6];
64 #define COMPARE_STRING(tctx, c,r,e) \
65 torture_assert_str_equal(tctx, c.e, r.e, "invalid value")
67 /* not every compiler supports __typeof__() */
69 #define _CHECK_FIELD_SIZE(c,r,e,type) do {\
70 if (sizeof(__typeof__(c.e)) != sizeof(type)) { \
71 torture_fail(tctx, #c "." #e "field is not " #type "\n"); \
73 if (sizeof(__typeof__(r.e)) != sizeof(type)) { \
74 torture_fail(tctx, #r "." #e "field is not " #type "\n"); \
78 #define _CHECK_FIELD_SIZE(c,r,e,type) do {} while(0)
81 #define COMPARE_UINT32(tctx, c, r, e) do {\
82 _CHECK_FIELD_SIZE(c, r, e, uint32_t); \
83 torture_assert_int_equal(tctx, c.e, r.e, "invalid value"); \
86 #define COMPARE_UINT64(tctx, c, r, e) do {\
87 _CHECK_FIELD_SIZE(c, r, e, uint64_t); \
88 torture_assert_int_equal(tctx, c.e, r.e, "invalid value"); \
92 #define COMPARE_NTTIME(tctx, c, r, e) do {\
93 _CHECK_FIELD_SIZE(c, r, e, NTTIME); \
94 torture_assert_int_equal(tctx, c.e, r.e, "invalid value"); \
97 #define COMPARE_STRING_ARRAY(tctx, c,r,e) do {\
103 torture_fail(tctx, #r "." #e " field is NULL and " #c "." #e " is not\n"); \
106 torture_fail(tctx, #c "." #e " field is NULL and " #r "." #e " is not\n"); \
108 for (__i=0;c.e[__i] != NULL; __i++) { \
109 torture_assert_str_equal(tctx, c.e[__i], r.e[__i], "invalid value"); \
113 #define CHECK_ALIGN(size, n) do {\
115 torture_warning(tctx, "%d is *NOT* %d byte aligned, should be %d",\
116 size, n, size + n - (size % n));\
120 #define DO_ROUND(size, n) (((size)+((n)-1)) & ~((n)-1))
122 #define CHECK_NEEDED_SIZE_ENUM_LEVEL(fn, info, level, count, ic, needed, align) do { \
123 if (torture_setting_bool(tctx, "spoolss_check_size", false)) {\
124 uint32_t size = ndr_size_##fn##_info(tctx, ic, level, count, info);\
125 uint32_t round_size = DO_ROUND(size, align);\
126 if (round_size != needed) {\
127 torture_warning(tctx, __location__": "#fn" level %d (count: %d) got unexpected needed size: %d, we calculated: %d", level, count, needed, round_size);\
128 CHECK_ALIGN(size, align);\
133 #define CHECK_NEEDED_SIZE_ENUM(fn, info, count, ic, needed, align) do { \
134 if (torture_setting_bool(tctx, "spoolss_check_size", false)) {\
135 uint32_t size = ndr_size_##fn##_info(tctx, ic, count, info);\
136 uint32_t round_size = DO_ROUND(size, align);\
137 if (round_size != needed) {\
138 torture_warning(tctx, __location__": "#fn" (count: %d) got unexpected needed size: %d, we calculated: %d", count, needed, round_size);\
139 CHECK_ALIGN(size, align);\
144 #define CHECK_NEEDED_SIZE_LEVEL(fn, info, level, ic, needed, align) do { \
145 if (torture_setting_bool(tctx, "spoolss_check_size", false)) {\
146 uint32_t size = ndr_size_##fn(info, level, ic, 0);\
147 uint32_t round_size = DO_ROUND(size, align);\
148 if (round_size != needed) {\
149 torture_warning(tctx, __location__": "#fn" level %d got unexpected needed size: %d, we calculated: %d", level, needed, round_size);\
150 CHECK_ALIGN(size, align);\
155 static bool test_OpenPrinter_server(struct torture_context
*tctx
,
156 struct dcerpc_pipe
*p
,
157 struct policy_handle
*server_handle
)
160 struct spoolss_OpenPrinter op
;
162 op
.in
.printername
= talloc_asprintf(tctx
, "\\\\%s", dcerpc_server_name(p
));
163 op
.in
.datatype
= NULL
;
164 op
.in
.devmode_ctr
.devmode
= NULL
;
165 op
.in
.access_mask
= 0;
166 op
.out
.handle
= server_handle
;
168 torture_comment(tctx
, "Testing OpenPrinter(%s)\n", op
.in
.printername
);
170 status
= dcerpc_spoolss_OpenPrinter(p
, tctx
, &op
);
171 torture_assert_ntstatus_ok(tctx
, status
, "dcerpc_spoolss_OpenPrinter failed");
172 torture_assert_werr_ok(tctx
, op
.out
.result
, "dcerpc_spoolss_OpenPrinter failed");
177 static bool test_EnumPorts(struct torture_context
*tctx
,
178 struct dcerpc_pipe
*p
,
179 struct test_spoolss_context
*ctx
)
182 struct spoolss_EnumPorts r
;
183 uint16_t levels
[] = { 1, 2 };
186 for (i
=0;i
<ARRAY_SIZE(levels
);i
++) {
187 int level
= levels
[i
];
191 union spoolss_PortInfo
*info
;
193 r
.in
.servername
= "";
197 r
.out
.needed
= &needed
;
198 r
.out
.count
= &count
;
201 torture_comment(tctx
, "Testing EnumPorts level %u\n", r
.in
.level
);
203 status
= dcerpc_spoolss_EnumPorts(p
, ctx
, &r
);
204 torture_assert_ntstatus_ok(tctx
, status
, "dcerpc_spoolss_EnumPorts failed");
205 if (W_ERROR_IS_OK(r
.out
.result
)) {
206 /* TODO: do some more checks here */
209 torture_assert_werr_equal(tctx
, r
.out
.result
, WERR_INSUFFICIENT_BUFFER
,
210 "EnumPorts unexpected return code");
212 blob
= data_blob_talloc(ctx
, NULL
, needed
);
213 data_blob_clear(&blob
);
215 r
.in
.offered
= needed
;
217 status
= dcerpc_spoolss_EnumPorts(p
, ctx
, &r
);
218 torture_assert_ntstatus_ok(tctx
, status
, "dcerpc_spoolss_EnumPorts failed");
220 torture_assert_werr_ok(tctx
, r
.out
.result
, "EnumPorts failed");
222 torture_assert(tctx
, info
, "EnumPorts returned no info");
224 CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumPorts
, info
, r
.in
.level
, count
, lp_iconv_convenience(tctx
->lp_ctx
), needed
, 4);
226 ctx
->port_count
[level
] = count
;
227 ctx
->ports
[level
] = info
;
230 for (i
=1;i
<ARRAY_SIZE(levels
);i
++) {
231 int level
= levels
[i
];
232 int old_level
= levels
[i
-1];
233 torture_assert_int_equal(tctx
, ctx
->port_count
[level
], ctx
->port_count
[old_level
],
234 "EnumPorts invalid value");
236 /* if the array sizes are not the same we would maybe segfault in the following code */
238 for (i
=0;i
<ARRAY_SIZE(levels
);i
++) {
239 int level
= levels
[i
];
240 for (j
=0;j
<ctx
->port_count
[level
];j
++) {
241 union spoolss_PortInfo
*cur
= &ctx
->ports
[level
][j
];
242 union spoolss_PortInfo
*ref
= &ctx
->ports
[2][j
];
245 COMPARE_STRING(tctx
, cur
->info1
, ref
->info2
, port_name
);
248 /* level 2 is our reference, and it makes no sense to compare it to itself */
257 static bool test_GetPrintProcessorDirectory(struct torture_context
*tctx
,
258 struct dcerpc_pipe
*p
,
259 struct test_spoolss_context
*ctx
,
260 const char *environment
)
263 struct spoolss_GetPrintProcessorDirectory r
;
278 .server
= talloc_asprintf(ctx
, "\\\\%s", dcerpc_server_name(p
))
281 .server
= talloc_asprintf(ctx
, "\\\\%s", dcerpc_server_name(p
))
287 for (i
=0;i
<ARRAY_SIZE(levels
);i
++) {
288 int level
= levels
[i
].level
;
291 r
.in
.server
= levels
[i
].server
;
292 r
.in
.environment
= environment
;
296 r
.out
.needed
= &needed
;
298 torture_comment(tctx
, "Testing GetPrintProcessorDirectory level %u\n", r
.in
.level
);
300 status
= dcerpc_spoolss_GetPrintProcessorDirectory(p
, ctx
, &r
);
301 torture_assert_ntstatus_ok(tctx
, status
,
302 "dcerpc_spoolss_GetPrintProcessorDirectory failed");
303 torture_assert_werr_equal(tctx
, r
.out
.result
, WERR_INSUFFICIENT_BUFFER
,
304 "GetPrintProcessorDirectory unexpected return code");
306 blob
= data_blob_talloc(ctx
, NULL
, needed
);
307 data_blob_clear(&blob
);
309 r
.in
.offered
= needed
;
311 status
= dcerpc_spoolss_GetPrintProcessorDirectory(p
, ctx
, &r
);
312 torture_assert_ntstatus_ok(tctx
, status
, "dcerpc_spoolss_GetPrintProcessorDirectory failed");
314 torture_assert_werr_ok(tctx
, r
.out
.result
, "GetPrintProcessorDirectory failed");
316 CHECK_NEEDED_SIZE_LEVEL(spoolss_PrintProcessorDirectoryInfo
, r
.out
.info
, r
.in
.level
, lp_iconv_convenience(tctx
->lp_ctx
), needed
, 2);
323 static bool test_GetPrinterDriverDirectory(struct torture_context
*tctx
,
324 struct dcerpc_pipe
*p
,
325 struct test_spoolss_context
*ctx
,
326 const char *environment
)
329 struct spoolss_GetPrinterDriverDirectory r
;
344 .server
= talloc_asprintf(ctx
, "\\\\%s", dcerpc_server_name(p
))
347 .server
= talloc_asprintf(ctx
, "\\\\%s", dcerpc_server_name(p
))
353 for (i
=0;i
<ARRAY_SIZE(levels
);i
++) {
354 int level
= levels
[i
].level
;
357 r
.in
.server
= levels
[i
].server
;
358 r
.in
.environment
= environment
;
362 r
.out
.needed
= &needed
;
364 torture_comment(tctx
, "Testing GetPrinterDriverDirectory level %u\n", r
.in
.level
);
366 status
= dcerpc_spoolss_GetPrinterDriverDirectory(p
, ctx
, &r
);
367 torture_assert_ntstatus_ok(tctx
, status
,
368 "dcerpc_spoolss_GetPrinterDriverDirectory failed");
369 torture_assert_werr_equal(tctx
, r
.out
.result
, WERR_INSUFFICIENT_BUFFER
,
370 "GetPrinterDriverDirectory unexpected return code");
372 blob
= data_blob_talloc(ctx
, NULL
, needed
);
373 data_blob_clear(&blob
);
375 r
.in
.offered
= needed
;
377 status
= dcerpc_spoolss_GetPrinterDriverDirectory(p
, ctx
, &r
);
378 torture_assert_ntstatus_ok(tctx
, status
, "dcerpc_spoolss_GetPrinterDriverDirectory failed");
380 torture_assert_werr_ok(tctx
, r
.out
.result
, "GetPrinterDriverDirectory failed");
382 CHECK_NEEDED_SIZE_LEVEL(spoolss_DriverDirectoryInfo
, r
.out
.info
, r
.in
.level
, lp_iconv_convenience(tctx
->lp_ctx
), needed
, 2);
388 static bool test_EnumPrinterDrivers(struct torture_context
*tctx
,
389 struct dcerpc_pipe
*p
,
390 struct test_spoolss_context
*ctx
,
391 const char *architecture
)
394 struct spoolss_EnumPrinterDrivers r
;
395 uint16_t levels
[] = { 1, 2, 3, 4, 5, 6, 8 };
398 for (i
=0;i
<ARRAY_SIZE(levels
);i
++) {
399 int level
= levels
[i
];
403 union spoolss_DriverInfo
*info
;
405 /* FIXME: gd, come back and fix "" as server, and handle
406 * priority of returned error codes in torture test and samba 3
409 r
.in
.server
= talloc_asprintf(tctx
, "\\\\%s", dcerpc_server_name(p
));
410 r
.in
.environment
= architecture
;
414 r
.out
.needed
= &needed
;
415 r
.out
.count
= &count
;
418 torture_comment(tctx
, "Testing EnumPrinterDrivers level %u (%s)\n", r
.in
.level
, r
.in
.environment
);
420 status
= dcerpc_spoolss_EnumPrinterDrivers(p
, ctx
, &r
);
421 torture_assert_ntstatus_ok(tctx
, status
,
422 "dcerpc_spoolss_EnumPrinterDrivers failed");
423 if (W_ERROR_IS_OK(r
.out
.result
)) {
424 /* TODO: do some more checks here */
427 if (W_ERROR_EQUAL(r
.out
.result
, WERR_INSUFFICIENT_BUFFER
)) {
428 blob
= data_blob_talloc(ctx
, NULL
, needed
);
429 data_blob_clear(&blob
);
431 r
.in
.offered
= needed
;
433 status
= dcerpc_spoolss_EnumPrinterDrivers(p
, ctx
, &r
);
434 torture_assert_ntstatus_ok(tctx
, status
, "dcerpc_spoolss_EnumPrinterDrivers failed");
437 torture_assert_werr_ok(tctx
, r
.out
.result
, "EnumPrinterDrivers failed");
439 CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumPrinterDrivers
, info
, r
.in
.level
, count
, lp_iconv_convenience(tctx
->lp_ctx
), needed
, 4);
441 ctx
->driver_count
[level
] = count
;
442 ctx
->drivers
[level
] = info
;
445 for (i
=1;i
<ARRAY_SIZE(levels
);i
++) {
446 int level
= levels
[i
];
447 int old_level
= levels
[i
-1];
449 torture_assert_int_equal(tctx
, ctx
->driver_count
[level
], ctx
->driver_count
[old_level
],
450 "EnumPrinterDrivers invalid value");
453 for (i
=0;i
<ARRAY_SIZE(levels
);i
++) {
454 int level
= levels
[i
];
456 for (j
=0;j
<ctx
->driver_count
[level
];j
++) {
457 union spoolss_DriverInfo
*cur
= &ctx
->drivers
[level
][j
];
458 union spoolss_DriverInfo
*ref
= &ctx
->drivers
[8][j
];
462 COMPARE_STRING(tctx
, cur
->info1
, ref
->info8
, driver_name
);
465 COMPARE_UINT32(tctx
, cur
->info2
, ref
->info8
, version
);
466 COMPARE_STRING(tctx
, cur
->info2
, ref
->info8
, driver_name
);
467 COMPARE_STRING(tctx
, cur
->info2
, ref
->info8
, architecture
);
468 COMPARE_STRING(tctx
, cur
->info2
, ref
->info8
, driver_path
);
469 COMPARE_STRING(tctx
, cur
->info2
, ref
->info8
, data_file
);
470 COMPARE_STRING(tctx
, cur
->info2
, ref
->info8
, config_file
);
473 COMPARE_UINT32(tctx
, cur
->info3
, ref
->info8
, version
);
474 COMPARE_STRING(tctx
, cur
->info3
, ref
->info8
, driver_name
);
475 COMPARE_STRING(tctx
, cur
->info3
, ref
->info8
, architecture
);
476 COMPARE_STRING(tctx
, cur
->info3
, ref
->info8
, driver_path
);
477 COMPARE_STRING(tctx
, cur
->info3
, ref
->info8
, data_file
);
478 COMPARE_STRING(tctx
, cur
->info3
, ref
->info8
, config_file
);
479 COMPARE_STRING(tctx
, cur
->info3
, ref
->info8
, help_file
);
480 COMPARE_STRING_ARRAY(tctx
, cur
->info3
, ref
->info8
, dependent_files
);
481 COMPARE_STRING(tctx
, cur
->info3
, ref
->info8
, monitor_name
);
482 COMPARE_STRING(tctx
, cur
->info3
, ref
->info8
, default_datatype
);
485 COMPARE_UINT32(tctx
, cur
->info4
, ref
->info8
, version
);
486 COMPARE_STRING(tctx
, cur
->info4
, ref
->info8
, driver_name
);
487 COMPARE_STRING(tctx
, cur
->info4
, ref
->info8
, architecture
);
488 COMPARE_STRING(tctx
, cur
->info4
, ref
->info8
, driver_path
);
489 COMPARE_STRING(tctx
, cur
->info4
, ref
->info8
, data_file
);
490 COMPARE_STRING(tctx
, cur
->info4
, ref
->info8
, config_file
);
491 COMPARE_STRING(tctx
, cur
->info4
, ref
->info8
, help_file
);
492 COMPARE_STRING_ARRAY(tctx
, cur
->info4
, ref
->info8
, dependent_files
);
493 COMPARE_STRING(tctx
, cur
->info4
, ref
->info8
, monitor_name
);
494 COMPARE_STRING(tctx
, cur
->info4
, ref
->info8
, default_datatype
);
495 COMPARE_STRING_ARRAY(tctx
, cur
->info4
, ref
->info8
, previous_names
);
498 COMPARE_UINT32(tctx
, cur
->info5
, ref
->info8
, version
);
499 COMPARE_STRING(tctx
, cur
->info5
, ref
->info8
, driver_name
);
500 COMPARE_STRING(tctx
, cur
->info5
, ref
->info8
, architecture
);
501 COMPARE_STRING(tctx
, cur
->info5
, ref
->info8
, driver_path
);
502 COMPARE_STRING(tctx
, cur
->info5
, ref
->info8
, data_file
);
503 COMPARE_STRING(tctx
, cur
->info5
, ref
->info8
, config_file
);
504 /*COMPARE_UINT32(tctx, cur->info5, ref->info8, driver_attributes);*/
505 /*COMPARE_UINT32(tctx, cur->info5, ref->info8, config_version);*/
506 /*TODO: ! COMPARE_UINT32(tctx, cur->info5, ref->info8, driver_version); */
509 COMPARE_UINT32(tctx
, cur
->info6
, ref
->info8
, version
);
510 COMPARE_STRING(tctx
, cur
->info6
, ref
->info8
, driver_name
);
511 COMPARE_STRING(tctx
, cur
->info6
, ref
->info8
, architecture
);
512 COMPARE_STRING(tctx
, cur
->info6
, ref
->info8
, driver_path
);
513 COMPARE_STRING(tctx
, cur
->info6
, ref
->info8
, data_file
);
514 COMPARE_STRING(tctx
, cur
->info6
, ref
->info8
, config_file
);
515 COMPARE_STRING(tctx
, cur
->info6
, ref
->info8
, help_file
);
516 COMPARE_STRING_ARRAY(tctx
, cur
->info6
, ref
->info8
, dependent_files
);
517 COMPARE_STRING(tctx
, cur
->info6
, ref
->info8
, monitor_name
);
518 COMPARE_STRING(tctx
, cur
->info6
, ref
->info8
, default_datatype
);
519 COMPARE_STRING_ARRAY(tctx
, cur
->info6
, ref
->info8
, previous_names
);
520 COMPARE_NTTIME(tctx
, cur
->info6
, ref
->info8
, driver_date
);
521 COMPARE_UINT64(tctx
, cur
->info6
, ref
->info8
, driver_version
);
522 COMPARE_STRING(tctx
, cur
->info6
, ref
->info8
, manufacturer_name
);
523 COMPARE_STRING(tctx
, cur
->info6
, ref
->info8
, manufacturer_url
);
524 COMPARE_STRING(tctx
, cur
->info6
, ref
->info8
, hardware_id
);
525 COMPARE_STRING(tctx
, cur
->info6
, ref
->info8
, provider
);
528 /* level 8 is our reference, and it makes no sense to compare it to itself */
537 static bool test_EnumMonitors(struct torture_context
*tctx
,
538 struct dcerpc_pipe
*p
,
539 struct test_spoolss_context
*ctx
)
542 struct spoolss_EnumMonitors r
;
543 uint16_t levels
[] = { 1, 2 };
546 for (i
=0;i
<ARRAY_SIZE(levels
);i
++) {
547 int level
= levels
[i
];
551 union spoolss_MonitorInfo
*info
;
553 r
.in
.servername
= "";
557 r
.out
.needed
= &needed
;
558 r
.out
.count
= &count
;
561 torture_comment(tctx
, "Testing EnumMonitors level %u\n", r
.in
.level
);
563 status
= dcerpc_spoolss_EnumMonitors(p
, ctx
, &r
);
564 torture_assert_ntstatus_ok(tctx
, status
, "dcerpc_spoolss_EnumMonitors failed");
565 if (W_ERROR_IS_OK(r
.out
.result
)) {
566 /* TODO: do some more checks here */
569 torture_assert_werr_equal(tctx
, r
.out
.result
, WERR_INSUFFICIENT_BUFFER
,
570 "EnumMonitors failed");
572 blob
= data_blob_talloc(ctx
, NULL
, needed
);
573 data_blob_clear(&blob
);
575 r
.in
.offered
= needed
;
577 status
= dcerpc_spoolss_EnumMonitors(p
, ctx
, &r
);
578 torture_assert_ntstatus_ok(tctx
, status
, "dcerpc_spoolss_EnumMonitors failed");
580 torture_assert_werr_ok(tctx
, r
.out
.result
, "EnumMonitors failed");
582 CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumMonitors
, info
, r
.in
.level
, count
, lp_iconv_convenience(tctx
->lp_ctx
), needed
, 4);
584 ctx
->monitor_count
[level
] = count
;
585 ctx
->monitors
[level
] = info
;
588 for (i
=1;i
<ARRAY_SIZE(levels
);i
++) {
589 int level
= levels
[i
];
590 int old_level
= levels
[i
-1];
591 torture_assert_int_equal(tctx
, ctx
->monitor_count
[level
], ctx
->monitor_count
[old_level
],
592 "EnumMonitors invalid value");
595 for (i
=0;i
<ARRAY_SIZE(levels
);i
++) {
596 int level
= levels
[i
];
597 for (j
=0;j
<ctx
->monitor_count
[level
];j
++) {
598 union spoolss_MonitorInfo
*cur
= &ctx
->monitors
[level
][j
];
599 union spoolss_MonitorInfo
*ref
= &ctx
->monitors
[2][j
];
602 COMPARE_STRING(tctx
, cur
->info1
, ref
->info2
, monitor_name
);
605 /* level 2 is our reference, and it makes no sense to compare it to itself */
614 static bool test_EnumPrintProcessors(struct torture_context
*tctx
,
615 struct dcerpc_pipe
*p
,
616 struct test_spoolss_context
*ctx
,
617 const char *environment
)
620 struct spoolss_EnumPrintProcessors r
;
621 uint16_t levels
[] = { 1 };
624 for (i
=0;i
<ARRAY_SIZE(levels
);i
++) {
625 int level
= levels
[i
];
629 union spoolss_PrintProcessorInfo
*info
;
631 r
.in
.servername
= "";
632 r
.in
.environment
= environment
;
636 r
.out
.needed
= &needed
;
637 r
.out
.count
= &count
;
640 torture_comment(tctx
, "Testing EnumPrintProcessors level %u\n", r
.in
.level
);
642 status
= dcerpc_spoolss_EnumPrintProcessors(p
, ctx
, &r
);
643 torture_assert_ntstatus_ok(tctx
, status
, "dcerpc_spoolss_EnumPrintProcessors failed");
644 if (W_ERROR_IS_OK(r
.out
.result
)) {
645 /* TODO: do some more checks here */
648 torture_assert_werr_equal(tctx
, r
.out
.result
, WERR_INSUFFICIENT_BUFFER
,
649 "EnumPrintProcessors unexpected return code");
651 blob
= data_blob_talloc(ctx
, NULL
, needed
);
652 data_blob_clear(&blob
);
654 r
.in
.offered
= needed
;
656 status
= dcerpc_spoolss_EnumPrintProcessors(p
, ctx
, &r
);
657 torture_assert_ntstatus_ok(tctx
, status
, "dcerpc_spoolss_EnumPrintProcessors failed");
659 torture_assert_werr_ok(tctx
, r
.out
.result
, "EnumPrintProcessors failed");
661 CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumPrintProcessors
, info
, r
.in
.level
, count
, lp_iconv_convenience(tctx
->lp_ctx
), needed
, 4);
663 ctx
->print_processor_count
[level
] = count
;
664 ctx
->print_processors
[level
] = info
;
667 for (i
=1;i
<ARRAY_SIZE(levels
);i
++) {
668 int level
= levels
[i
];
669 int old_level
= levels
[i
-1];
670 torture_assert_int_equal(tctx
, ctx
->print_processor_count
[level
], ctx
->print_processor_count
[old_level
],
671 "EnumPrintProcessors failed");
674 for (i
=0;i
<ARRAY_SIZE(levels
);i
++) {
675 int level
= levels
[i
];
676 for (j
=0;j
<ctx
->print_processor_count
[level
];j
++) {
678 union spoolss_PrintProcessorInfo
*cur
= &ctx
->print_processors
[level
][j
];
679 union spoolss_PrintProcessorInfo
*ref
= &ctx
->print_processors
[1][j
];
683 /* level 1 is our reference, and it makes no sense to compare it to itself */
692 static bool test_EnumPrintProcDataTypes(struct torture_context
*tctx
,
693 struct dcerpc_pipe
*p
,
694 struct test_spoolss_context
*ctx
)
697 struct spoolss_EnumPrintProcDataTypes r
;
698 uint16_t levels
[] = { 1 };
701 for (i
=0;i
<ARRAY_SIZE(levels
);i
++) {
702 int level
= levels
[i
];
706 union spoolss_PrintProcDataTypesInfo
*info
;
708 r
.in
.servername
= "";
709 r
.in
.print_processor_name
= "winprint";
713 r
.out
.needed
= &needed
;
714 r
.out
.count
= &count
;
717 torture_comment(tctx
, "Testing EnumPrintProcDataTypes level %u\n", r
.in
.level
);
719 status
= dcerpc_spoolss_EnumPrintProcDataTypes(p
, ctx
, &r
);
720 torture_assert_ntstatus_ok(tctx
, status
, "dcerpc_spoolss_EnumPrintProcDataType failed");
721 if (W_ERROR_IS_OK(r
.out
.result
)) {
722 /* TODO: do some more checks here */
725 torture_assert_werr_equal(tctx
, r
.out
.result
, WERR_INSUFFICIENT_BUFFER
,
726 "EnumPrintProcDataTypes unexpected return code");
728 blob
= data_blob_talloc(ctx
, NULL
, needed
);
729 data_blob_clear(&blob
);
731 r
.in
.offered
= needed
;
733 status
= dcerpc_spoolss_EnumPrintProcDataTypes(p
, ctx
, &r
);
734 torture_assert_ntstatus_ok(tctx
, status
, "dcerpc_spoolss_EnumPrintProcDataTypes failed");
736 torture_assert_werr_ok(tctx
, r
.out
.result
, "EnumPrintProcDataTypes failed");
738 CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumPrintProcDataTypes
, info
, r
.in
.level
, count
, lp_iconv_convenience(tctx
->lp_ctx
), needed
, 4);
746 static bool test_EnumPrinters(struct torture_context
*tctx
,
747 struct dcerpc_pipe
*p
,
748 struct test_spoolss_context
*ctx
)
750 struct spoolss_EnumPrinters r
;
752 uint16_t levels
[] = { 0, 1, 2, 4, 5 };
755 for (i
=0;i
<ARRAY_SIZE(levels
);i
++) {
756 int level
= levels
[i
];
760 union spoolss_PrinterInfo
*info
;
762 r
.in
.flags
= PRINTER_ENUM_LOCAL
;
767 r
.out
.needed
= &needed
;
768 r
.out
.count
= &count
;
771 torture_comment(tctx
, "Testing EnumPrinters level %u\n", r
.in
.level
);
773 status
= dcerpc_spoolss_EnumPrinters(p
, ctx
, &r
);
774 torture_assert_ntstatus_ok(tctx
, status
, "dcerpc_spoolss_EnumPrinters failed");
775 if (W_ERROR_IS_OK(r
.out
.result
)) {
776 /* TODO: do some more checks here */
779 torture_assert_werr_equal(tctx
, r
.out
.result
, WERR_INSUFFICIENT_BUFFER
,
780 "EnumPrinters unexpected return code");
782 blob
= data_blob_talloc(ctx
, NULL
, needed
);
783 data_blob_clear(&blob
);
785 r
.in
.offered
= needed
;
787 status
= dcerpc_spoolss_EnumPrinters(p
, ctx
, &r
);
788 torture_assert_ntstatus_ok(tctx
, status
, "dcerpc_spoolss_EnumPrinters failed");
790 torture_assert_werr_ok(tctx
, r
.out
.result
, "EnumPrinters failed");
792 CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumPrinters
, info
, r
.in
.level
, count
, lp_iconv_convenience(tctx
->lp_ctx
), needed
, 4);
794 ctx
->printer_count
[level
] = count
;
795 ctx
->printers
[level
] = info
;
798 for (i
=1;i
<ARRAY_SIZE(levels
);i
++) {
799 int level
= levels
[i
];
800 int old_level
= levels
[i
-1];
801 torture_assert_int_equal(tctx
, ctx
->printer_count
[level
], ctx
->printer_count
[old_level
],
802 "EnumPrinters invalid value");
805 for (i
=0;i
<ARRAY_SIZE(levels
);i
++) {
806 int level
= levels
[i
];
807 for (j
=0;j
<ctx
->printer_count
[level
];j
++) {
808 union spoolss_PrinterInfo
*cur
= &ctx
->printers
[level
][j
];
809 union spoolss_PrinterInfo
*ref
= &ctx
->printers
[2][j
];
812 COMPARE_STRING(tctx
, cur
->info0
, ref
->info2
, printername
);
813 COMPARE_STRING(tctx
, cur
->info0
, ref
->info2
, servername
);
814 COMPARE_UINT32(tctx
, cur
->info0
, ref
->info2
, cjobs
);
815 /*COMPARE_UINT32(tctx, cur->info0, ref->info2, total_jobs);
816 COMPARE_UINT32(tctx, cur->info0, ref->info2, total_bytes);
817 COMPARE_SPOOLSS_TIME(cur->info0, ref->info2, spoolss_Time time);
818 COMPARE_UINT32(tctx, cur->info0, ref->info2, global_counter);
819 COMPARE_UINT32(tctx, cur->info0, ref->info2, total_pages);
820 COMPARE_UINT32(tctx, cur->info0, ref->info2, version);
821 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown10);
822 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown11);
823 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown12);
824 COMPARE_UINT32(tctx, cur->info0, ref->info2, session_counter);
825 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown14);
826 COMPARE_UINT32(tctx, cur->info0, ref->info2, printer_errors);
827 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown16);
828 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown17);
829 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown18);
830 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown19);
831 COMPARE_UINT32(tctx, cur->info0, ref->info2, change_id);
832 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown21);*/
833 COMPARE_UINT32(tctx
, cur
->info0
, ref
->info2
, status
);
834 /*COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown23);
835 COMPARE_UINT32(tctx, cur->info0, ref->info2, c_setprinter);
836 COMPARE_UINT16(cur->info0, ref->info2, unknown25);
837 COMPARE_UINT16(cur->info0, ref->info2, unknown26);
838 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown27);
839 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown28);
840 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown29);*/
843 /*COMPARE_UINT32(tctx, cur->info1, ref->info2, flags);*/
844 /*COMPARE_STRING(tctx, cur->info1, ref->info2, name);*/
845 /*COMPARE_STRING(tctx, cur->info1, ref->info2, description);*/
846 COMPARE_STRING(tctx
, cur
->info1
, ref
->info2
, comment
);
849 /* level 2 is our reference, and it makes no sense to compare it to itself */
852 COMPARE_STRING(tctx
, cur
->info4
, ref
->info2
, printername
);
853 COMPARE_STRING(tctx
, cur
->info4
, ref
->info2
, servername
);
854 COMPARE_UINT32(tctx
, cur
->info4
, ref
->info2
, attributes
);
857 COMPARE_STRING(tctx
, cur
->info5
, ref
->info2
, printername
);
858 COMPARE_STRING(tctx
, cur
->info5
, ref
->info2
, portname
);
859 COMPARE_UINT32(tctx
, cur
->info5
, ref
->info2
, attributes
);
860 /*COMPARE_UINT32(tctx, cur->info5, ref->info2, device_not_selected_timeout);
861 COMPARE_UINT32(tctx, cur->info5, ref->info2, transmission_retry_timeout);*/
868 * - verify that the port of a printer was in the list returned by EnumPorts
874 static bool test_GetPrinterDriver2(struct torture_context
*tctx
,
875 struct dcerpc_pipe
*p
,
876 struct policy_handle
*handle
,
877 const char *driver_name
,
878 const char *environment
);
880 bool test_GetPrinter_level(struct torture_context
*tctx
,
881 struct dcerpc_pipe
*p
,
882 struct policy_handle
*handle
,
884 union spoolss_PrinterInfo
*info
)
886 struct spoolss_GetPrinter r
;
889 r
.in
.handle
= handle
;
893 r
.out
.needed
= &needed
;
895 torture_comment(tctx
, "Testing GetPrinter level %u\n", r
.in
.level
);
897 torture_assert_ntstatus_ok(tctx
, dcerpc_spoolss_GetPrinter(p
, tctx
, &r
),
898 "GetPrinter failed");
900 if (W_ERROR_EQUAL(r
.out
.result
, WERR_INSUFFICIENT_BUFFER
)) {
901 DATA_BLOB blob
= data_blob_talloc(tctx
, NULL
, needed
);
902 data_blob_clear(&blob
);
904 r
.in
.offered
= needed
;
906 torture_assert_ntstatus_ok(tctx
, dcerpc_spoolss_GetPrinter(p
, tctx
, &r
),
907 "GetPrinter failed");
910 torture_assert_werr_ok(tctx
, r
.out
.result
, "GetPrinter failed");
912 CHECK_NEEDED_SIZE_LEVEL(spoolss_PrinterInfo
, r
.out
.info
, r
.in
.level
, lp_iconv_convenience(tctx
->lp_ctx
), needed
, 4);
914 if (info
&& r
.out
.info
) {
922 static bool test_GetPrinter(struct torture_context
*tctx
,
923 struct dcerpc_pipe
*p
,
924 struct policy_handle
*handle
,
925 const char *environment
)
927 uint32_t levels
[] = {0, 1, 2, 3, 4, 5, 6, 7, 8};
930 for (i
=0;i
<ARRAY_SIZE(levels
);i
++) {
932 union spoolss_PrinterInfo info
;
936 torture_assert(tctx
, test_GetPrinter_level(tctx
, p
, handle
, levels
[i
], &info
),
937 "failed to call GetPrinter");
939 if ((levels
[i
] == 2) && info
.info2
.drivername
&& strlen(info
.info2
.drivername
)) {
941 test_GetPrinterDriver2(tctx
, p
, handle
, info
.info2
.drivername
, environment
),
942 "failed to call test_GetPrinterDriver2");
949 static bool test_SetPrinter(struct torture_context
*tctx
,
950 struct dcerpc_pipe
*p
,
951 struct policy_handle
*handle
,
952 struct spoolss_SetPrinterInfoCtr
*info_ctr
,
953 struct spoolss_DevmodeContainer
*devmode_ctr
,
954 struct sec_desc_buf
*secdesc_ctr
,
955 enum spoolss_PrinterControl command
)
957 struct spoolss_SetPrinter r
;
959 r
.in
.handle
= handle
;
960 r
.in
.info_ctr
= info_ctr
;
961 r
.in
.devmode_ctr
= devmode_ctr
;
962 r
.in
.secdesc_ctr
= secdesc_ctr
;
963 r
.in
.command
= command
;
965 torture_comment(tctx
, "Testing SetPrinter level %d\n", r
.in
.info_ctr
->level
);
967 torture_assert_ntstatus_ok(tctx
, dcerpc_spoolss_SetPrinter(p
, tctx
, &r
),
968 "failed to call SetPrinter");
969 torture_assert_werr_ok(tctx
, r
.out
.result
,
970 "failed to call SetPrinter");
975 static bool test_SetPrinter_errors(struct torture_context
*tctx
,
976 struct dcerpc_pipe
*p
,
977 struct policy_handle
*handle
)
979 struct spoolss_SetPrinter r
;
980 uint16_t levels
[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
983 struct spoolss_SetPrinterInfoCtr info_ctr
;
984 struct spoolss_DevmodeContainer devmode_ctr
;
985 struct sec_desc_buf secdesc_ctr
;
988 info_ctr
.info
.info0
= NULL
;
990 ZERO_STRUCT(devmode_ctr
);
991 ZERO_STRUCT(secdesc_ctr
);
993 r
.in
.handle
= handle
;
994 r
.in
.info_ctr
= &info_ctr
;
995 r
.in
.devmode_ctr
= &devmode_ctr
;
996 r
.in
.secdesc_ctr
= &secdesc_ctr
;
999 torture_comment(tctx
, "Testing SetPrinter all zero\n");
1001 torture_assert_ntstatus_ok(tctx
, dcerpc_spoolss_SetPrinter(p
, tctx
, &r
),
1002 "failed to call SetPrinter");
1003 torture_assert_werr_equal(tctx
, r
.out
.result
, WERR_INVALID_PARAM
,
1004 "failed to call SetPrinter");
1007 for (i
=0; i
< ARRAY_SIZE(levels
); i
++) {
1009 struct spoolss_SetPrinterInfo0 info0
;
1010 struct spoolss_SetPrinterInfo1 info1
;
1011 struct spoolss_SetPrinterInfo2 info2
;
1012 struct spoolss_SetPrinterInfo3 info3
;
1013 struct spoolss_SetPrinterInfo4 info4
;
1014 struct spoolss_SetPrinterInfo5 info5
;
1015 struct spoolss_SetPrinterInfo6 info6
;
1016 struct spoolss_SetPrinterInfo7 info7
;
1017 struct spoolss_SetPrinterInfo8 info8
;
1018 struct spoolss_SetPrinterInfo9 info9
;
1021 info_ctr
.level
= levels
[i
];
1022 switch (levels
[i
]) {
1025 info_ctr
.info
.info0
= &info0
;
1029 info_ctr
.info
.info1
= &info1
;
1033 info_ctr
.info
.info2
= &info2
;
1037 info_ctr
.info
.info3
= &info3
;
1041 info_ctr
.info
.info4
= &info4
;
1045 info_ctr
.info
.info5
= &info5
;
1049 info_ctr
.info
.info6
= &info6
;
1053 info_ctr
.info
.info7
= &info7
;
1057 info_ctr
.info
.info8
= &info8
;
1061 info_ctr
.info
.info9
= &info9
;
1065 torture_comment(tctx
, "Testing SetPrinter level %d, command %d\n",
1066 info_ctr
.level
, r
.in
.command
);
1068 torture_assert_ntstatus_ok(tctx
, dcerpc_spoolss_SetPrinter(p
, tctx
, &r
),
1069 "failed to call SetPrinter");
1071 switch (r
.in
.command
) {
1072 case SPOOLSS_PRINTER_CONTROL_UNPAUSE
: /* 0 */
1073 /* is ignored for all levels other then 0 */
1074 if (info_ctr
.level
> 0) {
1078 case SPOOLSS_PRINTER_CONTROL_PAUSE
: /* 1 */
1079 case SPOOLSS_PRINTER_CONTROL_RESUME
: /* 2 */
1080 case SPOOLSS_PRINTER_CONTROL_PURGE
: /* 3 */
1081 if (info_ctr
.level
> 0) {
1082 /* is invalid for all levels other then 0 */
1083 torture_assert_werr_equal(tctx
, r
.out
.result
, WERR_INVALID_PRINTER_COMMAND
,
1084 "unexpected error code returned");
1087 torture_assert_werr_ok(tctx
, r
.out
.result
,
1088 "failed to call SetPrinter with non 0 command");
1093 case SPOOLSS_PRINTER_CONTROL_SET_STATUS
: /* 4 */
1094 /* FIXME: gd needs further investigation */
1096 torture_assert_werr_equal(tctx
, r
.out
.result
, WERR_INVALID_PRINTER_COMMAND
,
1097 "unexpected error code returned");
1101 switch (info_ctr
.level
) {
1103 torture_assert_werr_equal(tctx
, r
.out
.result
, WERR_UNKNOWN_LEVEL
,
1104 "unexpected error code returned");
1107 torture_assert_werr_equal(tctx
, r
.out
.result
, WERR_UNKNOWN_PRINTER_DRIVER
,
1108 "unexpected error code returned");
1114 torture_assert_werr_equal(tctx
, r
.out
.result
, WERR_INVALID_PARAM
,
1115 "unexpected error code returned");
1118 torture_assert_werr_equal(tctx
, r
.out
.result
, WERR_NOT_SUPPORTED
,
1119 "unexpected error code returned");
1122 torture_assert_werr_ok(tctx
, r
.out
.result
,
1123 "failed to call SetPrinter");
1128 if (r
.in
.command
< 5) {
1136 static void clear_info2(struct spoolss_SetPrinterInfoCtr
*r
)
1138 if ((r
->level
== 2) && (r
->info
.info2
)) {
1139 r
->info
.info2
->secdesc_ptr
= 0;
1140 r
->info
.info2
->devmode_ptr
= 0;
1144 static bool test_PrinterInfo(struct torture_context
*tctx
,
1145 struct dcerpc_pipe
*p
,
1146 struct policy_handle
*handle
)
1149 struct spoolss_SetPrinter s
;
1150 struct spoolss_GetPrinter q
;
1151 struct spoolss_GetPrinter q0
;
1152 struct spoolss_SetPrinterInfoCtr info_ctr
;
1153 union spoolss_PrinterInfo info
;
1154 struct spoolss_DevmodeContainer devmode_ctr
;
1155 struct sec_desc_buf secdesc_ctr
;
1160 uint32_t status_list
[] = {
1161 /* these do not stick
1162 PRINTER_STATUS_PAUSED,
1163 PRINTER_STATUS_ERROR,
1164 PRINTER_STATUS_PENDING_DELETION, */
1165 PRINTER_STATUS_PAPER_JAM
,
1166 PRINTER_STATUS_PAPER_OUT
,
1167 PRINTER_STATUS_MANUAL_FEED
,
1168 PRINTER_STATUS_PAPER_PROBLEM
,
1169 PRINTER_STATUS_OFFLINE
,
1170 PRINTER_STATUS_IO_ACTIVE
,
1171 PRINTER_STATUS_BUSY
,
1172 PRINTER_STATUS_PRINTING
,
1173 PRINTER_STATUS_OUTPUT_BIN_FULL
,
1174 PRINTER_STATUS_NOT_AVAILABLE
,
1175 PRINTER_STATUS_WAITING
,
1176 PRINTER_STATUS_PROCESSING
,
1177 PRINTER_STATUS_INITIALIZING
,
1178 PRINTER_STATUS_WARMING_UP
,
1179 PRINTER_STATUS_TONER_LOW
,
1180 PRINTER_STATUS_NO_TONER
,
1181 PRINTER_STATUS_PAGE_PUNT
,
1182 PRINTER_STATUS_USER_INTERVENTION
,
1183 PRINTER_STATUS_OUT_OF_MEMORY
,
1184 PRINTER_STATUS_DOOR_OPEN
,
1185 PRINTER_STATUS_SERVER_UNKNOWN
,
1186 PRINTER_STATUS_POWER_SAVE
,
1187 /* these do not stick
1196 uint32_t default_attribute
= PRINTER_ATTRIBUTE_LOCAL
;
1197 uint32_t attribute_list
[] = {
1198 PRINTER_ATTRIBUTE_QUEUED
,
1199 /* fails with WERR_INVALID_DATATYPE:
1200 PRINTER_ATTRIBUTE_DIRECT, */
1202 PRINTER_ATTRIBUTE_DEFAULT, */
1203 PRINTER_ATTRIBUTE_SHARED
,
1205 PRINTER_ATTRIBUTE_NETWORK, */
1206 PRINTER_ATTRIBUTE_HIDDEN
,
1207 PRINTER_ATTRIBUTE_LOCAL
,
1208 PRINTER_ATTRIBUTE_ENABLE_DEVQ
,
1209 PRINTER_ATTRIBUTE_KEEPPRINTEDJOBS
,
1210 PRINTER_ATTRIBUTE_DO_COMPLETE_FIRST
,
1211 PRINTER_ATTRIBUTE_WORK_OFFLINE
,
1213 PRINTER_ATTRIBUTE_ENABLE_BIDI, */
1214 /* fails with WERR_INVALID_DATATYPE:
1215 PRINTER_ATTRIBUTE_RAW_ONLY, */
1216 /* these do not stick
1217 PRINTER_ATTRIBUTE_PUBLISHED,
1218 PRINTER_ATTRIBUTE_FAX,
1219 PRINTER_ATTRIBUTE_TS,
1238 ZERO_STRUCT(devmode_ctr
);
1239 ZERO_STRUCT(secdesc_ctr
);
1241 s
.in
.handle
= handle
;
1243 s
.in
.info_ctr
= &info_ctr
;
1244 s
.in
.devmode_ctr
= &devmode_ctr
;
1245 s
.in
.secdesc_ctr
= &secdesc_ctr
;
1247 q
.in
.handle
= handle
;
1251 #define TESTGETCALL(call, r) \
1252 r.in.buffer = NULL; \
1254 r.out.needed = &needed; \
1255 status = dcerpc_spoolss_ ##call(p, tctx, &r); \
1256 if (!NT_STATUS_IS_OK(status)) { \
1257 torture_comment(tctx, #call " level %u failed - %s (%s)\n", \
1258 r.in.level, nt_errstr(status), __location__); \
1262 if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {\
1263 DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed); \
1264 data_blob_clear(&blob); \
1265 r.in.buffer = &blob; \
1266 r.in.offered = needed; \
1268 status = dcerpc_spoolss_ ##call(p, tctx, &r); \
1269 if (!NT_STATUS_IS_OK(status)) { \
1270 torture_comment(tctx, #call " level %u failed - %s (%s)\n", \
1271 r.in.level, nt_errstr(status), __location__); \
1275 if (!W_ERROR_IS_OK(r.out.result)) { \
1276 torture_comment(tctx, #call " level %u failed - %s (%s)\n", \
1277 r.in.level, win_errstr(r.out.result), __location__); \
1283 #define TESTSETCALL_EXP(call, r, err) \
1284 clear_info2(&info_ctr);\
1285 status = dcerpc_spoolss_ ##call(p, tctx, &r); \
1286 if (!NT_STATUS_IS_OK(status)) { \
1287 torture_comment(tctx, #call " level %u failed - %s (%s)\n", \
1288 r.in.info_ctr->level, nt_errstr(status), __location__); \
1292 if (!W_ERROR_IS_OK(err)) { \
1293 if (!W_ERROR_EQUAL(err, r.out.result)) { \
1294 torture_comment(tctx, #call " level %u failed - %s, expected %s (%s)\n", \
1295 r.in.info_ctr->level, win_errstr(r.out.result), win_errstr(err), __location__); \
1300 if (!W_ERROR_IS_OK(r.out.result)) { \
1301 torture_comment(tctx, #call " level %u failed - %s (%s)\n", \
1302 r.in.info_ctr->level, win_errstr(r.out.result), __location__); \
1307 #define TESTSETCALL(call, r) \
1308 TESTSETCALL_EXP(call, r, WERR_OK)
1310 #define STRING_EQUAL(s1, s2, field) \
1311 if ((s1 && !s2) || (s2 && !s1) || strcmp(s1, s2)) { \
1312 torture_comment(tctx, "Failed to set %s to '%s' (%s)\n", \
1313 #field, s2, __location__); \
1318 #define MEM_EQUAL(s1, s2, length, field) \
1319 if ((s1 && !s2) || (s2 && !s1) || memcmp(s1, s2, length)) { \
1320 torture_comment(tctx, "Failed to set %s to '%s' (%s)\n", \
1321 #field, (const char *)s2, __location__); \
1326 #define INT_EQUAL(i1, i2, field) \
1328 torture_comment(tctx, "Failed to set %s to 0x%llx - got 0x%llx (%s)\n", \
1329 #field, (unsigned long long)i2, (unsigned long long)i1, __location__); \
1334 #define SD_EQUAL(sd1, sd2, field) \
1335 if (!security_descriptor_equal(sd1, sd2)) { \
1336 torture_comment(tctx, "Failed to set %s (%s)\n", \
1337 #field, __location__); \
1342 #define TEST_PRINTERINFO_STRING_EXP_ERR(lvl1, field1, lvl2, field2, value, err) do { \
1343 torture_comment(tctx, "field test %d/%s vs %d/%s\n", lvl1, #field1, lvl2, #field2); \
1344 q.in.level = lvl1; \
1345 TESTGETCALL(GetPrinter, q) \
1346 info_ctr.level = lvl1; \
1347 info_ctr.info.info ## lvl1 = (struct spoolss_SetPrinterInfo ## lvl1 *)&q.out.info->info ## lvl1; \
1348 info_ctr.info.info ## lvl1->field1 = value;\
1349 TESTSETCALL_EXP(SetPrinter, s, err) \
1350 info_ctr.info.info ## lvl1->field1 = ""; \
1351 TESTGETCALL(GetPrinter, q) \
1352 info_ctr.info.info ## lvl1->field1 = value; \
1353 STRING_EQUAL(info_ctr.info.info ## lvl1->field1, value, field1); \
1354 q.in.level = lvl2; \
1355 TESTGETCALL(GetPrinter, q) \
1356 info_ctr.info.info ## lvl2 = (struct spoolss_SetPrinterInfo ## lvl2 *)&q.out.info->info ## lvl2; \
1357 STRING_EQUAL(info_ctr.info.info ## lvl2->field2, value, field2); \
1360 #define TEST_PRINTERINFO_STRING(lvl1, field1, lvl2, field2, value) do { \
1361 TEST_PRINTERINFO_STRING_EXP_ERR(lvl1, field1, lvl2, field2, value, WERR_OK); \
1364 #define TEST_PRINTERINFO_INT_EXP(lvl1, field1, lvl2, field2, value, exp_value) do { \
1365 torture_comment(tctx, "field test %d/%s vs %d/%s\n", lvl1, #field1, lvl2, #field2); \
1366 q.in.level = lvl1; \
1367 TESTGETCALL(GetPrinter, q) \
1368 info_ctr.level = lvl1; \
1369 info_ctr.info.info ## lvl1 = (struct spoolss_SetPrinterInfo ## lvl1 *)&q.out.info->info ## lvl1; \
1370 info_ctr.info.info ## lvl1->field1 = value; \
1371 TESTSETCALL(SetPrinter, s) \
1372 info_ctr.info.info ## lvl1->field1 = 0; \
1373 TESTGETCALL(GetPrinter, q) \
1374 info_ctr.info.info ## lvl1 = (struct spoolss_SetPrinterInfo ## lvl1 *)&q.out.info->info ## lvl1; \
1375 INT_EQUAL(info_ctr.info.info ## lvl1->field1, exp_value, field1); \
1376 q.in.level = lvl2; \
1377 TESTGETCALL(GetPrinter, q) \
1378 info_ctr.info.info ## lvl2 = (struct spoolss_SetPrinterInfo ## lvl2 *)&q.out.info->info ## lvl2; \
1379 INT_EQUAL(info_ctr.info.info ## lvl2->field2, exp_value, field1); \
1382 #define TEST_PRINTERINFO_INT(lvl1, field1, lvl2, field2, value) do { \
1383 TEST_PRINTERINFO_INT_EXP(lvl1, field1, lvl2, field2, value, value); \
1387 do { TESTGETCALL(GetPrinter
, q0
) } while (0);
1389 TEST_PRINTERINFO_STRING(2, comment
, 1, comment
, "xx2-1 comment");
1390 TEST_PRINTERINFO_STRING(2, comment
, 2, comment
, "xx2-2 comment");
1392 /* level 0 printername does not stick */
1393 /* TEST_PRINTERINFO_STRING(2, printername, 0, printername, "xx2-0 printer"); */
1394 TEST_PRINTERINFO_STRING(2, printername
, 1, name
, "xx2-1 printer");
1395 TEST_PRINTERINFO_STRING(2, printername
, 2, printername
, "xx2-2 printer");
1396 TEST_PRINTERINFO_STRING(2, printername
, 4, printername
, "xx2-4 printer");
1397 TEST_PRINTERINFO_STRING(2, printername
, 5, printername
, "xx2-5 printer");
1398 /* TEST_PRINTERINFO_STRING(4, printername, 0, printername, "xx4-0 printer"); */
1399 TEST_PRINTERINFO_STRING(4, printername
, 1, name
, "xx4-1 printer");
1400 TEST_PRINTERINFO_STRING(4, printername
, 2, printername
, "xx4-2 printer");
1401 TEST_PRINTERINFO_STRING(4, printername
, 4, printername
, "xx4-4 printer");
1402 TEST_PRINTERINFO_STRING(4, printername
, 5, printername
, "xx4-5 printer");
1403 /* TEST_PRINTERINFO_STRING(5, printername, 0, printername, "xx5-0 printer"); */
1404 TEST_PRINTERINFO_STRING(5, printername
, 1, name
, "xx5-1 printer");
1405 TEST_PRINTERINFO_STRING(5, printername
, 2, printername
, "xx5-2 printer");
1406 TEST_PRINTERINFO_STRING(5, printername
, 4, printername
, "xx5-4 printer");
1407 TEST_PRINTERINFO_STRING(5, printername
, 5, printername
, "xx5-5 printer");
1409 /* servername can be set but does not stick
1410 TEST_PRINTERINFO_STRING(2, servername, 0, servername, "xx2-0 servername");
1411 TEST_PRINTERINFO_STRING(2, servername, 2, servername, "xx2-2 servername");
1412 TEST_PRINTERINFO_STRING(2, servername, 4, servername, "xx2-4 servername");
1415 /* passing an invalid port will result in WERR_UNKNOWN_PORT */
1416 TEST_PRINTERINFO_STRING_EXP_ERR(2, portname
, 2, portname
, "xx2-2 portname", WERR_UNKNOWN_PORT
);
1417 TEST_PRINTERINFO_STRING_EXP_ERR(2, portname
, 5, portname
, "xx2-5 portname", WERR_UNKNOWN_PORT
);
1418 TEST_PRINTERINFO_STRING_EXP_ERR(5, portname
, 2, portname
, "xx5-2 portname", WERR_UNKNOWN_PORT
);
1419 TEST_PRINTERINFO_STRING_EXP_ERR(5, portname
, 5, portname
, "xx5-5 portname", WERR_UNKNOWN_PORT
);
1421 TEST_PRINTERINFO_STRING(2, sharename
, 2, sharename
, "xx2-2 sharename");
1422 /* passing an invalid driver will result in WERR_UNKNOWN_PRINTER_DRIVER */
1423 TEST_PRINTERINFO_STRING_EXP_ERR(2, drivername
, 2, drivername
, "xx2-2 drivername", WERR_UNKNOWN_PRINTER_DRIVER
);
1424 TEST_PRINTERINFO_STRING(2, location
, 2, location
, "xx2-2 location");
1425 /* passing an invalid sepfile will result in WERR_INVALID_SEPARATOR_FILE */
1426 TEST_PRINTERINFO_STRING_EXP_ERR(2, sepfile
, 2, sepfile
, "xx2-2 sepfile", WERR_INVALID_SEPARATOR_FILE
);
1427 /* passing an invalid printprocessor will result in WERR_UNKNOWN_PRINTPROCESSOR */
1428 TEST_PRINTERINFO_STRING_EXP_ERR(2, printprocessor
, 2, printprocessor
, "xx2-2 printprocessor", WERR_UNKNOWN_PRINTPROCESSOR
);
1429 TEST_PRINTERINFO_STRING(2, datatype
, 2, datatype
, "xx2-2 datatype");
1430 TEST_PRINTERINFO_STRING(2, parameters
, 2, parameters
, "xx2-2 parameters");
1432 for (i
=0; i
< ARRAY_SIZE(attribute_list
); i
++) {
1433 /* TEST_PRINTERINFO_INT_EXP(2, attributes, 1, flags,
1435 (attribute_list[i] | default_attribute)
1437 TEST_PRINTERINFO_INT_EXP(2, attributes
, 2, attributes
,
1439 (attribute_list
[i
] | default_attribute
)
1441 TEST_PRINTERINFO_INT_EXP(2, attributes
, 4, attributes
,
1443 (attribute_list
[i
] | default_attribute
)
1445 TEST_PRINTERINFO_INT_EXP(2, attributes
, 5, attributes
,
1447 (attribute_list
[i
] | default_attribute
)
1449 /* TEST_PRINTERINFO_INT_EXP(4, attributes, 1, flags,
1451 (attribute_list[i] | default_attribute)
1453 TEST_PRINTERINFO_INT_EXP(4, attributes
, 2, attributes
,
1455 (attribute_list
[i
] | default_attribute
)
1457 TEST_PRINTERINFO_INT_EXP(4, attributes
, 4, attributes
,
1459 (attribute_list
[i
] | default_attribute
)
1461 TEST_PRINTERINFO_INT_EXP(4, attributes
, 5, attributes
,
1463 (attribute_list
[i
] | default_attribute
)
1465 /* TEST_PRINTERINFO_INT_EXP(5, attributes, 1, flags,
1467 (attribute_list[i] | default_attribute)
1469 TEST_PRINTERINFO_INT_EXP(5, attributes
, 2, attributes
,
1471 (attribute_list
[i
] | default_attribute
)
1473 TEST_PRINTERINFO_INT_EXP(5, attributes
, 4, attributes
,
1475 (attribute_list
[i
] | default_attribute
)
1477 TEST_PRINTERINFO_INT_EXP(5, attributes
, 5, attributes
,
1479 (attribute_list
[i
] | default_attribute
)
1483 for (i
=0; i
< ARRAY_SIZE(status_list
); i
++) {
1484 /* level 2 sets do not stick
1485 TEST_PRINTERINFO_INT(2, status, 0, status, status_list[i]);
1486 TEST_PRINTERINFO_INT(2, status, 2, status, status_list[i]);
1487 TEST_PRINTERINFO_INT(2, status, 6, status, status_list[i]); */
1488 TEST_PRINTERINFO_INT(6, status
, 0, status
, status_list
[i
]);
1489 TEST_PRINTERINFO_INT(6, status
, 2, status
, status_list
[i
]);
1490 TEST_PRINTERINFO_INT(6, status
, 6, status
, status_list
[i
]);
1493 /* priorities need to be between 0 and 99
1494 passing an invalid priority will result in WERR_INVALID_PRIORITY */
1495 TEST_PRINTERINFO_INT(2, priority
, 2, priority
, 0);
1496 TEST_PRINTERINFO_INT(2, priority
, 2, priority
, 1);
1497 TEST_PRINTERINFO_INT(2, priority
, 2, priority
, 99);
1498 /* TEST_PRINTERINFO_INT(2, priority, 2, priority, 100); */
1499 TEST_PRINTERINFO_INT(2, defaultpriority
,2, defaultpriority
, 0);
1500 TEST_PRINTERINFO_INT(2, defaultpriority
,2, defaultpriority
, 1);
1501 TEST_PRINTERINFO_INT(2, defaultpriority
,2, defaultpriority
, 99);
1502 /* TEST_PRINTERINFO_INT(2, defaultpriority,2, defaultpriority, 100); */
1504 TEST_PRINTERINFO_INT(2, starttime
, 2, starttime
, __LINE__
);
1505 TEST_PRINTERINFO_INT(2, untiltime
, 2, untiltime
, __LINE__
);
1508 TEST_PRINTERINFO_INT(2, cjobs, 2, cjobs, __LINE__);
1509 TEST_PRINTERINFO_INT(2, averageppm, 2, averageppm, __LINE__); */
1512 TEST_PRINTERINFO_INT(5, device_not_selected_timeout, 5, device_not_selected_timeout, __LINE__);
1513 TEST_PRINTERINFO_INT(5, transmission_retry_timeout, 5, transmission_retry_timeout, __LINE__); */
1515 /* FIXME: gd also test devmode and secdesc behavior */
1518 /* verify composition of level 1 description field */
1519 const char *description
;
1523 do { TESTGETCALL(GetPrinter
, q0
) } while (0);
1525 description
= talloc_strdup(tctx
, q0
.out
.info
->info1
.description
);
1528 do { TESTGETCALL(GetPrinter
, q0
) } while (0);
1530 tmp
= talloc_asprintf(tctx
, "%s,%s,%s",
1531 q0
.out
.info
->info2
.printername
,
1532 q0
.out
.info
->info2
.drivername
,
1533 q0
.out
.info
->info2
.location
);
1535 do { STRING_EQUAL(description
, tmp
, "description")} while (0);
1541 #define torture_assert_sid_equal(torture_ctx,got,expected,cmt)\
1542 do { struct dom_sid *__got = (got), *__expected = (expected); \
1543 if (!dom_sid_equal(__got, __expected)) { \
1544 torture_result(torture_ctx, TORTURE_FAIL, \
1545 __location__": "#got" was %s, expected %s: %s", \
1546 dom_sid_string(torture_ctx, __got), dom_sid_string(torture_ctx, __expected), cmt); \
1551 static bool test_security_descriptor_equal(struct torture_context
*tctx
,
1552 const struct security_descriptor
*sd1
,
1553 const struct security_descriptor
*sd2
)
1560 torture_comment(tctx
, "%s\n", __location__
);
1564 torture_assert_int_equal(tctx
, sd1
->revision
, sd2
->revision
, "revision mismatch");
1565 torture_assert_int_equal(tctx
, sd1
->type
, sd2
->type
, "type mismatch");
1567 torture_assert_sid_equal(tctx
, sd1
->owner_sid
, sd2
->owner_sid
, "owner mismatch");
1568 torture_assert_sid_equal(tctx
, sd1
->group_sid
, sd2
->group_sid
, "group mismatch");
1570 if (!security_acl_equal(sd1
->sacl
, sd2
->sacl
)) {
1571 torture_comment(tctx
, "%s: sacl mismatch\n", __location__
);
1572 NDR_PRINT_DEBUG(security_acl
, sd1
->sacl
);
1573 NDR_PRINT_DEBUG(security_acl
, sd2
->sacl
);
1576 if (!security_acl_equal(sd1
->dacl
, sd2
->dacl
)) {
1577 torture_comment(tctx
, "%s: dacl mismatch\n", __location__
);
1578 NDR_PRINT_DEBUG(security_acl
, sd1
->dacl
);
1579 NDR_PRINT_DEBUG(security_acl
, sd2
->dacl
);
1586 static bool test_sd_set_level(struct torture_context
*tctx
,
1587 struct dcerpc_pipe
*p
,
1588 struct policy_handle
*handle
,
1590 struct security_descriptor
*sd
)
1592 struct spoolss_SetPrinterInfoCtr info_ctr
;
1593 struct spoolss_DevmodeContainer devmode_ctr
;
1594 struct sec_desc_buf secdesc_ctr
;
1596 ZERO_STRUCT(devmode_ctr
);
1597 ZERO_STRUCT(secdesc_ctr
);
1601 union spoolss_PrinterInfo info
;
1602 struct spoolss_SetPrinterInfo2 info2
;
1603 torture_assert(tctx
, test_GetPrinter_level(tctx
, p
, handle
, 2, &info
), "");
1605 info2
.servername
= info
.info2
.servername
;
1606 info2
.printername
= info
.info2
.printername
;
1607 info2
.sharename
= info
.info2
.sharename
;
1608 info2
.portname
= info
.info2
.portname
;
1609 info2
.drivername
= info
.info2
.drivername
;
1610 info2
.comment
= info
.info2
.comment
;
1611 info2
.location
= info
.info2
.location
;
1612 info2
.devmode_ptr
= 0;
1613 info2
.sepfile
= info
.info2
.sepfile
;
1614 info2
.printprocessor
= info
.info2
.printprocessor
;
1615 info2
.datatype
= info
.info2
.datatype
;
1616 info2
.parameters
= info
.info2
.parameters
;
1617 info2
.secdesc_ptr
= 0;
1618 info2
.attributes
= info
.info2
.attributes
;
1619 info2
.priority
= info
.info2
.priority
;
1620 info2
.defaultpriority
= info
.info2
.defaultpriority
;
1621 info2
.starttime
= info
.info2
.starttime
;
1622 info2
.untiltime
= info
.info2
.untiltime
;
1623 info2
.status
= info
.info2
.status
;
1624 info2
.cjobs
= info
.info2
.cjobs
;
1625 info2
.averageppm
= info
.info2
.averageppm
;
1628 info_ctr
.info
.info2
= &info2
;
1633 struct spoolss_SetPrinterInfo3 info3
;
1635 info3
.sec_desc_ptr
= 0;
1638 info_ctr
.info
.info3
= &info3
;
1646 secdesc_ctr
.sd
= sd
;
1648 torture_assert(tctx
,
1649 test_SetPrinter(tctx
, p
, handle
, &info_ctr
, &devmode_ctr
, &secdesc_ctr
, 0), "");
1654 static bool test_PrinterInfo_SDs(struct torture_context
*tctx
,
1655 struct dcerpc_pipe
*p
,
1656 struct policy_handle
*handle
)
1658 union spoolss_PrinterInfo info
;
1659 struct security_descriptor
*sd1
, *sd2
;
1662 /* just compare level 2 and level 3 */
1664 torture_assert(tctx
, test_GetPrinter_level(tctx
, p
, handle
, 2, &info
), "");
1666 sd1
= info
.info2
.secdesc
;
1668 torture_assert(tctx
, test_GetPrinter_level(tctx
, p
, handle
, 3, &info
), "");
1670 sd2
= info
.info3
.secdesc
;
1672 torture_assert(tctx
, test_security_descriptor_equal(tctx
, sd1
, sd2
),
1673 "SD level 2 != SD level 3");
1676 /* query level 2, set level 2, query level 2 */
1678 torture_assert(tctx
, test_GetPrinter_level(tctx
, p
, handle
, 2, &info
), "");
1680 sd1
= info
.info2
.secdesc
;
1682 torture_assert(tctx
, test_sd_set_level(tctx
, p
, handle
, 2, sd1
), "");
1684 torture_assert(tctx
, test_GetPrinter_level(tctx
, p
, handle
, 2, &info
), "");
1686 sd2
= info
.info2
.secdesc
;
1687 if (sd1
->type
& SEC_DESC_DACL_DEFAULTED
) {
1688 torture_comment(tctx
, "removing SEC_DESC_DACL_DEFAULTED\n");
1689 sd1
->type
&= ~SEC_DESC_DACL_DEFAULTED
;
1692 torture_assert(tctx
, test_security_descriptor_equal(tctx
, sd1
, sd2
),
1693 "SD level 2 != SD level 2 after SD has been set via level 2");
1696 /* query level 2, set level 3, query level 2 */
1698 torture_assert(tctx
, test_GetPrinter_level(tctx
, p
, handle
, 2, &info
), "");
1700 sd1
= info
.info2
.secdesc
;
1702 torture_assert(tctx
, test_sd_set_level(tctx
, p
, handle
, 3, sd1
), "");
1704 torture_assert(tctx
, test_GetPrinter_level(tctx
, p
, handle
, 2, &info
), "");
1706 sd2
= info
.info2
.secdesc
;
1708 torture_assert(tctx
, test_security_descriptor_equal(tctx
, sd1
, sd2
),
1709 "SD level 2 != SD level 2 after SD has been set via level 3");
1711 /* set modified sd level 3, query level 2 */
1713 for (i
=0; i
< 93; i
++) {
1714 struct security_ace a
;
1715 const char *sid_string
= talloc_asprintf(tctx
, "S-1-5-32-9999%i", i
);
1716 a
.type
= SEC_ACE_TYPE_ACCESS_ALLOWED
;
1718 a
.size
= 0; /* autogenerated */
1720 a
.trustee
= *dom_sid_parse_talloc(tctx
, sid_string
);
1721 torture_assert_ntstatus_ok(tctx
, security_descriptor_dacl_add(sd1
, &a
), "");
1724 torture_assert(tctx
, test_sd_set_level(tctx
, p
, handle
, 3, sd1
), "");
1726 torture_assert(tctx
, test_GetPrinter_level(tctx
, p
, handle
, 2, &info
), "");
1727 sd2
= info
.info2
.secdesc
;
1729 if (sd1
->type
& SEC_DESC_DACL_DEFAULTED
) {
1730 torture_comment(tctx
, "removing SEC_DESC_DACL_DEFAULTED\n");
1731 sd1
->type
&= ~SEC_DESC_DACL_DEFAULTED
;
1734 torture_assert(tctx
, test_security_descriptor_equal(tctx
, sd1
, sd2
),
1735 "modified SD level 2 != SD level 2 after SD has been set via level 3");
1742 * wrapper call that saves original sd, runs tests, and restores sd
1745 static bool test_PrinterInfo_SD(struct torture_context
*tctx
,
1746 struct dcerpc_pipe
*p
,
1747 struct policy_handle
*handle
)
1749 union spoolss_PrinterInfo info
;
1750 struct security_descriptor
*sd
;
1753 torture_comment(tctx
, "\nTesting Printer Security Descriptors\n");
1755 /* save original sd */
1757 torture_assert(tctx
, test_GetPrinter_level(tctx
, p
, handle
, 2, &info
),
1758 "failed to get initial security descriptor");
1760 sd
= security_descriptor_copy(tctx
, info
.info2
.secdesc
);
1764 ret
= test_PrinterInfo_SDs(tctx
, p
, handle
);
1766 /* restore original sd */
1768 torture_assert(tctx
, test_sd_set_level(tctx
, p
, handle
, 3, sd
),
1769 "failed to restore initial security descriptor");
1771 torture_comment(tctx
, "Printer Security Descriptors test %s\n",
1772 ret
? "succeeded" : "failed");
1778 static bool test_devmode_set_level(struct torture_context
*tctx
,
1779 struct dcerpc_pipe
*p
,
1780 struct policy_handle
*handle
,
1782 struct spoolss_DeviceMode
*devmode
)
1784 struct spoolss_SetPrinterInfoCtr info_ctr
;
1785 struct spoolss_DevmodeContainer devmode_ctr
;
1786 struct sec_desc_buf secdesc_ctr
;
1788 ZERO_STRUCT(devmode_ctr
);
1789 ZERO_STRUCT(secdesc_ctr
);
1793 union spoolss_PrinterInfo info
;
1794 struct spoolss_SetPrinterInfo2 info2
;
1795 torture_assert(tctx
, test_GetPrinter_level(tctx
, p
, handle
, 2, &info
), "");
1797 info2
.servername
= info
.info2
.servername
;
1798 info2
.printername
= info
.info2
.printername
;
1799 info2
.sharename
= info
.info2
.sharename
;
1800 info2
.portname
= info
.info2
.portname
;
1801 info2
.drivername
= info
.info2
.drivername
;
1802 info2
.comment
= info
.info2
.comment
;
1803 info2
.location
= info
.info2
.location
;
1804 info2
.devmode_ptr
= 0;
1805 info2
.sepfile
= info
.info2
.sepfile
;
1806 info2
.printprocessor
= info
.info2
.printprocessor
;
1807 info2
.datatype
= info
.info2
.datatype
;
1808 info2
.parameters
= info
.info2
.parameters
;
1809 info2
.secdesc_ptr
= 0;
1810 info2
.attributes
= info
.info2
.attributes
;
1811 info2
.priority
= info
.info2
.priority
;
1812 info2
.defaultpriority
= info
.info2
.defaultpriority
;
1813 info2
.starttime
= info
.info2
.starttime
;
1814 info2
.untiltime
= info
.info2
.untiltime
;
1815 info2
.status
= info
.info2
.status
;
1816 info2
.cjobs
= info
.info2
.cjobs
;
1817 info2
.averageppm
= info
.info2
.averageppm
;
1820 info_ctr
.info
.info2
= &info2
;
1825 struct spoolss_SetPrinterInfo8 info8
;
1827 info8
.devmode_ptr
= 0;
1830 info_ctr
.info
.info8
= &info8
;
1838 devmode_ctr
.devmode
= devmode
;
1840 torture_assert(tctx
,
1841 test_SetPrinter(tctx
, p
, handle
, &info_ctr
, &devmode_ctr
, &secdesc_ctr
, 0), "");
1847 static bool test_devicemode_equal(struct torture_context
*tctx
,
1848 const struct spoolss_DeviceMode
*d1
,
1849 const struct spoolss_DeviceMode
*d2
)
1856 torture_comment(tctx
, "%s\n", __location__
);
1859 torture_assert_str_equal(tctx
, d1
->devicename
, d2
->devicename
, "devicename mismatch");
1860 torture_assert_int_equal(tctx
, d1
->specversion
, d2
->specversion
, "specversion mismatch");
1861 torture_assert_int_equal(tctx
, d1
->driverversion
, d2
->driverversion
, "driverversion mismatch");
1862 torture_assert_int_equal(tctx
, d1
->size
, d2
->size
, "size mismatch");
1863 torture_assert_int_equal(tctx
, d1
->__driverextra_length
, d2
->__driverextra_length
, "__driverextra_length mismatch");
1864 torture_assert_int_equal(tctx
, d1
->fields
, d2
->fields
, "fields mismatch");
1865 torture_assert_int_equal(tctx
, d1
->orientation
, d2
->orientation
, "orientation mismatch");
1866 torture_assert_int_equal(tctx
, d1
->papersize
, d2
->papersize
, "papersize mismatch");
1867 torture_assert_int_equal(tctx
, d1
->paperlength
, d2
->paperlength
, "paperlength mismatch");
1868 torture_assert_int_equal(tctx
, d1
->paperwidth
, d2
->paperwidth
, "paperwidth mismatch");
1869 torture_assert_int_equal(tctx
, d1
->scale
, d2
->scale
, "scale mismatch");
1870 torture_assert_int_equal(tctx
, d1
->copies
, d2
->copies
, "copies mismatch");
1871 torture_assert_int_equal(tctx
, d1
->defaultsource
, d2
->defaultsource
, "defaultsource mismatch");
1872 torture_assert_int_equal(tctx
, d1
->printquality
, d2
->printquality
, "printquality mismatch");
1873 torture_assert_int_equal(tctx
, d1
->color
, d2
->color
, "color mismatch");
1874 torture_assert_int_equal(tctx
, d1
->duplex
, d2
->duplex
, "duplex mismatch");
1875 torture_assert_int_equal(tctx
, d1
->yresolution
, d2
->yresolution
, "yresolution mismatch");
1876 torture_assert_int_equal(tctx
, d1
->ttoption
, d2
->ttoption
, "ttoption mismatch");
1877 torture_assert_int_equal(tctx
, d1
->collate
, d2
->collate
, "collate mismatch");
1878 torture_assert_str_equal(tctx
, d1
->formname
, d2
->formname
, "formname mismatch");
1879 torture_assert_int_equal(tctx
, d1
->logpixels
, d2
->logpixels
, "logpixels mismatch");
1880 torture_assert_int_equal(tctx
, d1
->bitsperpel
, d2
->bitsperpel
, "bitsperpel mismatch");
1881 torture_assert_int_equal(tctx
, d1
->pelswidth
, d2
->pelswidth
, "pelswidth mismatch");
1882 torture_assert_int_equal(tctx
, d1
->pelsheight
, d2
->pelsheight
, "pelsheight mismatch");
1883 torture_assert_int_equal(tctx
, d1
->displayflags
, d2
->displayflags
, "displayflags mismatch");
1884 torture_assert_int_equal(tctx
, d1
->displayfrequency
, d2
->displayfrequency
, "displayfrequency mismatch");
1885 torture_assert_int_equal(tctx
, d1
->icmmethod
, d2
->icmmethod
, "icmmethod mismatch");
1886 torture_assert_int_equal(tctx
, d1
->icmintent
, d2
->icmintent
, "icmintent mismatch");
1887 torture_assert_int_equal(tctx
, d1
->mediatype
, d2
->mediatype
, "mediatype mismatch");
1888 torture_assert_int_equal(tctx
, d1
->dithertype
, d2
->dithertype
, "dithertype mismatch");
1889 torture_assert_int_equal(tctx
, d1
->reserved1
, d2
->reserved1
, "reserved1 mismatch");
1890 torture_assert_int_equal(tctx
, d1
->reserved2
, d2
->reserved2
, "reserved2 mismatch");
1891 torture_assert_int_equal(tctx
, d1
->panningwidth
, d2
->panningwidth
, "panningwidth mismatch");
1892 torture_assert_int_equal(tctx
, d1
->panningheight
, d2
->panningheight
, "panningheight mismatch");
1893 torture_assert_data_blob_equal(tctx
, d1
->driverextra_data
, d2
->driverextra_data
, "driverextra_data mismatch");
1898 static bool test_devicemode_full(struct torture_context
*tctx
,
1899 struct dcerpc_pipe
*p
,
1900 struct policy_handle
*handle
)
1902 struct spoolss_SetPrinter s
;
1903 struct spoolss_GetPrinter q
;
1904 struct spoolss_GetPrinter q0
;
1905 struct spoolss_SetPrinterInfoCtr info_ctr
;
1906 struct spoolss_SetPrinterInfo8 info8
;
1907 union spoolss_PrinterInfo info
;
1908 struct spoolss_DevmodeContainer devmode_ctr
;
1909 struct sec_desc_buf secdesc_ctr
;
1914 #define TEST_DEVMODE_INT_EXP(lvl1, field1, lvl2, field2, value, exp_value) do { \
1915 torture_comment(tctx, "field test %d/%s vs %d/%s\n", lvl1, #field1, lvl2, #field2); \
1916 q.in.level = lvl1; \
1917 TESTGETCALL(GetPrinter, q) \
1918 info_ctr.level = lvl1; \
1920 info_ctr.info.info ## lvl1 = (struct spoolss_SetPrinterInfo ## lvl1 *)&q.out.info->info ## lvl1; \
1921 } else if (lvl1 == 8) {\
1922 info_ctr.info.info ## lvl1 = &info8; \
1924 devmode_ctr.devmode = q.out.info->info ## lvl1.devmode; \
1925 devmode_ctr.devmode->field1 = value; \
1926 TESTSETCALL(SetPrinter, s) \
1927 TESTGETCALL(GetPrinter, q) \
1928 INT_EQUAL(q.out.info->info ## lvl1.devmode->field1, exp_value, field1); \
1929 q.in.level = lvl2; \
1930 TESTGETCALL(GetPrinter, q) \
1931 INT_EQUAL(q.out.info->info ## lvl2.devmode->field2, exp_value, field1); \
1934 #define TEST_DEVMODE_INT(lvl1, field1, lvl2, field2, value) do { \
1935 TEST_DEVMODE_INT_EXP(lvl1, field1, lvl2, field2, value, value); \
1938 ZERO_STRUCT(devmode_ctr
);
1939 ZERO_STRUCT(secdesc_ctr
);
1942 s
.in
.handle
= handle
;
1944 s
.in
.info_ctr
= &info_ctr
;
1945 s
.in
.devmode_ctr
= &devmode_ctr
;
1946 s
.in
.secdesc_ctr
= &secdesc_ctr
;
1948 q
.in
.handle
= handle
;
1953 const char *devicename
;/* [charset(UTF16)] */
1954 enum spoolss_DeviceModeSpecVersion specversion
;
1955 uint16_t driverversion
;
1957 uint16_t __driverextra_length
;/* [value(r->driverextra_data.length)] */
1961 TEST_DEVMODE_INT(8, orientation
, 8, orientation
, __LINE__
);
1962 TEST_DEVMODE_INT(8, papersize
, 8, papersize
, __LINE__
);
1963 TEST_DEVMODE_INT(8, paperlength
, 8, paperlength
, __LINE__
);
1964 TEST_DEVMODE_INT(8, paperwidth
, 8, paperwidth
, __LINE__
);
1965 TEST_DEVMODE_INT(8, scale
, 8, scale
, __LINE__
);
1966 TEST_DEVMODE_INT(8, copies
, 8, copies
, __LINE__
);
1967 TEST_DEVMODE_INT(8, defaultsource
, 8, defaultsource
, __LINE__
);
1968 TEST_DEVMODE_INT(8, printquality
, 8, printquality
, __LINE__
);
1969 TEST_DEVMODE_INT(8, color
, 8, color
, __LINE__
);
1970 TEST_DEVMODE_INT(8, duplex
, 8, duplex
, __LINE__
);
1971 TEST_DEVMODE_INT(8, yresolution
, 8, yresolution
, __LINE__
);
1972 TEST_DEVMODE_INT(8, ttoption
, 8, ttoption
, __LINE__
);
1973 TEST_DEVMODE_INT(8, collate
, 8, collate
, __LINE__
);
1975 const char *formname
;/* [charset(UTF16)] */
1977 TEST_DEVMODE_INT(8, logpixels
, 8, logpixels
, __LINE__
);
1978 TEST_DEVMODE_INT(8, bitsperpel
, 8, bitsperpel
, __LINE__
);
1979 TEST_DEVMODE_INT(8, pelswidth
, 8, pelswidth
, __LINE__
);
1980 TEST_DEVMODE_INT(8, pelsheight
, 8, pelsheight
, __LINE__
);
1981 TEST_DEVMODE_INT(8, displayflags
, 8, displayflags
, __LINE__
);
1982 TEST_DEVMODE_INT(8, displayfrequency
, 8, displayfrequency
, __LINE__
);
1983 TEST_DEVMODE_INT(8, icmmethod
, 8, icmmethod
, __LINE__
);
1984 TEST_DEVMODE_INT(8, icmintent
, 8, icmintent
, __LINE__
);
1985 TEST_DEVMODE_INT(8, mediatype
, 8, mediatype
, __LINE__
);
1986 TEST_DEVMODE_INT(8, dithertype
, 8, dithertype
, __LINE__
);
1987 TEST_DEVMODE_INT(8, reserved1
, 8, reserved1
, __LINE__
);
1988 TEST_DEVMODE_INT(8, reserved2
, 8, reserved2
, __LINE__
);
1989 TEST_DEVMODE_INT(8, panningwidth
, 8, panningwidth
, __LINE__
);
1990 TEST_DEVMODE_INT(8, panningheight
, 8, panningheight
, __LINE__
);
1995 static bool call_OpenPrinterEx(struct torture_context
*tctx
,
1996 struct dcerpc_pipe
*p
,
1998 struct spoolss_DeviceMode
*devmode
,
1999 struct policy_handle
*handle
);
2001 static bool test_ClosePrinter(struct torture_context
*tctx
,
2002 struct dcerpc_pipe
*p
,
2003 struct policy_handle
*handle
);
2005 static bool test_PrinterInfo_DevModes(struct torture_context
*tctx
,
2006 struct dcerpc_pipe
*p
,
2007 struct policy_handle
*handle
,
2010 union spoolss_PrinterInfo info
;
2011 struct spoolss_DeviceMode
*devmode
;
2012 struct spoolss_DeviceMode
*devmode2
;
2013 struct policy_handle handle_devmode
;
2015 /* simply compare level8 and level2 devmode */
2017 torture_assert(tctx
, test_GetPrinter_level(tctx
, p
, handle
, 8, &info
), "");
2019 devmode
= info
.info8
.devmode
;
2021 torture_assert(tctx
, test_GetPrinter_level(tctx
, p
, handle
, 2, &info
), "");
2023 devmode2
= info
.info2
.devmode
;
2025 torture_assert(tctx
, test_devicemode_equal(tctx
, devmode
, devmode2
),
2026 "DM level 8 != DM level 2");
2029 /* set devicemode level 8 and see if it persists */
2031 devmode
->copies
= 93;
2032 devmode
->formname
= talloc_strdup(tctx
, "Legal");
2034 torture_assert(tctx
, test_devmode_set_level(tctx
, p
, handle
, 8, devmode
), "");
2036 torture_assert(tctx
, test_GetPrinter_level(tctx
, p
, handle
, 8, &info
), "");
2038 devmode2
= info
.info8
.devmode
;
2040 torture_assert(tctx
, test_devicemode_equal(tctx
, devmode
, devmode2
),
2041 "modified DM level 8 != DM level 8 after DM has been set via level 8");
2043 torture_assert(tctx
, test_GetPrinter_level(tctx
, p
, handle
, 2, &info
), "");
2045 devmode2
= info
.info2
.devmode
;
2047 torture_assert(tctx
, test_devicemode_equal(tctx
, devmode
, devmode2
),
2048 "modified DM level 8 != DM level 2");
2051 /* set devicemode level 2 and see if it persists */
2053 devmode
->copies
= 39;
2054 devmode
->formname
= talloc_strdup(tctx
, "Executive");
2056 torture_assert(tctx
, test_devmode_set_level(tctx
, p
, handle
, 2, devmode
), "");
2058 torture_assert(tctx
, test_GetPrinter_level(tctx
, p
, handle
, 8, &info
), "");
2060 devmode2
= info
.info8
.devmode
;
2062 torture_assert(tctx
, test_devicemode_equal(tctx
, devmode
, devmode2
),
2063 "modified DM level 8 != DM level 8 after DM has been set via level 2");
2065 torture_assert(tctx
, test_GetPrinter_level(tctx
, p
, handle
, 2, &info
), "");
2067 devmode2
= info
.info2
.devmode
;
2069 torture_assert(tctx
, test_devicemode_equal(tctx
, devmode
, devmode2
),
2070 "modified DM level 8 != DM level 2");
2073 /* check every single bit in public part of devicemode */
2075 torture_assert(tctx
, test_devicemode_full(tctx
, p
, handle
),
2076 "failed to set every single devicemode component");
2079 /* change formname upon open and see if it persists in getprinter calls */
2081 devmode
->formname
= talloc_strdup(tctx
, "A4");
2082 devmode
->copies
= 42;
2084 torture_assert(tctx
, call_OpenPrinterEx(tctx
, p
, name
, devmode
, &handle_devmode
),
2085 "failed to open printer handle");
2087 torture_assert(tctx
, test_GetPrinter_level(tctx
, p
, &handle_devmode
, 8, &info
), "");
2089 devmode2
= info
.info8
.devmode
;
2091 if (strequal(devmode
->devicename
, devmode2
->devicename
)) {
2092 torture_comment(tctx
, "devicenames are the same\n");
2094 torture_comment(tctx
, "devicename passed in for open: %s\n", devmode
->devicename
);
2095 torture_comment(tctx
, "devicename after level 8 get: %s\n", devmode2
->devicename
);
2098 if (strequal(devmode
->formname
, devmode2
->formname
)) {
2099 torture_warning(tctx
, "formname are the same\n");
2101 torture_comment(tctx
, "formname passed in for open: %s\n", devmode
->formname
);
2102 torture_comment(tctx
, "formname after level 8 get: %s\n", devmode2
->formname
);
2105 if (devmode
->copies
== devmode2
->copies
) {
2106 torture_warning(tctx
, "copies are the same\n");
2108 torture_comment(tctx
, "copies passed in for open: %d\n", devmode
->copies
);
2109 torture_comment(tctx
, "copies after level 8 get: %d\n", devmode2
->copies
);
2112 torture_assert(tctx
, test_GetPrinter_level(tctx
, p
, &handle_devmode
, 2, &info
), "");
2114 devmode2
= info
.info2
.devmode
;
2116 if (strequal(devmode
->devicename
, devmode2
->devicename
)) {
2117 torture_comment(tctx
, "devicenames are the same\n");
2119 torture_comment(tctx
, "devicename passed in for open: %s\n", devmode
->devicename
);
2120 torture_comment(tctx
, "devicename after level 2 get: %s\n", devmode2
->devicename
);
2123 if (strequal(devmode
->formname
, devmode2
->formname
)) {
2124 torture_warning(tctx
, "formname is the same\n");
2126 torture_comment(tctx
, "formname passed in for open: %s\n", devmode
->formname
);
2127 torture_comment(tctx
, "formname after level 2 get: %s\n", devmode2
->formname
);
2130 if (devmode
->copies
== devmode2
->copies
) {
2131 torture_warning(tctx
, "copies are the same\n");
2133 torture_comment(tctx
, "copies passed in for open: %d\n", devmode
->copies
);
2134 torture_comment(tctx
, "copies after level 2 get: %d\n", devmode2
->copies
);
2137 test_ClosePrinter(tctx
, p
, &handle_devmode
);
2143 * wrapper call that saves original devmode, runs tests, and restores devmode
2146 static bool test_PrinterInfo_DevMode(struct torture_context
*tctx
,
2147 struct dcerpc_pipe
*p
,
2148 struct policy_handle
*handle
,
2151 union spoolss_PrinterInfo info
;
2152 struct spoolss_DeviceMode
*devmode
;
2155 torture_comment(tctx
, "\nTesting Printer Devicemodes\n");
2157 /* save original devmode */
2159 torture_assert(tctx
, test_GetPrinter_level(tctx
, p
, handle
, 8, &info
),
2160 "failed to get initial global devicemode");
2162 devmode
= info
.info8
.devmode
;
2166 ret
= test_PrinterInfo_DevModes(tctx
, p
, handle
, name
);
2168 /* restore original devmode */
2170 torture_assert(tctx
, test_devmode_set_level(tctx
, p
, handle
, 8, devmode
),
2171 "failed to restore initial global device mode");
2173 torture_comment(tctx
, "Printer Devicemodes test %s\n",
2174 ret
? "succeeded" : "failed");
2180 static bool test_ClosePrinter(struct torture_context
*tctx
,
2181 struct dcerpc_pipe
*p
,
2182 struct policy_handle
*handle
)
2185 struct spoolss_ClosePrinter r
;
2187 r
.in
.handle
= handle
;
2188 r
.out
.handle
= handle
;
2190 torture_comment(tctx
, "Testing ClosePrinter\n");
2192 status
= dcerpc_spoolss_ClosePrinter(p
, tctx
, &r
);
2193 torture_assert_ntstatus_ok(tctx
, status
, "ClosePrinter failed");
2194 torture_assert_werr_ok(tctx
, r
.out
.result
, "ClosePrinter failed");
2199 static bool test_GetForm(struct torture_context
*tctx
,
2200 struct dcerpc_pipe
*p
,
2201 struct policy_handle
*handle
,
2202 const char *form_name
,
2206 struct spoolss_GetForm r
;
2209 r
.in
.handle
= handle
;
2210 r
.in
.form_name
= form_name
;
2214 r
.out
.needed
= &needed
;
2216 torture_comment(tctx
, "Testing GetForm level %d\n", r
.in
.level
);
2218 status
= dcerpc_spoolss_GetForm(p
, tctx
, &r
);
2219 torture_assert_ntstatus_ok(tctx
, status
, "GetForm failed");
2221 if (W_ERROR_EQUAL(r
.out
.result
, WERR_INSUFFICIENT_BUFFER
)) {
2222 DATA_BLOB blob
= data_blob_talloc(tctx
, NULL
, needed
);
2223 data_blob_clear(&blob
);
2224 r
.in
.buffer
= &blob
;
2225 r
.in
.offered
= needed
;
2226 status
= dcerpc_spoolss_GetForm(p
, tctx
, &r
);
2227 torture_assert_ntstatus_ok(tctx
, status
, "GetForm failed");
2229 torture_assert_werr_ok(tctx
, r
.out
.result
, "GetForm failed");
2231 torture_assert(tctx
, r
.out
.info
, "No form info returned");
2234 torture_assert_werr_ok(tctx
, r
.out
.result
, "GetForm failed");
2236 CHECK_NEEDED_SIZE_LEVEL(spoolss_FormInfo
, r
.out
.info
, r
.in
.level
, lp_iconv_convenience(tctx
->lp_ctx
), needed
, 4);
2241 static bool test_EnumForms(struct torture_context
*tctx
,
2242 struct dcerpc_pipe
*p
,
2243 struct policy_handle
*handle
, bool print_server
)
2246 struct spoolss_EnumForms r
;
2250 uint32_t levels
[] = { 1, 2 };
2253 for (i
=0; i
<ARRAY_SIZE(levels
); i
++) {
2255 union spoolss_FormInfo
*info
;
2257 r
.in
.handle
= handle
;
2258 r
.in
.level
= levels
[i
];
2261 r
.out
.needed
= &needed
;
2262 r
.out
.count
= &count
;
2265 torture_comment(tctx
, "Testing EnumForms level %d\n", levels
[i
]);
2267 status
= dcerpc_spoolss_EnumForms(p
, tctx
, &r
);
2268 torture_assert_ntstatus_ok(tctx
, status
, "EnumForms failed");
2270 if ((r
.in
.level
== 2) && (W_ERROR_EQUAL(r
.out
.result
, WERR_UNKNOWN_LEVEL
))) {
2274 if (print_server
&& W_ERROR_EQUAL(r
.out
.result
, WERR_BADFID
))
2275 torture_fail(tctx
, "EnumForms on the PrintServer isn't supported by test server (NT4)");
2277 if (W_ERROR_EQUAL(r
.out
.result
, WERR_INSUFFICIENT_BUFFER
)) {
2279 DATA_BLOB blob
= data_blob_talloc(tctx
, NULL
, needed
);
2280 data_blob_clear(&blob
);
2281 r
.in
.buffer
= &blob
;
2282 r
.in
.offered
= needed
;
2284 status
= dcerpc_spoolss_EnumForms(p
, tctx
, &r
);
2286 torture_assert(tctx
, info
, "No forms returned");
2288 for (j
= 0; j
< count
; j
++) {
2290 ret
&= test_GetForm(tctx
, p
, handle
, info
[j
].info1
.form_name
, levels
[i
]);
2294 torture_assert_ntstatus_ok(tctx
, status
, "EnumForms failed");
2296 torture_assert_werr_ok(tctx
, r
.out
.result
, "EnumForms failed");
2298 CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumForms
, info
, r
.in
.level
, count
, lp_iconv_convenience(tctx
->lp_ctx
), needed
, 4);
2304 static bool test_DeleteForm(struct torture_context
*tctx
,
2305 struct dcerpc_pipe
*p
,
2306 struct policy_handle
*handle
,
2307 const char *form_name
)
2310 struct spoolss_DeleteForm r
;
2312 r
.in
.handle
= handle
;
2313 r
.in
.form_name
= form_name
;
2315 status
= dcerpc_spoolss_DeleteForm(p
, tctx
, &r
);
2317 torture_assert_ntstatus_ok(tctx
, status
, "DeleteForm failed");
2319 torture_assert_werr_ok(tctx
, r
.out
.result
, "DeleteForm failed");
2324 static bool test_AddForm(struct torture_context
*tctx
,
2325 struct dcerpc_pipe
*p
,
2326 struct policy_handle
*handle
, bool print_server
)
2328 struct spoolss_AddForm r
;
2329 struct spoolss_AddFormInfo1 addform
;
2330 const char *form_name
= "testform3";
2334 r
.in
.handle
= handle
;
2336 r
.in
.info
.info1
= &addform
;
2337 addform
.flags
= SPOOLSS_FORM_USER
;
2338 addform
.form_name
= form_name
;
2339 addform
.size
.width
= 50;
2340 addform
.size
.height
= 25;
2341 addform
.area
.left
= 5;
2342 addform
.area
.top
= 10;
2343 addform
.area
.right
= 45;
2344 addform
.area
.bottom
= 15;
2346 status
= dcerpc_spoolss_AddForm(p
, tctx
, &r
);
2348 torture_assert_ntstatus_ok(tctx
, status
, "AddForm failed");
2350 torture_assert_werr_ok(tctx
, r
.out
.result
, "AddForm failed");
2352 if (!print_server
) ret
&= test_GetForm(tctx
, p
, handle
, form_name
, 1);
2355 struct spoolss_SetForm sf
;
2356 struct spoolss_AddFormInfo1 setform
;
2358 sf
.in
.handle
= handle
;
2359 sf
.in
.form_name
= form_name
;
2361 sf
.in
.info
.info1
= &setform
;
2362 setform
.flags
= addform
.flags
;
2363 setform
.form_name
= addform
.form_name
;
2364 setform
.size
= addform
.size
;
2365 setform
.area
= addform
.area
;
2367 setform
.size
.width
= 1234;
2369 status
= dcerpc_spoolss_SetForm(p
, tctx
, &sf
);
2371 torture_assert_ntstatus_ok(tctx
, status
, "SetForm failed");
2373 torture_assert_werr_ok(tctx
, r
.out
.result
, "SetForm failed");
2376 if (!print_server
) ret
&= test_GetForm(tctx
, p
, handle
, form_name
, 1);
2379 struct spoolss_EnumForms e
;
2380 union spoolss_FormInfo
*info
;
2385 e
.in
.handle
= handle
;
2389 e
.out
.needed
= &needed
;
2390 e
.out
.count
= &count
;
2393 torture_comment(tctx
, "Testing EnumForms level 1\n");
2395 status
= dcerpc_spoolss_EnumForms(p
, tctx
, &e
);
2396 torture_assert_ntstatus_ok(tctx
, status
, "EnumForms failed");
2398 if (print_server
&& W_ERROR_EQUAL(e
.out
.result
, WERR_BADFID
))
2399 torture_fail(tctx
, "EnumForms on the PrintServer isn't supported by test server (NT4)");
2401 if (W_ERROR_EQUAL(e
.out
.result
, WERR_INSUFFICIENT_BUFFER
)) {
2403 DATA_BLOB blob
= data_blob_talloc(tctx
, NULL
, needed
);
2404 data_blob_clear(&blob
);
2405 e
.in
.buffer
= &blob
;
2406 e
.in
.offered
= needed
;
2408 status
= dcerpc_spoolss_EnumForms(p
, tctx
, &e
);
2410 torture_assert(tctx
, info
, "No forms returned");
2412 for (j
= 0; j
< count
; j
++) {
2413 if (strequal(form_name
, info
[j
].info1
.form_name
)) {
2419 torture_assert(tctx
, found
, "Newly added form not found in enum call");
2422 if (!test_DeleteForm(tctx
, p
, handle
, form_name
)) {
2429 static bool test_EnumPorts_old(struct torture_context
*tctx
,
2430 struct dcerpc_pipe
*p
)
2433 struct spoolss_EnumPorts r
;
2436 union spoolss_PortInfo
*info
;
2438 r
.in
.servername
= talloc_asprintf(tctx
, "\\\\%s",
2439 dcerpc_server_name(p
));
2443 r
.out
.needed
= &needed
;
2444 r
.out
.count
= &count
;
2447 torture_comment(tctx
, "Testing EnumPorts\n");
2449 status
= dcerpc_spoolss_EnumPorts(p
, tctx
, &r
);
2451 torture_assert_ntstatus_ok(tctx
, status
, "EnumPorts failed");
2453 if (W_ERROR_EQUAL(r
.out
.result
, WERR_INSUFFICIENT_BUFFER
)) {
2454 DATA_BLOB blob
= data_blob_talloc(tctx
, NULL
, needed
);
2455 data_blob_clear(&blob
);
2456 r
.in
.buffer
= &blob
;
2457 r
.in
.offered
= needed
;
2459 status
= dcerpc_spoolss_EnumPorts(p
, tctx
, &r
);
2460 torture_assert_ntstatus_ok(tctx
, status
, "EnumPorts failed");
2461 torture_assert_werr_ok(tctx
, r
.out
.result
, "EnumPorts failed");
2463 torture_assert(tctx
, info
, "No ports returned");
2466 torture_assert_werr_ok(tctx
, r
.out
.result
, "EnumPorts failed");
2468 CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumPorts
, info
, 2, count
, lp_iconv_convenience(tctx
->lp_ctx
), needed
, 4);
2473 static bool test_AddPort(struct torture_context
*tctx
,
2474 struct dcerpc_pipe
*p
)
2477 struct spoolss_AddPort r
;
2479 r
.in
.server_name
= talloc_asprintf(tctx
, "\\\\%s",
2480 dcerpc_server_name(p
));
2482 r
.in
.monitor_name
= "foo";
2484 torture_comment(tctx
, "Testing AddPort\n");
2486 status
= dcerpc_spoolss_AddPort(p
, tctx
, &r
);
2488 torture_assert_ntstatus_ok(tctx
, status
, "AddPort failed");
2490 /* win2k3 returns WERR_NOT_SUPPORTED */
2494 if (!W_ERROR_IS_OK(r
.out
.result
)) {
2495 printf("AddPort failed - %s\n", win_errstr(r
.out
.result
));
2504 static bool test_GetJob(struct torture_context
*tctx
,
2505 struct dcerpc_pipe
*p
,
2506 struct policy_handle
*handle
, uint32_t job_id
)
2509 struct spoolss_GetJob r
;
2510 union spoolss_JobInfo info
;
2512 uint32_t levels
[] = {1, 2 /* 3, 4 */};
2515 r
.in
.handle
= handle
;
2516 r
.in
.job_id
= job_id
;
2520 r
.out
.needed
= &needed
;
2523 torture_comment(tctx
, "Testing GetJob level %d\n", r
.in
.level
);
2525 status
= dcerpc_spoolss_GetJob(p
, tctx
, &r
);
2526 torture_assert_werr_equal(tctx
, r
.out
.result
, WERR_UNKNOWN_LEVEL
, "Unexpected return code");
2528 for (i
= 0; i
< ARRAY_SIZE(levels
); i
++) {
2530 torture_comment(tctx
, "Testing GetJob level %d\n", r
.in
.level
);
2534 r
.in
.level
= levels
[i
];
2538 status
= dcerpc_spoolss_GetJob(p
, tctx
, &r
);
2539 torture_assert_ntstatus_ok(tctx
, status
, "GetJob failed");
2541 if (W_ERROR_EQUAL(r
.out
.result
, WERR_INSUFFICIENT_BUFFER
)) {
2542 DATA_BLOB blob
= data_blob_talloc(tctx
, NULL
, needed
);
2543 data_blob_clear(&blob
);
2544 r
.in
.buffer
= &blob
;
2545 r
.in
.offered
= needed
;
2547 status
= dcerpc_spoolss_GetJob(p
, tctx
, &r
);
2548 torture_assert_ntstatus_ok(tctx
, status
, "GetJob failed");
2551 torture_assert(tctx
, r
.out
.info
, "No job info returned");
2552 torture_assert_werr_ok(tctx
, r
.out
.result
, "GetJob failed");
2554 CHECK_NEEDED_SIZE_LEVEL(spoolss_JobInfo
, r
.out
.info
, r
.in
.level
, lp_iconv_convenience(tctx
->lp_ctx
), needed
, 4);
2560 static bool test_SetJob(struct torture_context
*tctx
,
2561 struct dcerpc_pipe
*p
,
2562 struct policy_handle
*handle
, uint32_t job_id
,
2563 enum spoolss_JobControl command
)
2566 struct spoolss_SetJob r
;
2568 r
.in
.handle
= handle
;
2569 r
.in
.job_id
= job_id
;
2571 r
.in
.command
= command
;
2574 case SPOOLSS_JOB_CONTROL_PAUSE
:
2575 torture_comment(tctx
, "Testing SetJob: SPOOLSS_JOB_CONTROL_PAUSE\n");
2577 case SPOOLSS_JOB_CONTROL_RESUME
:
2578 torture_comment(tctx
, "Testing SetJob: SPOOLSS_JOB_CONTROL_RESUME\n");
2580 case SPOOLSS_JOB_CONTROL_CANCEL
:
2581 torture_comment(tctx
, "Testing SetJob: SPOOLSS_JOB_CONTROL_CANCEL\n");
2583 case SPOOLSS_JOB_CONTROL_RESTART
:
2584 torture_comment(tctx
, "Testing SetJob: SPOOLSS_JOB_CONTROL_RESTART\n");
2586 case SPOOLSS_JOB_CONTROL_DELETE
:
2587 torture_comment(tctx
, "Testing SetJob: SPOOLSS_JOB_CONTROL_DELETE\n");
2589 case SPOOLSS_JOB_CONTROL_SEND_TO_PRINTER
:
2590 torture_comment(tctx
, "Testing SetJob: SPOOLSS_JOB_CONTROL_SEND_TO_PRINTER\n");
2592 case SPOOLSS_JOB_CONTROL_LAST_PAGE_EJECTED
:
2593 torture_comment(tctx
, "Testing SetJob: SPOOLSS_JOB_CONTROL_LAST_PAGE_EJECTED\n");
2595 case SPOOLSS_JOB_CONTROL_RETAIN
:
2596 torture_comment(tctx
, "Testing SetJob: SPOOLSS_JOB_CONTROL_RETAIN\n");
2598 case SPOOLSS_JOB_CONTROL_RELEASE
:
2599 torture_comment(tctx
, "Testing SetJob: SPOOLSS_JOB_CONTROL_RELEASE\n");
2602 torture_comment(tctx
, "Testing SetJob\n");
2606 status
= dcerpc_spoolss_SetJob(p
, tctx
, &r
);
2607 torture_assert_ntstatus_ok(tctx
, status
, "SetJob failed");
2608 torture_assert_werr_ok(tctx
, r
.out
.result
, "SetJob failed");
2613 static bool test_AddJob(struct torture_context
*tctx
,
2614 struct dcerpc_pipe
*p
,
2615 struct policy_handle
*handle
)
2618 struct spoolss_AddJob r
;
2622 r
.in
.handle
= handle
;
2624 r
.out
.needed
= &needed
;
2625 r
.in
.buffer
= r
.out
.buffer
= NULL
;
2627 torture_comment(tctx
, "Testing AddJob\n");
2629 status
= dcerpc_spoolss_AddJob(p
, tctx
, &r
);
2630 torture_assert_werr_equal(tctx
, r
.out
.result
, WERR_UNKNOWN_LEVEL
, "AddJob failed");
2634 status
= dcerpc_spoolss_AddJob(p
, tctx
, &r
);
2635 torture_assert_werr_equal(tctx
, r
.out
.result
, WERR_INVALID_PARAM
, "AddJob failed");
2641 static bool test_EnumJobs(struct torture_context
*tctx
,
2642 struct dcerpc_pipe
*p
,
2643 struct policy_handle
*handle
)
2646 struct spoolss_EnumJobs r
;
2649 union spoolss_JobInfo
*info
;
2651 r
.in
.handle
= handle
;
2653 r
.in
.numjobs
= 0xffffffff;
2657 r
.out
.needed
= &needed
;
2658 r
.out
.count
= &count
;
2661 torture_comment(tctx
, "Testing EnumJobs\n");
2663 status
= dcerpc_spoolss_EnumJobs(p
, tctx
, &r
);
2665 torture_assert_ntstatus_ok(tctx
, status
, "EnumJobs failed");
2667 if (W_ERROR_EQUAL(r
.out
.result
, WERR_INSUFFICIENT_BUFFER
)) {
2669 DATA_BLOB blob
= data_blob_talloc(tctx
, NULL
, needed
);
2670 data_blob_clear(&blob
);
2671 r
.in
.buffer
= &blob
;
2672 r
.in
.offered
= needed
;
2674 status
= dcerpc_spoolss_EnumJobs(p
, tctx
, &r
);
2676 torture_assert_ntstatus_ok(tctx
, status
, "EnumJobs failed");
2677 torture_assert_werr_ok(tctx
, r
.out
.result
, "EnumJobs failed");
2678 torture_assert(tctx
, info
, "No jobs returned");
2680 CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumJobs
, *r
.out
.info
, r
.in
.level
, count
, lp_iconv_convenience(tctx
->lp_ctx
), needed
, 4);
2682 for (j
= 0; j
< count
; j
++) {
2684 torture_assert(tctx
, test_GetJob(tctx
, p
, handle
, info
[j
].info1
.job_id
),
2685 "failed to call test_GetJob");
2688 if (!torture_setting_bool(tctx
, "samba3", false)) {
2689 test_SetJob(tctx
, p
, handle
, info
[j
].info1
.job_id
, SPOOLSS_JOB_CONTROL_PAUSE
);
2690 test_SetJob(tctx
, p
, handle
, info
[j
].info1
.job_id
, SPOOLSS_JOB_CONTROL_RESUME
);
2695 torture_assert_werr_ok(tctx
, r
.out
.result
, "EnumJobs failed");
2701 static bool test_DoPrintTest(struct torture_context
*tctx
,
2702 struct dcerpc_pipe
*p
,
2703 struct policy_handle
*handle
)
2707 struct spoolss_StartDocPrinter s
;
2708 struct spoolss_DocumentInfo1 info1
;
2709 struct spoolss_StartPagePrinter sp
;
2710 struct spoolss_WritePrinter w
;
2711 struct spoolss_EndPagePrinter ep
;
2712 struct spoolss_EndDocPrinter e
;
2715 uint32_t num_written
;
2717 torture_comment(tctx
, "Testing StartDocPrinter\n");
2719 s
.in
.handle
= handle
;
2721 s
.in
.info
.info1
= &info1
;
2722 s
.out
.job_id
= &job_id
;
2723 info1
.document_name
= "TorturePrintJob";
2724 info1
.output_file
= NULL
;
2725 info1
.datatype
= "RAW";
2727 status
= dcerpc_spoolss_StartDocPrinter(p
, tctx
, &s
);
2728 torture_assert_ntstatus_ok(tctx
, status
, "dcerpc_spoolss_StartDocPrinter failed");
2729 torture_assert_werr_ok(tctx
, s
.out
.result
, "StartDocPrinter failed");
2731 for (i
=1; i
< 4; i
++) {
2732 torture_comment(tctx
, "Testing StartPagePrinter: Page[%d]\n", i
);
2734 sp
.in
.handle
= handle
;
2736 status
= dcerpc_spoolss_StartPagePrinter(p
, tctx
, &sp
);
2737 torture_assert_ntstatus_ok(tctx
, status
,
2738 "dcerpc_spoolss_StartPagePrinter failed");
2739 torture_assert_werr_ok(tctx
, sp
.out
.result
, "StartPagePrinter failed");
2741 torture_comment(tctx
, "Testing WritePrinter: Page[%d]\n", i
);
2743 w
.in
.handle
= handle
;
2744 w
.in
.data
= data_blob_string_const(talloc_asprintf(tctx
,"TortureTestPage: %d\nData\n",i
));
2745 w
.out
.num_written
= &num_written
;
2747 status
= dcerpc_spoolss_WritePrinter(p
, tctx
, &w
);
2748 torture_assert_ntstatus_ok(tctx
, status
, "dcerpc_spoolss_WritePrinter failed");
2749 torture_assert_werr_ok(tctx
, w
.out
.result
, "WritePrinter failed");
2751 torture_comment(tctx
, "Testing EndPagePrinter: Page[%d]\n", i
);
2753 ep
.in
.handle
= handle
;
2755 status
= dcerpc_spoolss_EndPagePrinter(p
, tctx
, &ep
);
2756 torture_assert_ntstatus_ok(tctx
, status
, "dcerpc_spoolss_EndPagePrinter failed");
2757 torture_assert_werr_ok(tctx
, ep
.out
.result
, "EndPagePrinter failed");
2760 torture_comment(tctx
, "Testing EndDocPrinter\n");
2762 e
.in
.handle
= handle
;
2764 status
= dcerpc_spoolss_EndDocPrinter(p
, tctx
, &e
);
2765 torture_assert_ntstatus_ok(tctx
, status
, "dcerpc_spoolss_EndDocPrinter failed");
2766 torture_assert_werr_ok(tctx
, e
.out
.result
, "EndDocPrinter failed");
2768 ret
&= test_AddJob(tctx
, p
, handle
);
2769 ret
&= test_EnumJobs(tctx
, p
, handle
);
2771 ret
&= test_SetJob(tctx
, p
, handle
, job_id
, SPOOLSS_JOB_CONTROL_DELETE
);
2776 static bool test_PausePrinter(struct torture_context
*tctx
,
2777 struct dcerpc_pipe
*p
,
2778 struct policy_handle
*handle
)
2781 struct spoolss_SetPrinter r
;
2782 struct spoolss_SetPrinterInfoCtr info_ctr
;
2783 struct spoolss_DevmodeContainer devmode_ctr
;
2784 struct sec_desc_buf secdesc_ctr
;
2787 info_ctr
.info
.info0
= NULL
;
2789 ZERO_STRUCT(devmode_ctr
);
2790 ZERO_STRUCT(secdesc_ctr
);
2792 r
.in
.handle
= handle
;
2793 r
.in
.info_ctr
= &info_ctr
;
2794 r
.in
.devmode_ctr
= &devmode_ctr
;
2795 r
.in
.secdesc_ctr
= &secdesc_ctr
;
2796 r
.in
.command
= SPOOLSS_PRINTER_CONTROL_PAUSE
;
2798 torture_comment(tctx
, "Testing SetPrinter: SPOOLSS_PRINTER_CONTROL_PAUSE\n");
2800 status
= dcerpc_spoolss_SetPrinter(p
, tctx
, &r
);
2802 torture_assert_ntstatus_ok(tctx
, status
, "SetPrinter failed");
2804 torture_assert_werr_ok(tctx
, r
.out
.result
, "SetPrinter failed");
2809 static bool test_ResumePrinter(struct torture_context
*tctx
,
2810 struct dcerpc_pipe
*p
,
2811 struct policy_handle
*handle
)
2814 struct spoolss_SetPrinter r
;
2815 struct spoolss_SetPrinterInfoCtr info_ctr
;
2816 struct spoolss_DevmodeContainer devmode_ctr
;
2817 struct sec_desc_buf secdesc_ctr
;
2820 info_ctr
.info
.info0
= NULL
;
2822 ZERO_STRUCT(devmode_ctr
);
2823 ZERO_STRUCT(secdesc_ctr
);
2825 r
.in
.handle
= handle
;
2826 r
.in
.info_ctr
= &info_ctr
;
2827 r
.in
.devmode_ctr
= &devmode_ctr
;
2828 r
.in
.secdesc_ctr
= &secdesc_ctr
;
2829 r
.in
.command
= SPOOLSS_PRINTER_CONTROL_RESUME
;
2831 torture_comment(tctx
, "Testing SetPrinter: SPOOLSS_PRINTER_CONTROL_RESUME\n");
2833 status
= dcerpc_spoolss_SetPrinter(p
, tctx
, &r
);
2835 torture_assert_ntstatus_ok(tctx
, status
, "SetPrinter failed");
2837 torture_assert_werr_ok(tctx
, r
.out
.result
, "SetPrinter failed");
2842 static bool test_GetPrinterData(struct torture_context
*tctx
,
2843 struct dcerpc_pipe
*p
,
2844 struct policy_handle
*handle
,
2845 const char *value_name
,
2846 enum winreg_Type
*type_p
,
2847 union spoolss_PrinterData
*data_p
)
2850 struct spoolss_GetPrinterData r
;
2852 enum winreg_Type type
;
2853 union spoolss_PrinterData data
;
2855 r
.in
.handle
= handle
;
2856 r
.in
.value_name
= value_name
;
2858 r
.out
.needed
= &needed
;
2862 torture_comment(tctx
, "Testing GetPrinterData(%s)\n", r
.in
.value_name
);
2864 status
= dcerpc_spoolss_GetPrinterData(p
, tctx
, &r
);
2865 torture_assert_ntstatus_ok(tctx
, status
, "GetPrinterData failed");
2867 if (W_ERROR_EQUAL(r
.out
.result
, WERR_MORE_DATA
)) {
2868 r
.in
.offered
= needed
;
2870 status
= dcerpc_spoolss_GetPrinterData(p
, tctx
, &r
);
2871 torture_assert_ntstatus_ok(tctx
, status
, "GetPrinterData failed");
2874 torture_assert_werr_ok(tctx
, r
.out
.result
,
2875 talloc_asprintf(tctx
, "GetPrinterData(%s) failed", r
.in
.value_name
));
2877 CHECK_NEEDED_SIZE_LEVEL(spoolss_PrinterData
, &data
, type
, lp_iconv_convenience(tctx
->lp_ctx
), needed
, 1);
2890 static bool test_GetPrinterDataEx(struct torture_context
*tctx
,
2891 struct dcerpc_pipe
*p
,
2892 struct policy_handle
*handle
,
2893 const char *key_name
,
2894 const char *value_name
,
2895 enum winreg_Type
*type_p
,
2896 union spoolss_PrinterData
*data_p
)
2899 struct spoolss_GetPrinterDataEx r
;
2900 enum winreg_Type type
;
2902 union spoolss_PrinterData data
;
2904 r
.in
.handle
= handle
;
2905 r
.in
.key_name
= key_name
;
2906 r
.in
.value_name
= value_name
;
2909 r
.out
.needed
= &needed
;
2912 torture_comment(tctx
, "Testing GetPrinterDataEx(%s - %s)\n",
2913 r
.in
.key_name
, r
.in
.value_name
);
2915 status
= dcerpc_spoolss_GetPrinterDataEx(p
, tctx
, &r
);
2916 if (!NT_STATUS_IS_OK(status
)) {
2917 if (NT_STATUS_EQUAL(status
,NT_STATUS_NET_WRITE_FAULT
) &&
2918 p
->last_fault_code
== DCERPC_FAULT_OP_RNG_ERROR
) {
2919 torture_skip(tctx
, "GetPrinterDataEx not supported by server\n");
2921 torture_assert_ntstatus_ok(tctx
, status
, "GetPrinterDataEx failed");
2924 if (W_ERROR_EQUAL(r
.out
.result
, WERR_MORE_DATA
)) {
2925 r
.in
.offered
= needed
;
2926 status
= dcerpc_spoolss_GetPrinterDataEx(p
, tctx
, &r
);
2927 torture_assert_ntstatus_ok(tctx
, status
, "GetPrinterDataEx failed");
2930 torture_assert_werr_ok(tctx
, r
.out
.result
,
2931 talloc_asprintf(tctx
, "GetPrinterDataEx(%s - %s) failed", r
.in
.key_name
, r
.in
.value_name
));
2933 CHECK_NEEDED_SIZE_LEVEL(spoolss_PrinterData
, &data
, type
, lp_iconv_convenience(tctx
->lp_ctx
), needed
, 1);
2946 static bool test_GetPrinterData_list(struct torture_context
*tctx
,
2947 struct dcerpc_pipe
*p
,
2948 struct policy_handle
*handle
)
2950 const char *list
[] = {
2954 /* "NetPopup", not on w2k8 */
2955 /* "NetPopupToComputer", not on w2k8 */
2958 "DefaultSpoolDirectory",
2962 /* "OSVersionEx", not on s3 */
2967 for (i
=0; i
< ARRAY_SIZE(list
); i
++) {
2968 enum winreg_Type type
, type_ex
;
2969 union spoolss_PrinterData data
, data_ex
;
2971 torture_assert(tctx
, test_GetPrinterData(tctx
, p
, handle
, list
[i
], &type
, &data
),
2972 talloc_asprintf(tctx
, "GetPrinterData failed on %s\n", list
[i
]));
2973 torture_assert(tctx
, test_GetPrinterDataEx(tctx
, p
, handle
, "random_string", list
[i
], &type_ex
, &data_ex
),
2974 talloc_asprintf(tctx
, "GetPrinterDataEx failed on %s\n", list
[i
]));
2975 torture_assert_int_equal(tctx
, type
, type_ex
, "type mismatch");
2978 torture_assert_str_equal(tctx
, data
.string
, data_ex
.string
, "REG_SZ mismatch");
2981 torture_assert_int_equal(tctx
, data
.value
, data_ex
.value
, "REG_DWORD mismatch");
2984 torture_assert_data_blob_equal(tctx
, data
.binary
, data_ex
.binary
, "REG_BINARY mismatch");
2994 static bool test_EnumPrinterData(struct torture_context
*tctx
, struct dcerpc_pipe
*p
,
2995 struct policy_handle
*handle
)
2998 struct spoolss_EnumPrinterData r
;
3001 r
.in
.handle
= handle
;
3002 r
.in
.enum_index
= 0;
3005 uint32_t value_size
= 0;
3006 uint32_t data_size
= 0;
3007 enum winreg_Type type
= 0;
3009 r
.in
.value_offered
= value_size
;
3010 r
.out
.value_needed
= &value_size
;
3011 r
.in
.data_offered
= data_size
;
3012 r
.out
.data_needed
= &data_size
;
3015 r
.out
.data
= talloc_zero_array(tctx
, uint8_t, 0);
3017 torture_comment(tctx
, "Testing EnumPrinterData\n");
3019 status
= dcerpc_spoolss_EnumPrinterData(p
, tctx
, &r
);
3021 torture_assert_ntstatus_ok(tctx
, status
, "EnumPrinterData failed");
3022 if (W_ERROR_EQUAL(r
.out
.result
, WERR_NO_MORE_ITEMS
)) {
3025 torture_assert_werr_ok(tctx
, r
.out
.result
, "EnumPrinterData");
3027 r
.in
.value_offered
= value_size
;
3028 r
.out
.value_name
= talloc_zero_array(tctx
, const char, value_size
);
3029 r
.in
.data_offered
= data_size
;
3030 r
.out
.data
= talloc_zero_array(tctx
, uint8_t, data_size
);
3032 status
= dcerpc_spoolss_EnumPrinterData(p
, tctx
, &r
);
3034 torture_assert_ntstatus_ok(tctx
, status
, "EnumPrinterData failed");
3035 if (W_ERROR_EQUAL(r
.out
.result
, WERR_NO_MORE_ITEMS
)) {
3039 torture_assert_werr_ok(tctx
, r
.out
.result
, "EnumPrinterData failed");
3041 torture_assert(tctx
, test_GetPrinterData(tctx
, p
, handle
, r
.out
.value_name
, NULL
, NULL
),
3042 talloc_asprintf(tctx
, "failed to call GetPrinterData for %s\n", r
.out
.value_name
));
3044 torture_assert(tctx
, test_GetPrinterDataEx(tctx
, p
, handle
, "PrinterDriverData", r
.out
.value_name
, NULL
, NULL
),
3045 talloc_asprintf(tctx
, "failed to call GetPrinterDataEx on PrinterDriverData for %s\n", r
.out
.value_name
));
3049 } while (W_ERROR_IS_OK(r
.out
.result
));
3054 static bool test_EnumPrinterDataEx(struct torture_context
*tctx
,
3055 struct dcerpc_pipe
*p
,
3056 struct policy_handle
*handle
,
3057 const char *key_name
)
3059 struct spoolss_EnumPrinterDataEx r
;
3060 struct spoolss_PrinterEnumValues
*info
;
3064 r
.in
.handle
= handle
;
3065 r
.in
.key_name
= key_name
;
3067 r
.out
.needed
= &needed
;
3068 r
.out
.count
= &count
;
3071 torture_comment(tctx
, "Testing EnumPrinterDataEx(%s)\n", key_name
);
3073 torture_assert_ntstatus_ok(tctx
, dcerpc_spoolss_EnumPrinterDataEx(p
, tctx
, &r
),
3074 "EnumPrinterDataEx failed");
3075 if (W_ERROR_EQUAL(r
.out
.result
, WERR_MORE_DATA
)) {
3076 r
.in
.offered
= needed
;
3077 torture_assert_ntstatus_ok(tctx
, dcerpc_spoolss_EnumPrinterDataEx(p
, tctx
, &r
),
3078 "EnumPrinterDataEx failed");
3081 torture_assert_werr_ok(tctx
, r
.out
.result
, "EnumPrinterDataEx failed");
3083 CHECK_NEEDED_SIZE_ENUM(spoolss_EnumPrinterDataEx
, info
, count
, lp_iconv_convenience(tctx
->lp_ctx
), needed
, 1);
3089 static bool test_DeletePrinterData(struct torture_context
*tctx
,
3090 struct dcerpc_pipe
*p
,
3091 struct policy_handle
*handle
,
3092 const char *value_name
)
3095 struct spoolss_DeletePrinterData r
;
3097 r
.in
.handle
= handle
;
3098 r
.in
.value_name
= value_name
;
3100 torture_comment(tctx
, "Testing DeletePrinterData(%s)\n",
3103 status
= dcerpc_spoolss_DeletePrinterData(p
, tctx
, &r
);
3105 torture_assert_ntstatus_ok(tctx
, status
, "DeletePrinterData failed");
3106 torture_assert_werr_ok(tctx
, r
.out
.result
, "DeletePrinterData failed");
3111 static bool test_DeletePrinterDataEx(struct torture_context
*tctx
,
3112 struct dcerpc_pipe
*p
,
3113 struct policy_handle
*handle
,
3114 const char *key_name
,
3115 const char *value_name
)
3117 struct spoolss_DeletePrinterDataEx r
;
3119 r
.in
.handle
= handle
;
3120 r
.in
.key_name
= key_name
;
3121 r
.in
.value_name
= value_name
;
3123 torture_comment(tctx
, "Testing DeletePrinterDataEx(%s - %s)\n",
3124 r
.in
.key_name
, r
.in
.value_name
);
3126 torture_assert_ntstatus_ok(tctx
,
3127 dcerpc_spoolss_DeletePrinterDataEx(p
, tctx
, &r
),
3128 "DeletePrinterDataEx failed");
3129 torture_assert_werr_ok(tctx
, r
.out
.result
,
3130 "DeletePrinterDataEx failed");
3135 static bool test_DeletePrinterKey(struct torture_context
*tctx
,
3136 struct dcerpc_pipe
*p
,
3137 struct policy_handle
*handle
,
3138 const char *key_name
)
3140 struct spoolss_DeletePrinterKey r
;
3142 r
.in
.handle
= handle
;
3143 r
.in
.key_name
= key_name
;
3145 torture_comment(tctx
, "Testing DeletePrinterKey(%s)\n", r
.in
.key_name
);
3147 if (strequal(key_name
, "") && !torture_setting_bool(tctx
, "dangerous", false)) {
3148 torture_skip(tctx
, "not wiping out printer registry - enable dangerous tests to use\n");
3152 torture_assert_ntstatus_ok(tctx
,
3153 dcerpc_spoolss_DeletePrinterKey(p
, tctx
, &r
),
3154 "DeletePrinterKey failed");
3155 torture_assert_werr_ok(tctx
, r
.out
.result
,
3156 "DeletePrinterKey failed");
3161 static bool test_SetPrinterData(struct torture_context
*tctx
,
3162 struct dcerpc_pipe
*p
,
3163 struct policy_handle
*handle
)
3166 struct spoolss_SetPrinterData r
;
3167 const char *values
[] = {
3171 /* FIXME: not working with s3 atm. */
3177 /* FIXME: not working with s3 atm. */
3184 for (i
=0; i
< ARRAY_SIZE(values
); i
++) {
3186 enum winreg_Type type
;
3187 union spoolss_PrinterData data
;
3189 r
.in
.handle
= handle
;
3190 r
.in
.value_name
= values
[i
];
3192 r
.in
.data
.string
= "dog";
3194 torture_comment(tctx
, "Testing SetPrinterData(%s)\n",
3197 status
= dcerpc_spoolss_SetPrinterData(p
, tctx
, &r
);
3199 torture_assert_ntstatus_ok(tctx
, status
, "SetPrinterData failed");
3200 torture_assert_werr_ok(tctx
, r
.out
.result
, "SetPrinterData failed");
3202 if (!test_GetPrinterData(tctx
, p
, handle
, r
.in
.value_name
, &type
, &data
)) {
3206 torture_assert_int_equal(tctx
, r
.in
.type
, type
, "type mismatch");
3207 torture_assert_str_equal(tctx
, r
.in
.data
.string
, data
.string
, "data mismatch");
3209 if (!test_DeletePrinterData(tctx
, p
, handle
, r
.in
.value_name
)) {
3217 static bool test_EnumPrinterKey(struct torture_context
*tctx
,
3218 struct dcerpc_pipe
*p
,
3219 struct policy_handle
*handle
,
3220 const char *key_name
,
3221 const char ***array
);
3223 static bool test_SetPrinterDataEx(struct torture_context
*tctx
,
3224 struct dcerpc_pipe
*p
,
3225 struct policy_handle
*handle
)
3228 struct spoolss_SetPrinterDataEx r
;
3229 const char *value_name
= "dog";
3230 const char *keys
[] = {
3234 /* FIXME: not working with s3 atm. */
3235 "torturedataex_with_subkey\\subkey",
3236 "torturedataex_with_subkey\\subkey:0",
3237 "torturedataex_with_subkey\\subkey:1",
3238 "torturedataex_with_subkey\\subkey\\subsubkey",
3239 "torturedataex_with_subkey\\subkey\\subsubkey:0",
3240 "torturedataex_with_subkey\\subkey\\subsubkey:1",
3244 /* FIXME: not working with s3 atm. */
3251 enum winreg_Type types
[] = {
3259 for (i
=0; i
< ARRAY_SIZE(keys
); i
++) {
3260 for (t
=0; t
< ARRAY_SIZE(types
); t
++) {
3264 enum winreg_Type type
;
3265 const char *string
= "I have no idea";
3266 DATA_BLOB blob
= data_blob_string_const("catfoobar");
3267 uint32_t value
= 12345678;
3268 const char **subkeys
;
3269 union spoolss_PrinterData data
;
3271 r
.in
.handle
= handle
;
3272 r
.in
.key_name
= keys
[i
];
3273 r
.in
.value_name
= value_name
;
3274 r
.in
.type
= types
[t
];
3278 r
.in
.data
.binary
= blob
;
3281 r
.in
.data
.value
= value
;
3284 r
.in
.data
.string
= string
;
3287 torture_fail(tctx
, talloc_asprintf(tctx
, "type %d untested\n", types
[t
]));
3290 torture_comment(tctx
, "Testing SetPrinterDataEx(%s - %s) type %d\n", r
.in
.key_name
, value_name
, types
[t
]);
3292 status
= dcerpc_spoolss_SetPrinterDataEx(p
, tctx
, &r
);
3294 torture_assert_ntstatus_ok(tctx
, status
, "SetPrinterDataEx failed");
3295 torture_assert_werr_ok(tctx
, r
.out
.result
, "SetPrinterDataEx failed");
3297 key
= talloc_strdup(tctx
, r
.in
.key_name
);
3299 if (!test_GetPrinterDataEx(tctx
, p
, handle
, r
.in
.key_name
, value_name
, &type
, &data
)) {
3303 torture_assert_int_equal(tctx
, r
.in
.type
, type
, "type mismatch");
3307 torture_assert_data_blob_equal(tctx
, blob
, data
.binary
, "data mismatch");
3310 torture_assert_int_equal(tctx
, value
, data
.value
, "data mismatch");
3313 torture_assert_str_equal(tctx
, string
, data
.string
, "data mismatch");
3316 torture_fail(tctx
, talloc_asprintf(tctx
, "type %d untested\n", type
));
3319 if (!test_EnumPrinterDataEx(tctx
, p
, handle
, r
.in
.key_name
)) {
3323 if (!test_DeletePrinterDataEx(tctx
, p
, handle
, r
.in
.key_name
, value_name
)) {
3327 c
= strchr(key
, '\\');
3331 /* we have subkeys */
3335 if (!test_EnumPrinterKey(tctx
, p
, handle
, key
, &subkeys
)) {
3339 for (i
=0; subkeys
&& subkeys
[i
]; i
++) {
3341 const char *current_key
= talloc_asprintf(tctx
, "%s\\%s", key
, subkeys
[i
]);
3343 if (!test_DeletePrinterKey(tctx
, p
, handle
, current_key
)) {
3348 if (!test_DeletePrinterKey(tctx
, p
, handle
, key
)) {
3353 if (!test_DeletePrinterKey(tctx
, p
, handle
, key
)) {
3363 static bool test_GetChangeID_PrinterData(struct torture_context
*tctx
,
3364 struct dcerpc_pipe
*p
,
3365 struct policy_handle
*handle
,
3366 uint32_t *change_id
)
3368 enum winreg_Type type
;
3369 union spoolss_PrinterData data
;
3371 torture_assert(tctx
,
3372 test_GetPrinterData(tctx
, p
, handle
, "ChangeID", &type
, &data
),
3373 "failed to call GetPrinterData");
3375 torture_assert(tctx
, type
== REG_DWORD
, "unexpected type");
3377 *change_id
= data
.value
;
3382 static bool test_GetChangeID_PrinterDataEx(struct torture_context
*tctx
,
3383 struct dcerpc_pipe
*p
,
3384 struct policy_handle
*handle
,
3385 uint32_t *change_id
)
3387 enum winreg_Type type
;
3388 union spoolss_PrinterData data
;
3390 torture_assert(tctx
,
3391 test_GetPrinterDataEx(tctx
, p
, handle
, "PrinterDriverData", "ChangeID", &type
, &data
),
3392 "failed to call GetPrinterData");
3394 torture_assert(tctx
, type
== REG_DWORD
, "unexpected type");
3396 *change_id
= data
.value
;
3401 static bool test_GetChangeID_PrinterInfo(struct torture_context
*tctx
,
3402 struct dcerpc_pipe
*p
,
3403 struct policy_handle
*handle
,
3404 uint32_t *change_id
)
3406 union spoolss_PrinterInfo info
;
3408 torture_assert(tctx
, test_GetPrinter_level(tctx
, p
, handle
, 0, &info
),
3409 "failed to query Printer level 0");
3411 *change_id
= info
.info0
.change_id
;
3416 static bool test_ChangeID(struct torture_context
*tctx
,
3417 struct dcerpc_pipe
*p
,
3418 struct policy_handle
*handle
)
3420 uint32_t change_id
, change_id_ex
, change_id_info
;
3421 uint32_t change_id2
, change_id_ex2
, change_id_info2
;
3422 union spoolss_PrinterInfo info
;
3423 const char *comment
;
3426 torture_comment(tctx
, "Testing ChangeID: id change test #1\n");
3428 torture_assert(tctx
, test_GetChangeID_PrinterData(tctx
, p
, handle
, &change_id
),
3429 "failed to query for ChangeID");
3430 torture_assert(tctx
, test_GetChangeID_PrinterDataEx(tctx
, p
, handle
, &change_id_ex
),
3431 "failed to query for ChangeID");
3432 torture_assert(tctx
, test_GetChangeID_PrinterInfo(tctx
, p
, handle
, &change_id_info
),
3433 "failed to query for ChangeID");
3435 torture_assert_int_equal(tctx
, change_id
, change_id_ex
,
3436 "change_ids should all be equal");
3437 torture_assert_int_equal(tctx
, change_id_ex
, change_id_info
,
3438 "change_ids should all be equal");
3441 torture_comment(tctx
, "Testing ChangeID: id change test #2\n");
3443 torture_assert(tctx
, test_GetChangeID_PrinterData(tctx
, p
, handle
, &change_id
),
3444 "failed to query for ChangeID");
3445 torture_assert(tctx
, test_GetPrinter_level(tctx
, p
, handle
, 2, &info
),
3446 "failed to query Printer level 2");
3447 torture_assert(tctx
, test_GetChangeID_PrinterDataEx(tctx
, p
, handle
, &change_id_ex
),
3448 "failed to query for ChangeID");
3449 torture_assert(tctx
, test_GetChangeID_PrinterInfo(tctx
, p
, handle
, &change_id_info
),
3450 "failed to query for ChangeID");
3451 torture_assert_int_equal(tctx
, change_id
, change_id_ex
,
3452 "change_id should not have changed");
3453 torture_assert_int_equal(tctx
, change_id_ex
, change_id_info
,
3454 "change_id should not have changed");
3457 torture_comment(tctx
, "Testing ChangeID: id change test #3\n");
3459 torture_assert(tctx
, test_GetChangeID_PrinterData(tctx
, p
, handle
, &change_id
),
3460 "failed to query for ChangeID");
3461 torture_assert(tctx
, test_GetChangeID_PrinterDataEx(tctx
, p
, handle
, &change_id_ex
),
3462 "failed to query for ChangeID");
3463 torture_assert(tctx
, test_GetChangeID_PrinterInfo(tctx
, p
, handle
, &change_id_info
),
3464 "failed to query for ChangeID");
3465 torture_assert(tctx
, test_GetPrinter_level(tctx
, p
, handle
, 2, &info
),
3466 "failed to query Printer level 2");
3467 comment
= talloc_strdup(tctx
, info
.info2
.comment
);
3470 struct spoolss_SetPrinterInfoCtr info_ctr
;
3471 struct spoolss_DevmodeContainer devmode_ctr
;
3472 struct sec_desc_buf secdesc_ctr
;
3473 struct spoolss_SetPrinterInfo2 info2
;
3475 ZERO_STRUCT(info_ctr
);
3476 ZERO_STRUCT(devmode_ctr
);
3477 ZERO_STRUCT(secdesc_ctr
);
3479 info2
.servername
= info
.info2
.servername
;
3480 info2
.printername
= info
.info2
.printername
;
3481 info2
.sharename
= info
.info2
.sharename
;
3482 info2
.portname
= info
.info2
.portname
;
3483 info2
.drivername
= info
.info2
.drivername
;
3484 info2
.comment
= "torture_comment";
3485 info2
.location
= info
.info2
.location
;
3486 info2
.devmode_ptr
= 0;
3487 info2
.sepfile
= info
.info2
.sepfile
;
3488 info2
.printprocessor
= info
.info2
.printprocessor
;
3489 info2
.datatype
= info
.info2
.datatype
;
3490 info2
.parameters
= info
.info2
.parameters
;
3491 info2
.secdesc_ptr
= 0;
3492 info2
.attributes
= info
.info2
.attributes
;
3493 info2
.priority
= info
.info2
.priority
;
3494 info2
.defaultpriority
= info
.info2
.defaultpriority
;
3495 info2
.starttime
= info
.info2
.starttime
;
3496 info2
.untiltime
= info
.info2
.untiltime
;
3497 info2
.status
= info
.info2
.status
;
3498 info2
.cjobs
= info
.info2
.cjobs
;
3499 info2
.averageppm
= info
.info2
.averageppm
;
3502 info_ctr
.info
.info2
= &info2
;
3504 torture_assert(tctx
, test_SetPrinter(tctx
, p
, handle
, &info_ctr
, &devmode_ctr
, &secdesc_ctr
, 0),
3505 "failed to call SetPrinter");
3507 info2
.comment
= comment
;
3509 torture_assert(tctx
, test_SetPrinter(tctx
, p
, handle
, &info_ctr
, &devmode_ctr
, &secdesc_ctr
, 0),
3510 "failed to call SetPrinter");
3514 torture_assert(tctx
, test_GetChangeID_PrinterData(tctx
, p
, handle
, &change_id2
),
3515 "failed to query for ChangeID");
3516 torture_assert(tctx
, test_GetChangeID_PrinterDataEx(tctx
, p
, handle
, &change_id_ex2
),
3517 "failed to query for ChangeID");
3518 torture_assert(tctx
, test_GetChangeID_PrinterInfo(tctx
, p
, handle
, &change_id_info2
),
3519 "failed to query for ChangeID");
3521 torture_assert_int_equal(tctx
, change_id2
, change_id_ex2
,
3522 "change_ids should all be equal");
3523 torture_assert_int_equal(tctx
, change_id_ex2
, change_id_info2
,
3524 "change_ids should all be equal");
3526 torture_assert(tctx
, (change_id
< change_id2
),
3527 talloc_asprintf(tctx
, "change_id %d needs to be larger than change_id %d",
3528 change_id2
, change_id
));
3529 torture_assert(tctx
, (change_id_ex
< change_id_ex2
),
3530 talloc_asprintf(tctx
, "change_id %d needs to be larger than change_id %d",
3531 change_id_ex2
, change_id_ex
));
3532 torture_assert(tctx
, (change_id_info
< change_id_info2
),
3533 talloc_asprintf(tctx
, "change_id %d needs to be larger than change_id %d",
3534 change_id_info2
, change_id_info
));
3539 static bool test_SecondaryClosePrinter(struct torture_context
*tctx
,
3540 struct dcerpc_pipe
*p
,
3541 struct policy_handle
*handle
)
3544 struct dcerpc_binding
*b
;
3545 struct dcerpc_pipe
*p2
;
3546 struct spoolss_ClosePrinter cp
;
3548 /* only makes sense on SMB */
3549 if (p
->conn
->transport
.transport
!= NCACN_NP
) {
3553 torture_comment(tctx
, "testing close on secondary pipe\n");
3555 status
= dcerpc_parse_binding(tctx
, p
->conn
->binding_string
, &b
);
3556 torture_assert_ntstatus_ok(tctx
, status
, "Failed to parse dcerpc binding");
3558 status
= dcerpc_secondary_connection(p
, &p2
, b
);
3559 torture_assert_ntstatus_ok(tctx
, status
, "Failed to create secondary connection");
3561 status
= dcerpc_bind_auth_none(p2
, &ndr_table_spoolss
);
3562 torture_assert_ntstatus_ok(tctx
, status
, "Failed to create bind on secondary connection");
3564 cp
.in
.handle
= handle
;
3565 cp
.out
.handle
= handle
;
3567 status
= dcerpc_spoolss_ClosePrinter(p2
, tctx
, &cp
);
3568 torture_assert_ntstatus_equal(tctx
, status
, NT_STATUS_NET_WRITE_FAULT
,
3569 "ERROR: Allowed close on secondary connection");
3571 torture_assert_int_equal(tctx
, p2
->last_fault_code
, DCERPC_FAULT_CONTEXT_MISMATCH
,
3572 "Unexpected fault code");
3579 static bool test_OpenPrinter_badname(struct torture_context
*tctx
,
3580 struct dcerpc_pipe
*p
, const char *name
)
3583 struct spoolss_OpenPrinter op
;
3584 struct spoolss_OpenPrinterEx opEx
;
3585 struct policy_handle handle
;
3588 op
.in
.printername
= name
;
3589 op
.in
.datatype
= NULL
;
3590 op
.in
.devmode_ctr
.devmode
= NULL
;
3591 op
.in
.access_mask
= 0;
3592 op
.out
.handle
= &handle
;
3594 torture_comment(tctx
, "\nTesting OpenPrinter(%s) with bad name\n", op
.in
.printername
);
3596 status
= dcerpc_spoolss_OpenPrinter(p
, tctx
, &op
);
3597 torture_assert_ntstatus_ok(tctx
, status
, "OpenPrinter failed");
3598 if (!W_ERROR_EQUAL(WERR_INVALID_PRINTER_NAME
,op
.out
.result
)) {
3599 torture_comment(tctx
, "OpenPrinter(%s) unexpected result[%s] should be WERR_INVALID_PRINTER_NAME\n",
3600 name
, win_errstr(op
.out
.result
));
3603 if (W_ERROR_IS_OK(op
.out
.result
)) {
3604 ret
&=test_ClosePrinter(tctx
, p
, &handle
);
3607 opEx
.in
.printername
= name
;
3608 opEx
.in
.datatype
= NULL
;
3609 opEx
.in
.devmode_ctr
.devmode
= NULL
;
3610 opEx
.in
.access_mask
= 0;
3612 opEx
.in
.userlevel
.level1
= NULL
;
3613 opEx
.out
.handle
= &handle
;
3615 torture_comment(tctx
, "Testing OpenPrinterEx(%s) with bad name\n", opEx
.in
.printername
);
3617 status
= dcerpc_spoolss_OpenPrinterEx(p
, tctx
, &opEx
);
3618 torture_assert_ntstatus_ok(tctx
, status
, "OpenPrinterEx failed");
3619 if (!W_ERROR_EQUAL(WERR_INVALID_PARAM
,opEx
.out
.result
)) {
3620 torture_comment(tctx
, "OpenPrinterEx(%s) unexpected result[%s] should be WERR_INVALID_PARAM\n",
3621 name
, win_errstr(opEx
.out
.result
));
3624 if (W_ERROR_IS_OK(opEx
.out
.result
)) {
3625 ret
&=test_ClosePrinter(tctx
, p
, &handle
);
3631 static bool test_OpenPrinter(struct torture_context
*tctx
,
3632 struct dcerpc_pipe
*p
,
3634 const char *environment
)
3637 struct spoolss_OpenPrinter r
;
3638 struct policy_handle handle
;
3641 r
.in
.printername
= talloc_asprintf(tctx
, "\\\\%s\\%s", dcerpc_server_name(p
), name
);
3642 r
.in
.datatype
= NULL
;
3643 r
.in
.devmode_ctr
.devmode
= NULL
;
3644 r
.in
.access_mask
= SEC_FLAG_MAXIMUM_ALLOWED
;
3645 r
.out
.handle
= &handle
;
3647 torture_comment(tctx
, "Testing OpenPrinter(%s)\n", r
.in
.printername
);
3649 status
= dcerpc_spoolss_OpenPrinter(p
, tctx
, &r
);
3651 torture_assert_ntstatus_ok(tctx
, status
, "OpenPrinter failed");
3653 torture_assert_werr_ok(tctx
, r
.out
.result
, "OpenPrinter failed");
3655 if (!test_GetPrinter(tctx
, p
, &handle
, environment
)) {
3659 if (!torture_setting_bool(tctx
, "samba3", false)) {
3660 if (!test_SecondaryClosePrinter(tctx
, p
, &handle
)) {
3665 if (!test_ClosePrinter(tctx
, p
, &handle
)) {
3672 static bool call_OpenPrinterEx(struct torture_context
*tctx
,
3673 struct dcerpc_pipe
*p
,
3675 struct spoolss_DeviceMode
*devmode
,
3676 struct policy_handle
*handle
)
3678 struct spoolss_OpenPrinterEx r
;
3679 struct spoolss_UserLevel1 userlevel1
;
3682 if (name
&& name
[0]) {
3683 r
.in
.printername
= talloc_asprintf(tctx
, "\\\\%s\\%s",
3684 dcerpc_server_name(p
), name
);
3686 r
.in
.printername
= talloc_asprintf(tctx
, "\\\\%s",
3687 dcerpc_server_name(p
));
3690 r
.in
.datatype
= NULL
;
3691 r
.in
.devmode_ctr
.devmode
= devmode
;
3692 r
.in
.access_mask
= SEC_FLAG_MAXIMUM_ALLOWED
;
3694 r
.in
.userlevel
.level1
= &userlevel1
;
3695 r
.out
.handle
= handle
;
3697 userlevel1
.size
= 1234;
3698 userlevel1
.client
= "hello";
3699 userlevel1
.user
= "spottyfoot!";
3700 userlevel1
.build
= 1;
3701 userlevel1
.major
= 2;
3702 userlevel1
.minor
= 3;
3703 userlevel1
.processor
= 4;
3705 torture_comment(tctx
, "Testing OpenPrinterEx(%s)\n", r
.in
.printername
);
3707 status
= dcerpc_spoolss_OpenPrinterEx(p
, tctx
, &r
);
3709 torture_assert_ntstatus_ok(tctx
, status
, "OpenPrinterEx failed");
3711 torture_assert_werr_ok(tctx
, r
.out
.result
, "OpenPrinterEx failed");
3716 static bool test_OpenPrinterEx(struct torture_context
*tctx
,
3717 struct dcerpc_pipe
*p
,
3719 const char *environment
)
3721 struct policy_handle handle
;
3724 if (!call_OpenPrinterEx(tctx
, p
, name
, NULL
, &handle
)) {
3728 if (!test_PrinterInfo_SD(tctx
, p
, &handle
)) {
3732 if (!test_GetPrinter(tctx
, p
, &handle
, environment
)) {
3736 if (!test_EnumForms(tctx
, p
, &handle
, false)) {
3740 if (!test_AddForm(tctx
, p
, &handle
, false)) {
3744 if (!test_EnumPrinterData(tctx
, p
, &handle
)) {
3748 if (!test_EnumPrinterDataEx(tctx
, p
, &handle
, "PrinterDriverData")) {
3752 if (!test_printer_keys(tctx
, p
, &handle
)) {
3756 if (!test_PausePrinter(tctx
, p
, &handle
)) {
3760 if (!test_DoPrintTest(tctx
, p
, &handle
)) {
3764 if (!test_ResumePrinter(tctx
, p
, &handle
)) {
3768 if (!test_SetPrinterData(tctx
, p
, &handle
)) {
3772 if (!test_SetPrinterDataEx(tctx
, p
, &handle
)) {
3776 if (!torture_setting_bool(tctx
, "samba3", false)) {
3777 if (!test_SecondaryClosePrinter(tctx
, p
, &handle
)) {
3782 if (!test_ClosePrinter(tctx
, p
, &handle
)) {
3789 static bool test_EnumPrinters_old(struct torture_context
*tctx
,
3790 struct dcerpc_pipe
*p
,
3791 const char *environment
)
3793 struct spoolss_EnumPrinters r
;
3795 uint16_t levels
[] = {1, 2, 4, 5};
3799 for (i
=0;i
<ARRAY_SIZE(levels
);i
++) {
3800 union spoolss_PrinterInfo
*info
;
3805 r
.in
.flags
= PRINTER_ENUM_LOCAL
;
3807 r
.in
.level
= levels
[i
];
3810 r
.out
.needed
= &needed
;
3811 r
.out
.count
= &count
;
3814 torture_comment(tctx
, "Testing EnumPrinters level %u\n", r
.in
.level
);
3816 status
= dcerpc_spoolss_EnumPrinters(p
, tctx
, &r
);
3817 torture_assert_ntstatus_ok(tctx
, status
, "EnumPrinters failed");
3819 if (W_ERROR_EQUAL(r
.out
.result
, WERR_INSUFFICIENT_BUFFER
)) {
3820 DATA_BLOB blob
= data_blob_talloc(tctx
, NULL
, needed
);
3821 data_blob_clear(&blob
);
3822 r
.in
.buffer
= &blob
;
3823 r
.in
.offered
= needed
;
3824 status
= dcerpc_spoolss_EnumPrinters(p
, tctx
, &r
);
3827 torture_assert_ntstatus_ok(tctx
, status
, "EnumPrinters failed");
3829 torture_assert_werr_ok(tctx
, r
.out
.result
, "EnumPrinters failed");
3831 CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumPrinters
, info
, r
.in
.level
, count
, lp_iconv_convenience(tctx
->lp_ctx
), needed
, 4);
3834 torture_comment(tctx
, "No printers returned\n");
3838 for (j
=0;j
<count
;j
++) {
3839 if (r
.in
.level
== 1) {
3840 char *unc
= talloc_strdup(tctx
, info
[j
].info1
.name
);
3843 if (unc
[0] == '\\' && unc
[1] == '\\') {
3846 slash
= strchr(unc
, '\\');
3851 if (!test_OpenPrinter(tctx
, p
, name
, environment
)) {
3854 if (!test_OpenPrinterEx(tctx
, p
, name
, environment
)) {
3864 static bool test_GetPrinterDriver(struct torture_context
*tctx
,
3865 struct dcerpc_pipe
*p
,
3866 struct policy_handle
*handle
,
3867 const char *driver_name
)
3869 struct spoolss_GetPrinterDriver r
;
3872 r
.in
.handle
= handle
;
3873 r
.in
.architecture
= "W32X86";
3877 r
.out
.needed
= &needed
;
3879 torture_comment(tctx
, "Testing GetPrinterDriver level %d\n", r
.in
.level
);
3881 torture_assert_ntstatus_ok(tctx
, dcerpc_spoolss_GetPrinterDriver(p
, tctx
, &r
),
3882 "failed to call GetPrinterDriver");
3883 if (W_ERROR_EQUAL(r
.out
.result
, WERR_INSUFFICIENT_BUFFER
)) {
3884 DATA_BLOB blob
= data_blob_talloc(tctx
, NULL
, needed
);
3885 data_blob_clear(&blob
);
3886 r
.in
.buffer
= &blob
;
3887 r
.in
.offered
= needed
;
3888 torture_assert_ntstatus_ok(tctx
, dcerpc_spoolss_GetPrinterDriver(p
, tctx
, &r
),
3889 "failed to call GetPrinterDriver");
3892 torture_assert_werr_ok(tctx
, r
.out
.result
,
3893 "failed to call GetPrinterDriver");
3895 CHECK_NEEDED_SIZE_LEVEL(spoolss_DriverInfo
, r
.out
.info
, r
.in
.level
, lp_iconv_convenience(tctx
->lp_ctx
), needed
, 4);
3900 static bool test_GetPrinterDriver2(struct torture_context
*tctx
,
3901 struct dcerpc_pipe
*p
,
3902 struct policy_handle
*handle
,
3903 const char *driver_name
,
3904 const char *architecture
)
3906 struct spoolss_GetPrinterDriver2 r
;
3907 uint16_t levels
[] = {1, 2, 3, 4, 5, 6, 8, 101 };
3909 uint32_t server_major_version
;
3910 uint32_t server_minor_version
;
3913 r
.in
.handle
= handle
;
3914 r
.in
.architecture
= architecture
;
3915 r
.in
.client_major_version
= 3;
3916 r
.in
.client_minor_version
= 0;
3917 r
.out
.needed
= &needed
;
3918 r
.out
.server_major_version
= &server_major_version
;
3919 r
.out
.server_minor_version
= &server_minor_version
;
3921 for (i
=0;i
<ARRAY_SIZE(levels
);i
++) {
3925 r
.in
.level
= levels
[i
];
3927 torture_comment(tctx
, "Testing GetPrinterDriver2(%s) level %d\n",
3928 driver_name
, r
.in
.level
);
3930 torture_assert_ntstatus_ok(tctx
, dcerpc_spoolss_GetPrinterDriver2(p
, tctx
, &r
),
3931 "failed to call GetPrinterDriver2");
3932 if (W_ERROR_EQUAL(r
.out
.result
, WERR_INSUFFICIENT_BUFFER
)) {
3933 DATA_BLOB blob
= data_blob_talloc(tctx
, NULL
, needed
);
3934 data_blob_clear(&blob
);
3935 r
.in
.buffer
= &blob
;
3936 r
.in
.offered
= needed
;
3937 torture_assert_ntstatus_ok(tctx
, dcerpc_spoolss_GetPrinterDriver2(p
, tctx
, &r
),
3938 "failed to call GetPrinterDriver2");
3941 if (W_ERROR_EQUAL(r
.out
.result
, WERR_INVALID_LEVEL
)) {
3942 switch (r
.in
.level
) {
3951 torture_assert_werr_ok(tctx
, r
.out
.result
,
3952 "failed to call GetPrinterDriver2");
3954 CHECK_NEEDED_SIZE_LEVEL(spoolss_DriverInfo
, r
.out
.info
, r
.in
.level
, lp_iconv_convenience(tctx
->lp_ctx
), needed
, 4);
3960 static bool test_EnumPrinterDrivers_old(struct torture_context
*tctx
,
3961 struct dcerpc_pipe
*p
,
3962 const char *environment
)
3964 struct spoolss_EnumPrinterDrivers r
;
3966 uint16_t levels
[] = {1, 2, 3, 4, 5, 6};
3969 for (i
=0;i
<ARRAY_SIZE(levels
);i
++) {
3973 union spoolss_DriverInfo
*info
;
3975 r
.in
.server
= talloc_asprintf(tctx
, "\\\\%s", dcerpc_server_name(p
));
3976 r
.in
.environment
= environment
;
3977 r
.in
.level
= levels
[i
];
3980 r
.out
.needed
= &needed
;
3981 r
.out
.count
= &count
;
3984 torture_comment(tctx
, "Testing EnumPrinterDrivers level %u\n", r
.in
.level
);
3986 status
= dcerpc_spoolss_EnumPrinterDrivers(p
, tctx
, &r
);
3988 torture_assert_ntstatus_ok(tctx
, status
, "EnumPrinterDrivers failed");
3990 if (W_ERROR_EQUAL(r
.out
.result
, WERR_INSUFFICIENT_BUFFER
)) {
3991 DATA_BLOB blob
= data_blob_talloc(tctx
, NULL
, needed
);
3992 data_blob_clear(&blob
);
3993 r
.in
.buffer
= &blob
;
3994 r
.in
.offered
= needed
;
3995 status
= dcerpc_spoolss_EnumPrinterDrivers(p
, tctx
, &r
);
3998 torture_assert_ntstatus_ok(tctx
, status
, "EnumPrinterDrivers failed");
4000 torture_assert_werr_ok(tctx
, r
.out
.result
, "EnumPrinterDrivers failed");
4003 torture_comment(tctx
, "No printer drivers returned\n");
4007 CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumPrinterDrivers
, info
, r
.in
.level
, count
, lp_iconv_convenience(tctx
->lp_ctx
), needed
, 4);
4013 static bool test_DeletePrinter(struct torture_context
*tctx
,
4014 struct dcerpc_pipe
*p
,
4015 struct policy_handle
*handle
)
4017 struct spoolss_DeletePrinter r
;
4019 torture_comment(tctx
, "Testing DeletePrinter\n");
4021 r
.in
.handle
= handle
;
4023 torture_assert_ntstatus_ok(tctx
, dcerpc_spoolss_DeletePrinter(p
, tctx
, &r
),
4024 "failed to delete printer");
4025 torture_assert_werr_ok(tctx
, r
.out
.result
,
4026 "failed to delete printer");
4031 static bool test_EnumPrinters_findname(struct torture_context
*tctx
,
4032 struct dcerpc_pipe
*p
,
4038 struct spoolss_EnumPrinters e
;
4040 union spoolss_PrinterInfo
*info
;
4051 e
.out
.count
= &count
;
4053 e
.out
.needed
= &needed
;
4055 torture_assert_ntstatus_ok(tctx
, dcerpc_spoolss_EnumPrinters(p
, tctx
, &e
),
4056 "failed to enum printers");
4058 if (W_ERROR_EQUAL(e
.out
.result
, WERR_INSUFFICIENT_BUFFER
)) {
4059 DATA_BLOB blob
= data_blob_talloc(tctx
, NULL
, needed
);
4060 data_blob_clear(&blob
);
4061 e
.in
.buffer
= &blob
;
4062 e
.in
.offered
= needed
;
4064 torture_assert_ntstatus_ok(tctx
, dcerpc_spoolss_EnumPrinters(p
, tctx
, &e
),
4065 "failed to enum printers");
4068 torture_assert_werr_ok(tctx
, e
.out
.result
,
4069 "failed to enum printers");
4071 for (i
=0; i
< count
; i
++) {
4073 const char *current
= NULL
;
4078 current
= info
[i
].info1
.name
;
4082 if (strequal(current
, name
)) {
4087 p
= strrchr(current
, '\\');
4090 torture_warning(tctx
,
4091 "server returns printername %s incl. servername although we did not set servername", current
);
4094 if (strequal(p
, name
)) {
4104 static bool test_AddPrinter_wellknown(struct torture_context
*tctx
,
4105 struct dcerpc_pipe
*p
,
4106 const char *printername
,
4110 struct spoolss_AddPrinter r
;
4111 struct spoolss_AddPrinterEx rex
;
4112 struct spoolss_SetPrinterInfoCtr info_ctr
;
4113 struct spoolss_SetPrinterInfo1 info1
;
4114 struct spoolss_DevmodeContainer devmode_ctr
;
4115 struct sec_desc_buf secdesc_ctr
;
4116 struct spoolss_UserLevelCtr userlevel_ctr
;
4117 struct policy_handle handle
;
4120 ZERO_STRUCT(devmode_ctr
);
4121 ZERO_STRUCT(secdesc_ctr
);
4122 ZERO_STRUCT(userlevel_ctr
);
4125 torture_comment(tctx
, "Testing AddPrinter%s level 1\n", ex
? "Ex":"");
4127 /* try to add printer to wellknown printer list (level 1) */
4129 userlevel_ctr
.level
= 1;
4131 info_ctr
.info
.info1
= &info1
;
4134 rex
.in
.server
= NULL
;
4135 rex
.in
.info_ctr
= &info_ctr
;
4136 rex
.in
.devmode_ctr
= &devmode_ctr
;
4137 rex
.in
.secdesc_ctr
= &secdesc_ctr
;
4138 rex
.in
.userlevel_ctr
= &userlevel_ctr
;
4139 rex
.out
.handle
= &handle
;
4142 r
.in
.info_ctr
= &info_ctr
;
4143 r
.in
.devmode_ctr
= &devmode_ctr
;
4144 r
.in
.secdesc_ctr
= &secdesc_ctr
;
4145 r
.out
.handle
= &handle
;
4147 torture_assert_ntstatus_ok(tctx
, ex
? dcerpc_spoolss_AddPrinterEx(p
, tctx
, &rex
) :
4148 dcerpc_spoolss_AddPrinter(p
, tctx
, &r
),
4149 "failed to add printer");
4150 result
= ex
? rex
.out
.result
: r
.out
.result
;
4151 torture_assert_werr_equal(tctx
, result
, WERR_INVALID_PRINTER_NAME
,
4152 "unexpected result code");
4154 info1
.name
= printername
;
4155 info1
.flags
= PRINTER_ATTRIBUTE_SHARED
;
4157 torture_assert_ntstatus_ok(tctx
, ex
? dcerpc_spoolss_AddPrinterEx(p
, tctx
, &rex
) :
4158 dcerpc_spoolss_AddPrinter(p
, tctx
, &r
),
4159 "failed to add printer");
4160 result
= ex
? rex
.out
.result
: r
.out
.result
;
4161 torture_assert_werr_equal(tctx
, result
, WERR_PRINTER_ALREADY_EXISTS
,
4162 "unexpected result code");
4164 /* bizarre protocol, WERR_PRINTER_ALREADY_EXISTS means success here,
4165 better do a real check to see the printer is really there */
4167 torture_assert(tctx
, test_EnumPrinters_findname(tctx
, p
,
4168 PRINTER_ENUM_NETWORK
, 1,
4171 "failed to enum printers");
4173 torture_assert(tctx
, found
, "failed to find newly added printer");
4177 torture_assert_ntstatus_ok(tctx
, ex
? dcerpc_spoolss_AddPrinterEx(p
, tctx
, &rex
) :
4178 dcerpc_spoolss_AddPrinter(p
, tctx
, &r
),
4179 "failed to add printer");
4180 result
= ex
? rex
.out
.result
: r
.out
.result
;
4181 torture_assert_werr_equal(tctx
, result
, WERR_PRINTER_ALREADY_EXISTS
,
4182 "unexpected result code");
4184 /* bizarre protocol, WERR_PRINTER_ALREADY_EXISTS means success here,
4185 better do a real check to see the printer has really been removed
4186 from the well known printer list */
4190 torture_assert(tctx
, test_EnumPrinters_findname(tctx
, p
,
4191 PRINTER_ENUM_NETWORK
, 1,
4194 "failed to enum printers");
4196 torture_assert(tctx
, !found
, "printer still in well known printer list");
4201 static bool test_AddPrinter_normal(struct torture_context
*tctx
,
4202 struct dcerpc_pipe
*p
,
4203 struct policy_handle
*handle_p
,
4204 const char *printername
,
4205 const char *drivername
,
4206 const char *portname
,
4210 struct spoolss_AddPrinter r
;
4211 struct spoolss_AddPrinterEx rex
;
4212 struct spoolss_SetPrinterInfoCtr info_ctr
;
4213 struct spoolss_SetPrinterInfo2 info2
;
4214 struct spoolss_DevmodeContainer devmode_ctr
;
4215 struct sec_desc_buf secdesc_ctr
;
4216 struct spoolss_UserLevelCtr userlevel_ctr
;
4217 struct policy_handle handle
;
4219 bool existing_printer_deleted
= false;
4221 ZERO_STRUCT(devmode_ctr
);
4222 ZERO_STRUCT(secdesc_ctr
);
4223 ZERO_STRUCT(userlevel_ctr
);
4225 torture_comment(tctx
, "Testing AddPrinter%s level 2\n", ex
? "Ex":"");
4227 userlevel_ctr
.level
= 1;
4229 rex
.in
.server
= NULL
;
4230 rex
.in
.info_ctr
= &info_ctr
;
4231 rex
.in
.devmode_ctr
= &devmode_ctr
;
4232 rex
.in
.secdesc_ctr
= &secdesc_ctr
;
4233 rex
.in
.userlevel_ctr
= &userlevel_ctr
;
4234 rex
.out
.handle
= &handle
;
4237 r
.in
.info_ctr
= &info_ctr
;
4238 r
.in
.devmode_ctr
= &devmode_ctr
;
4239 r
.in
.secdesc_ctr
= &secdesc_ctr
;
4240 r
.out
.handle
= &handle
;
4244 /* try to add printer to printer list (level 2) */
4248 info_ctr
.info
.info2
= &info2
;
4251 torture_assert_ntstatus_ok(tctx
, ex
? dcerpc_spoolss_AddPrinterEx(p
, tctx
, &rex
) :
4252 dcerpc_spoolss_AddPrinter(p
, tctx
, &r
),
4253 "failed to add printer");
4254 result
= ex
? rex
.out
.result
: r
.out
.result
;
4255 torture_assert_werr_equal(tctx
, result
, WERR_INVALID_PRINTER_NAME
,
4256 "unexpected result code");
4258 info2
.printername
= printername
;
4260 torture_assert_ntstatus_ok(tctx
, ex
? dcerpc_spoolss_AddPrinterEx(p
, tctx
, &rex
) :
4261 dcerpc_spoolss_AddPrinter(p
, tctx
, &r
),
4262 "failed to add printer");
4263 result
= ex
? rex
.out
.result
: r
.out
.result
;
4265 if (W_ERROR_EQUAL(result
, WERR_PRINTER_ALREADY_EXISTS
)) {
4266 struct policy_handle printer_handle
;
4268 if (existing_printer_deleted
) {
4269 torture_fail(tctx
, "already deleted printer still existing?");
4272 torture_assert(tctx
, call_OpenPrinterEx(tctx
, p
, printername
, NULL
, &printer_handle
),
4273 "failed to open printer handle");
4275 torture_assert(tctx
, test_DeletePrinter(tctx
, p
, &printer_handle
),
4276 "failed to delete printer");
4278 torture_assert(tctx
, test_ClosePrinter(tctx
, p
, &printer_handle
),
4279 "failed to close server handle");
4281 existing_printer_deleted
= true;
4286 torture_assert_werr_equal(tctx
, result
, WERR_UNKNOWN_PORT
,
4287 "unexpected result code");
4289 info2
.portname
= portname
;
4291 torture_assert_ntstatus_ok(tctx
, ex
? dcerpc_spoolss_AddPrinterEx(p
, tctx
, &rex
) :
4292 dcerpc_spoolss_AddPrinter(p
, tctx
, &r
),
4293 "failed to add printer");
4294 result
= ex
? rex
.out
.result
: r
.out
.result
;
4295 torture_assert_werr_equal(tctx
, result
, WERR_UNKNOWN_PRINTER_DRIVER
,
4296 "unexpected result code");
4298 info2
.drivername
= drivername
;
4300 torture_assert_ntstatus_ok(tctx
, ex
? dcerpc_spoolss_AddPrinterEx(p
, tctx
, &rex
) :
4301 dcerpc_spoolss_AddPrinter(p
, tctx
, &r
),
4302 "failed to add printer");
4303 result
= ex
? rex
.out
.result
: r
.out
.result
;
4305 /* w2k8r2 allows to add printer w/o defining printprocessor */
4307 if (!W_ERROR_IS_OK(result
)) {
4308 torture_assert_werr_equal(tctx
, result
, WERR_UNKNOWN_PRINTPROCESSOR
,
4309 "unexpected result code");
4311 info2
.printprocessor
= "winprint";
4313 torture_assert_ntstatus_ok(tctx
, ex
? dcerpc_spoolss_AddPrinterEx(p
, tctx
, &rex
) :
4314 dcerpc_spoolss_AddPrinter(p
, tctx
, &r
),
4315 "failed to add printer");
4316 result
= ex
? rex
.out
.result
: r
.out
.result
;
4317 torture_assert_werr_ok(tctx
, result
,
4318 "failed to add printer");
4323 /* we are paranoid, really check if the printer is there now */
4325 torture_assert(tctx
, test_EnumPrinters_findname(tctx
, p
,
4326 PRINTER_ENUM_LOCAL
, 1,
4329 "failed to enum printers");
4330 torture_assert(tctx
, found
, "failed to find newly added printer");
4332 torture_assert_ntstatus_ok(tctx
, ex
? dcerpc_spoolss_AddPrinterEx(p
, tctx
, &rex
) :
4333 dcerpc_spoolss_AddPrinter(p
, tctx
, &r
),
4334 "failed to add printer");
4335 result
= ex
? rex
.out
.result
: r
.out
.result
;
4336 torture_assert_werr_equal(tctx
, result
, WERR_PRINTER_ALREADY_EXISTS
,
4337 "unexpected result code");
4342 static bool test_AddPrinterEx(struct torture_context
*tctx
,
4343 struct dcerpc_pipe
*p
,
4344 struct policy_handle
*handle_p
,
4345 const char *printername
,
4346 const char *drivername
,
4347 const char *portname
)
4351 if (!torture_setting_bool(tctx
, "samba3", false)) {
4352 if (!test_AddPrinter_wellknown(tctx
, p
, TORTURE_WELLKNOWN_PRINTER_EX
, true)) {
4353 torture_comment(tctx
, "failed to add printer to well known list\n");
4358 if (!test_AddPrinter_normal(tctx
, p
, handle_p
,
4359 printername
, drivername
, portname
,
4361 torture_comment(tctx
, "failed to add printer to printer list\n");
4368 static bool test_AddPrinter(struct torture_context
*tctx
,
4369 struct dcerpc_pipe
*p
,
4370 struct policy_handle
*handle_p
,
4371 const char *printername
,
4372 const char *drivername
,
4373 const char *portname
)
4377 if (!torture_setting_bool(tctx
, "samba3", false)) {
4378 if (!test_AddPrinter_wellknown(tctx
, p
, TORTURE_WELLKNOWN_PRINTER
, false)) {
4379 torture_comment(tctx
, "failed to add printer to well known list\n");
4384 if (!test_AddPrinter_normal(tctx
, p
, handle_p
,
4385 printername
, drivername
, portname
,
4387 torture_comment(tctx
, "failed to add printer to printer list\n");
4394 static bool test_printer_info(struct torture_context
*tctx
,
4395 struct dcerpc_pipe
*p
,
4396 struct policy_handle
*handle
)
4400 if (torture_setting_bool(tctx
, "samba3", false)) {
4401 torture_skip(tctx
, "skipping printer info cross tests against samba 3");
4404 if (!test_PrinterInfo(tctx
, p
, handle
)) {
4408 if (!test_SetPrinter_errors(tctx
, p
, handle
)) {
4415 static bool test_EnumPrinterKey(struct torture_context
*tctx
,
4416 struct dcerpc_pipe
*p
,
4417 struct policy_handle
*handle
,
4418 const char *key_name
,
4419 const char ***array
)
4421 struct spoolss_EnumPrinterKey r
;
4422 uint32_t needed
= 0;
4423 union spoolss_KeyNames key_buffer
;
4424 int32_t offered
[] = { 0, 1, 2, 3, 4, 5, -1, -2, -3, -4, -5, 256, 512, 1024, 2048 };
4428 r
.in
.handle
= handle
;
4429 r
.in
.key_name
= key_name
;
4430 r
.out
.key_buffer
= &key_buffer
;
4431 r
.out
.needed
= &needed
;
4432 r
.out
._ndr_size
= &_ndr_size
;
4434 for (i
=0; i
< ARRAY_SIZE(offered
); i
++) {
4436 if (offered
[i
] < 0 && needed
) {
4440 r
.in
.offered
= needed
+ offered
[i
];
4442 r
.in
.offered
= offered
[i
];
4445 ZERO_STRUCT(key_buffer
);
4447 torture_comment(tctx
, "Testing EnumPrinterKey(%s) with %d offered\n", r
.in
.key_name
, r
.in
.offered
);
4449 torture_assert_ntstatus_ok(tctx
, dcerpc_spoolss_EnumPrinterKey(p
, tctx
, &r
),
4450 "failed to call EnumPrinterKey");
4451 if (W_ERROR_EQUAL(r
.out
.result
, WERR_MORE_DATA
)) {
4453 torture_assert(tctx
, (_ndr_size
== r
.in
.offered
/2),
4454 talloc_asprintf(tctx
, "EnumPrinterKey size mismatch, _ndr_size %d (expected %d)",
4455 _ndr_size
, r
.in
.offered
/2));
4457 r
.in
.offered
= needed
;
4458 torture_assert_ntstatus_ok(tctx
, dcerpc_spoolss_EnumPrinterKey(p
, tctx
, &r
),
4459 "failed to call EnumPrinterKey");
4462 if (offered
[i
] > 0) {
4463 torture_assert_werr_ok(tctx
, r
.out
.result
,
4464 "failed to call EnumPrinterKey");
4467 torture_assert(tctx
, (_ndr_size
== r
.in
.offered
/2),
4468 talloc_asprintf(tctx
, "EnumPrinterKey size mismatch, _ndr_size %d (expected %d)",
4469 _ndr_size
, r
.in
.offered
/2));
4471 torture_assert(tctx
, (*r
.out
.needed
<= r
.in
.offered
),
4472 talloc_asprintf(tctx
, "EnumPrinterKey size mismatch: needed %d is not <= offered %d", *r
.out
.needed
, r
.in
.offered
));
4474 torture_assert(tctx
, (*r
.out
.needed
<= _ndr_size
* 2),
4475 talloc_asprintf(tctx
, "EnumPrinterKey size mismatch: needed %d is not <= _ndr_size %d * 2", *r
.out
.needed
, _ndr_size
));
4477 if (key_buffer
.string_array
) {
4478 uint32_t calc_needed
= 0;
4480 for (s
=0; key_buffer
.string_array
[s
]; s
++) {
4481 calc_needed
+= strlen_m_term(key_buffer
.string_array
[s
])*2;
4483 if (!key_buffer
.string_array
[0]) {
4488 torture_assert_int_equal(tctx
, *r
.out
.needed
, calc_needed
,
4489 "EnumPrinterKey unexpected size");
4494 *array
= key_buffer
.string_array
;
4500 bool test_printer_keys(struct torture_context
*tctx
,
4501 struct dcerpc_pipe
*p
,
4502 struct policy_handle
*handle
)
4504 const char **key_array
= NULL
;
4507 torture_comment(tctx
, "\nTesting Printer Keys\n");
4509 torture_assert(tctx
, test_EnumPrinterKey(tctx
, p
, handle
, "", &key_array
),
4510 "failed to call test_EnumPrinterKey");
4512 for (i
=0; key_array
&& key_array
[i
]; i
++) {
4513 torture_assert(tctx
, test_EnumPrinterKey(tctx
, p
, handle
, key_array
[i
], NULL
),
4514 "failed to call test_EnumPrinterKey");
4516 for (i
=0; key_array
&& key_array
[i
]; i
++) {
4517 torture_assert(tctx
, test_EnumPrinterDataEx(tctx
, p
, handle
, key_array
[i
]),
4518 "failed to call test_EnumPrinterDataEx");
4524 static bool test_one_printer(struct torture_context
*tctx
,
4525 struct dcerpc_pipe
*p
,
4526 struct policy_handle
*handle
,
4531 if (!test_printer_info(tctx
, p
, handle
)) {
4535 if (!test_PrinterInfo_SD(tctx
, p
, handle
)) {
4539 if (!test_PrinterInfo_DevMode(tctx
, p
, handle
, name
)) {
4543 if (!test_ChangeID(tctx
, p
, handle
)) {
4547 if (!test_printer_keys(tctx
, p
, handle
)) {
4554 static bool test_printer(struct torture_context
*tctx
,
4555 struct dcerpc_pipe
*p
)
4558 struct policy_handle handle
[2];
4560 const char *drivername
= "Microsoft XPS Document Writer";
4561 const char *portname
= "LPT1:";
4563 /* test printer created via AddPrinter */
4565 if (!test_AddPrinter(tctx
, p
, &handle
[0], TORTURE_PRINTER
, drivername
, portname
)) {
4569 if (!test_one_printer(tctx
, p
, &handle
[0], TORTURE_PRINTER
)) {
4573 if (!test_DeletePrinter(tctx
, p
, &handle
[0])) {
4577 if (!test_EnumPrinters_findname(tctx
, p
, PRINTER_ENUM_LOCAL
, 1,
4578 TORTURE_PRINTER
, &found
)) {
4582 torture_assert(tctx
, !found
, "deleted printer still there");
4584 /* test printer created via AddPrinterEx */
4586 if (!test_AddPrinterEx(tctx
, p
, &handle
[1], TORTURE_PRINTER_EX
, drivername
, portname
)) {
4590 if (!test_one_printer(tctx
, p
, &handle
[1], TORTURE_PRINTER_EX
)) {
4594 if (!test_DeletePrinter(tctx
, p
, &handle
[1])) {
4598 if (!test_EnumPrinters_findname(tctx
, p
, PRINTER_ENUM_LOCAL
, 1,
4599 TORTURE_PRINTER_EX
, &found
)) {
4603 torture_assert(tctx
, !found
, "deleted printer still there");
4608 static bool test_architecture_buffer(struct torture_context
*tctx
,
4609 struct dcerpc_pipe
*p
)
4611 struct spoolss_OpenPrinterEx r
;
4612 struct spoolss_UserLevel1 u1
;
4613 struct policy_handle handle
;
4614 uint32_t architectures
[] = {
4615 PROCESSOR_ARCHITECTURE_INTEL
,
4616 PROCESSOR_ARCHITECTURE_IA64
,
4617 PROCESSOR_ARCHITECTURE_AMD64
4622 for (i
=0; i
< ARRAY_SIZE(architectures
); i
++) {
4624 torture_comment(tctx
, "Testing OpenPrinterEx with architecture %d\n", architectures
[i
]);
4632 u1
.processor
= architectures
[i
];
4634 r
.in
.printername
= talloc_asprintf(tctx
, "\\\\%s", dcerpc_server_name(p
));
4635 r
.in
.datatype
= NULL
;
4636 r
.in
.devmode_ctr
.devmode
= NULL
;
4637 r
.in
.access_mask
= SEC_FLAG_MAXIMUM_ALLOWED
;
4639 r
.in
.userlevel
.level1
= &u1
;
4640 r
.out
.handle
= &handle
;
4642 torture_assert_ntstatus_ok(tctx
, dcerpc_spoolss_OpenPrinterEx(p
, tctx
, &r
), "");
4643 torture_assert_werr_ok(tctx
, r
.out
.result
, "");
4646 struct spoolss_EnumPrinters e
;
4648 union spoolss_PrinterInfo
*info
;
4650 e
.in
.flags
= PRINTER_ENUM_LOCAL
;
4655 e
.out
.count
= &count
;
4657 e
.out
.needed
= &needed
[i
];
4659 torture_assert_ntstatus_ok(tctx
, dcerpc_spoolss_EnumPrinters(p
, tctx
, &e
), "");
4661 torture_comment(tctx
, "needed was %d\n", needed
[i
]);
4665 torture_assert(tctx
, test_ClosePrinter(tctx
, p
, &handle
), "");
4668 for (i
=1; i
< ARRAY_SIZE(architectures
); i
++) {
4669 if (needed
[i
-1] != needed
[i
]) {
4671 talloc_asprintf(tctx
, "needed size %d for architecture %d != needed size %d for architecture %d\n",
4672 needed
[i
-1], architectures
[i
-1], needed
[i
], architectures
[i
]));
4679 bool torture_rpc_spoolss(struct torture_context
*torture
)
4682 struct dcerpc_pipe
*p
;
4684 struct test_spoolss_context
*ctx
;
4685 const char *environment
= SPOOLSS_ARCHITECTURE_NT_X86
;
4687 status
= torture_rpc_connection(torture
, &p
, &ndr_table_spoolss
);
4688 if (!NT_STATUS_IS_OK(status
)) {
4692 ctx
= talloc_zero(torture
, struct test_spoolss_context
);
4694 ret
&= test_OpenPrinter_server(torture
, p
, &ctx
->server_handle
);
4695 ret
&= test_GetPrinterData_list(torture
, p
, &ctx
->server_handle
);
4696 ret
&= test_EnumForms(torture
, p
, &ctx
->server_handle
, true);
4697 ret
&= test_AddForm(torture
, p
, &ctx
->server_handle
, true);
4698 ret
&= test_EnumPorts(torture
, p
, ctx
);
4699 ret
&= test_GetPrinterDriverDirectory(torture
, p
, ctx
, environment
);
4700 ret
&= test_GetPrintProcessorDirectory(torture
, p
, ctx
, environment
);
4701 ret
&= test_EnumPrinterDrivers(torture
, p
, ctx
, environment
);
4702 ret
&= test_EnumPrinterDrivers(torture
, p
, ctx
, SPOOLSS_ARCHITECTURE_ALL
);
4703 ret
&= test_EnumMonitors(torture
, p
, ctx
);
4704 ret
&= test_EnumPrintProcessors(torture
, p
, ctx
, environment
);
4705 ret
&= test_EnumPrintProcDataTypes(torture
, p
, ctx
);
4706 ret
&= test_EnumPrinters(torture
, p
, ctx
);
4707 ret
&= test_OpenPrinter_badname(torture
, p
, "__INVALID_PRINTER__");
4708 ret
&= test_OpenPrinter_badname(torture
, p
, "\\\\__INVALID_HOST__");
4709 ret
&= test_OpenPrinter_badname(torture
, p
, "");
4710 ret
&= test_OpenPrinter_badname(torture
, p
, "\\\\\\");
4711 ret
&= test_OpenPrinter_badname(torture
, p
, "\\\\\\__INVALID_PRINTER__");
4712 ret
&= test_OpenPrinter_badname(torture
, p
, talloc_asprintf(torture
, "\\\\%s\\", dcerpc_server_name(p
)));
4713 ret
&= test_OpenPrinter_badname(torture
, p
,
4714 talloc_asprintf(torture
, "\\\\%s\\__INVALID_PRINTER__", dcerpc_server_name(p
)));
4717 ret
&= test_AddPort(torture
, p
);
4718 ret
&= test_EnumPorts_old(torture
, p
);
4719 ret
&= test_EnumPrinters_old(torture
, p
, environment
);
4720 ret
&= test_EnumPrinterDrivers_old(torture
, p
, environment
);
4721 ret
&= test_architecture_buffer(torture
, p
);
4726 struct torture_suite
*torture_rpc_spoolss_printer(TALLOC_CTX
*mem_ctx
)
4728 struct torture_suite
*suite
= torture_suite_create(mem_ctx
, "SPOOLSS-PRINTER");
4730 struct torture_rpc_tcase
*tcase
= torture_suite_add_rpc_iface_tcase(suite
,
4731 "printer", &ndr_table_spoolss
);
4733 torture_rpc_tcase_add_test(tcase
, "printer", test_printer
);