s4-smbtorture: more work on devicemode tests.
[Samba/cd1.git] / source4 / torture / rpc / spoolss.c
blob0a915a78f5a72917e8c4475a1ca5aceecf3c9992
1 /*
2 Unix SMB/CIFS implementation.
3 test suite for spoolss rpc operations
5 Copyright (C) Tim Potter 2003
6 Copyright (C) Stefan Metzmacher 2005
7 Copyright (C) Jelmer Vernooij 2007
8 Copyright (C) Guenther Deschner 2009-2010
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 3 of the License, or
13 (at your option) any later version.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program. If not, see <http://www.gnu.org/licenses/>.
24 #include "includes.h"
25 #include "torture/torture.h"
26 #include "librpc/gen_ndr/ndr_misc.h"
27 #include "librpc/gen_ndr/ndr_spoolss.h"
28 #include "librpc/gen_ndr/ndr_spoolss_c.h"
29 #include "librpc/gen_ndr/ndr_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;
43 /* for EnumPorts */
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__() */
68 #if (__GNUC__ >= 3)
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"); \
76 } while(0)
77 #else
78 #define _CHECK_FIELD_SIZE(c,r,e,type) do {} while(0)
79 #endif
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"); \
84 } while(0)
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"); \
89 } while(0)
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"); \
95 } while(0)
97 #define COMPARE_STRING_ARRAY(tctx, c,r,e) do {\
98 int __i; \
99 if (!c.e && !r.e) { \
100 break; \
102 if (c.e && !r.e) { \
103 torture_fail(tctx, #r "." #e " field is NULL and " #c "." #e " is not\n"); \
105 if (!c.e && r.e) { \
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"); \
111 } while(0)
113 #define CHECK_ALIGN(size, n) do {\
114 if (size % n) {\
115 torture_warning(tctx, "%d is *NOT* %d byte aligned, should be %d",\
116 size, n, size + n - (size % n));\
118 } while(0)
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);\
131 } while(0)
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);\
142 } while(0)
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);\
153 } while(0)
155 static bool test_OpenPrinter_server(struct torture_context *tctx,
156 struct dcerpc_pipe *p,
157 struct policy_handle *server_handle)
159 NTSTATUS status;
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");
174 return true;
177 static bool test_EnumPorts(struct torture_context *tctx,
178 struct dcerpc_pipe *p,
179 struct test_spoolss_context *ctx)
181 NTSTATUS status;
182 struct spoolss_EnumPorts r;
183 uint16_t levels[] = { 1, 2 };
184 int i, j;
186 for (i=0;i<ARRAY_SIZE(levels);i++) {
187 int level = levels[i];
188 DATA_BLOB blob;
189 uint32_t needed;
190 uint32_t count;
191 union spoolss_PortInfo *info;
193 r.in.servername = "";
194 r.in.level = level;
195 r.in.buffer = NULL;
196 r.in.offered = 0;
197 r.out.needed = &needed;
198 r.out.count = &count;
199 r.out.info = &info;
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 */
207 continue;
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);
214 r.in.buffer = &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];
243 switch (level) {
244 case 1:
245 COMPARE_STRING(tctx, cur->info1, ref->info2, port_name);
246 break;
247 case 2:
248 /* level 2 is our reference, and it makes no sense to compare it to itself */
249 break;
254 return true;
257 static bool test_GetPrintProcessorDirectory(struct torture_context *tctx,
258 struct dcerpc_pipe *p,
259 struct test_spoolss_context *ctx)
261 NTSTATUS status;
262 struct spoolss_GetPrintProcessorDirectory r;
263 struct {
264 uint16_t level;
265 const char *server;
266 } levels[] = {{
267 .level = 1,
268 .server = NULL
270 .level = 1,
271 .server = ""
273 .level = 78,
274 .server = ""
276 .level = 1,
277 .server = talloc_asprintf(ctx, "\\\\%s", dcerpc_server_name(p))
279 .level = 1024,
280 .server = talloc_asprintf(ctx, "\\\\%s", dcerpc_server_name(p))
283 int i;
284 uint32_t needed;
286 for (i=0;i<ARRAY_SIZE(levels);i++) {
287 int level = levels[i].level;
288 DATA_BLOB blob;
290 r.in.server = levels[i].server;
291 r.in.environment = SPOOLSS_ARCHITECTURE_NT_X86;
292 r.in.level = level;
293 r.in.buffer = NULL;
294 r.in.offered = 0;
295 r.out.needed = &needed;
297 torture_comment(tctx, "Testing GetPrintProcessorDirectory level %u\n", r.in.level);
299 status = dcerpc_spoolss_GetPrintProcessorDirectory(p, ctx, &r);
300 torture_assert_ntstatus_ok(tctx, status,
301 "dcerpc_spoolss_GetPrintProcessorDirectory failed");
302 torture_assert_werr_equal(tctx, r.out.result, WERR_INSUFFICIENT_BUFFER,
303 "GetPrintProcessorDirectory unexpected return code");
305 blob = data_blob_talloc(ctx, NULL, needed);
306 data_blob_clear(&blob);
307 r.in.buffer = &blob;
308 r.in.offered = needed;
310 status = dcerpc_spoolss_GetPrintProcessorDirectory(p, ctx, &r);
311 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_GetPrintProcessorDirectory failed");
313 torture_assert_werr_ok(tctx, r.out.result, "GetPrintProcessorDirectory failed");
315 CHECK_NEEDED_SIZE_LEVEL(spoolss_PrintProcessorDirectoryInfo, r.out.info, r.in.level, lp_iconv_convenience(tctx->lp_ctx), needed, 2);
318 return true;
322 static bool test_GetPrinterDriverDirectory(struct torture_context *tctx,
323 struct dcerpc_pipe *p,
324 struct test_spoolss_context *ctx)
326 NTSTATUS status;
327 struct spoolss_GetPrinterDriverDirectory r;
328 struct {
329 uint16_t level;
330 const char *server;
331 } levels[] = {{
332 .level = 1,
333 .server = NULL
335 .level = 1,
336 .server = ""
338 .level = 78,
339 .server = ""
341 .level = 1,
342 .server = talloc_asprintf(ctx, "\\\\%s", dcerpc_server_name(p))
344 .level = 1024,
345 .server = talloc_asprintf(ctx, "\\\\%s", dcerpc_server_name(p))
348 int i;
349 uint32_t needed;
351 for (i=0;i<ARRAY_SIZE(levels);i++) {
352 int level = levels[i].level;
353 DATA_BLOB blob;
355 r.in.server = levels[i].server;
356 r.in.environment = SPOOLSS_ARCHITECTURE_NT_X86;
357 r.in.level = level;
358 r.in.buffer = NULL;
359 r.in.offered = 0;
360 r.out.needed = &needed;
362 torture_comment(tctx, "Testing GetPrinterDriverDirectory level %u\n", r.in.level);
364 status = dcerpc_spoolss_GetPrinterDriverDirectory(p, ctx, &r);
365 torture_assert_ntstatus_ok(tctx, status,
366 "dcerpc_spoolss_GetPrinterDriverDirectory failed");
367 torture_assert_werr_equal(tctx, r.out.result, WERR_INSUFFICIENT_BUFFER,
368 "GetPrinterDriverDirectory unexpected return code");
370 blob = data_blob_talloc(ctx, NULL, needed);
371 data_blob_clear(&blob);
372 r.in.buffer = &blob;
373 r.in.offered = needed;
375 status = dcerpc_spoolss_GetPrinterDriverDirectory(p, ctx, &r);
376 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_GetPrinterDriverDirectory failed");
378 torture_assert_werr_ok(tctx, r.out.result, "GetPrinterDriverDirectory failed");
380 CHECK_NEEDED_SIZE_LEVEL(spoolss_DriverDirectoryInfo, r.out.info, r.in.level, lp_iconv_convenience(tctx->lp_ctx), needed, 2);
383 return true;
386 static bool test_EnumPrinterDrivers(struct torture_context *tctx,
387 struct dcerpc_pipe *p,
388 struct test_spoolss_context *ctx,
389 const char *architecture)
391 NTSTATUS status;
392 struct spoolss_EnumPrinterDrivers r;
393 uint16_t levels[] = { 1, 2, 3, 4, 5, 6, 8 };
394 int i, j;
396 for (i=0;i<ARRAY_SIZE(levels);i++) {
397 int level = levels[i];
398 DATA_BLOB blob;
399 uint32_t needed;
400 uint32_t count;
401 union spoolss_DriverInfo *info;
403 /* FIXME: gd, come back and fix "" as server, and handle
404 * priority of returned error codes in torture test and samba 3
405 * server */
407 r.in.server = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
408 r.in.environment = architecture;
409 r.in.level = level;
410 r.in.buffer = NULL;
411 r.in.offered = 0;
412 r.out.needed = &needed;
413 r.out.count = &count;
414 r.out.info = &info;
416 torture_comment(tctx, "Testing EnumPrinterDrivers level %u (%s)\n", r.in.level, r.in.environment);
418 status = dcerpc_spoolss_EnumPrinterDrivers(p, ctx, &r);
419 torture_assert_ntstatus_ok(tctx, status,
420 "dcerpc_spoolss_EnumPrinterDrivers failed");
421 if (W_ERROR_IS_OK(r.out.result)) {
422 /* TODO: do some more checks here */
423 continue;
425 if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
426 blob = data_blob_talloc(ctx, NULL, needed);
427 data_blob_clear(&blob);
428 r.in.buffer = &blob;
429 r.in.offered = needed;
431 status = dcerpc_spoolss_EnumPrinterDrivers(p, ctx, &r);
432 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EnumPrinterDrivers failed");
435 torture_assert_werr_ok(tctx, r.out.result, "EnumPrinterDrivers failed");
437 CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumPrinterDrivers, info, r.in.level, count, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
439 ctx->driver_count[level] = count;
440 ctx->drivers[level] = info;
443 for (i=1;i<ARRAY_SIZE(levels);i++) {
444 int level = levels[i];
445 int old_level = levels[i-1];
447 torture_assert_int_equal(tctx, ctx->driver_count[level], ctx->driver_count[old_level],
448 "EnumPrinterDrivers invalid value");
451 for (i=0;i<ARRAY_SIZE(levels);i++) {
452 int level = levels[i];
454 for (j=0;j<ctx->driver_count[level];j++) {
455 union spoolss_DriverInfo *cur = &ctx->drivers[level][j];
456 union spoolss_DriverInfo *ref = &ctx->drivers[8][j];
458 switch (level) {
459 case 1:
460 COMPARE_STRING(tctx, cur->info1, ref->info8, driver_name);
461 break;
462 case 2:
463 COMPARE_UINT32(tctx, cur->info2, ref->info8, version);
464 COMPARE_STRING(tctx, cur->info2, ref->info8, driver_name);
465 COMPARE_STRING(tctx, cur->info2, ref->info8, architecture);
466 COMPARE_STRING(tctx, cur->info2, ref->info8, driver_path);
467 COMPARE_STRING(tctx, cur->info2, ref->info8, data_file);
468 COMPARE_STRING(tctx, cur->info2, ref->info8, config_file);
469 break;
470 case 3:
471 COMPARE_UINT32(tctx, cur->info3, ref->info8, version);
472 COMPARE_STRING(tctx, cur->info3, ref->info8, driver_name);
473 COMPARE_STRING(tctx, cur->info3, ref->info8, architecture);
474 COMPARE_STRING(tctx, cur->info3, ref->info8, driver_path);
475 COMPARE_STRING(tctx, cur->info3, ref->info8, data_file);
476 COMPARE_STRING(tctx, cur->info3, ref->info8, config_file);
477 COMPARE_STRING(tctx, cur->info3, ref->info8, help_file);
478 COMPARE_STRING_ARRAY(tctx, cur->info3, ref->info8, dependent_files);
479 COMPARE_STRING(tctx, cur->info3, ref->info8, monitor_name);
480 COMPARE_STRING(tctx, cur->info3, ref->info8, default_datatype);
481 break;
482 case 4:
483 COMPARE_UINT32(tctx, cur->info4, ref->info8, version);
484 COMPARE_STRING(tctx, cur->info4, ref->info8, driver_name);
485 COMPARE_STRING(tctx, cur->info4, ref->info8, architecture);
486 COMPARE_STRING(tctx, cur->info4, ref->info8, driver_path);
487 COMPARE_STRING(tctx, cur->info4, ref->info8, data_file);
488 COMPARE_STRING(tctx, cur->info4, ref->info8, config_file);
489 COMPARE_STRING(tctx, cur->info4, ref->info8, help_file);
490 COMPARE_STRING_ARRAY(tctx, cur->info4, ref->info8, dependent_files);
491 COMPARE_STRING(tctx, cur->info4, ref->info8, monitor_name);
492 COMPARE_STRING(tctx, cur->info4, ref->info8, default_datatype);
493 COMPARE_STRING_ARRAY(tctx, cur->info4, ref->info8, previous_names);
494 break;
495 case 5:
496 COMPARE_UINT32(tctx, cur->info5, ref->info8, version);
497 COMPARE_STRING(tctx, cur->info5, ref->info8, driver_name);
498 COMPARE_STRING(tctx, cur->info5, ref->info8, architecture);
499 COMPARE_STRING(tctx, cur->info5, ref->info8, driver_path);
500 COMPARE_STRING(tctx, cur->info5, ref->info8, data_file);
501 COMPARE_STRING(tctx, cur->info5, ref->info8, config_file);
502 /*COMPARE_UINT32(tctx, cur->info5, ref->info8, driver_attributes);*/
503 /*COMPARE_UINT32(tctx, cur->info5, ref->info8, config_version);*/
504 /*TODO: ! COMPARE_UINT32(tctx, cur->info5, ref->info8, driver_version); */
505 break;
506 case 6:
507 COMPARE_UINT32(tctx, cur->info6, ref->info8, version);
508 COMPARE_STRING(tctx, cur->info6, ref->info8, driver_name);
509 COMPARE_STRING(tctx, cur->info6, ref->info8, architecture);
510 COMPARE_STRING(tctx, cur->info6, ref->info8, driver_path);
511 COMPARE_STRING(tctx, cur->info6, ref->info8, data_file);
512 COMPARE_STRING(tctx, cur->info6, ref->info8, config_file);
513 COMPARE_STRING(tctx, cur->info6, ref->info8, help_file);
514 COMPARE_STRING_ARRAY(tctx, cur->info6, ref->info8, dependent_files);
515 COMPARE_STRING(tctx, cur->info6, ref->info8, monitor_name);
516 COMPARE_STRING(tctx, cur->info6, ref->info8, default_datatype);
517 COMPARE_STRING_ARRAY(tctx, cur->info6, ref->info8, previous_names);
518 COMPARE_NTTIME(tctx, cur->info6, ref->info8, driver_date);
519 COMPARE_UINT64(tctx, cur->info6, ref->info8, driver_version);
520 COMPARE_STRING(tctx, cur->info6, ref->info8, manufacturer_name);
521 COMPARE_STRING(tctx, cur->info6, ref->info8, manufacturer_url);
522 COMPARE_STRING(tctx, cur->info6, ref->info8, hardware_id);
523 COMPARE_STRING(tctx, cur->info6, ref->info8, provider);
524 break;
525 case 8:
526 /* level 8 is our reference, and it makes no sense to compare it to itself */
527 break;
532 return true;
535 static bool test_EnumMonitors(struct torture_context *tctx,
536 struct dcerpc_pipe *p,
537 struct test_spoolss_context *ctx)
539 NTSTATUS status;
540 struct spoolss_EnumMonitors r;
541 uint16_t levels[] = { 1, 2 };
542 int i, j;
544 for (i=0;i<ARRAY_SIZE(levels);i++) {
545 int level = levels[i];
546 DATA_BLOB blob;
547 uint32_t needed;
548 uint32_t count;
549 union spoolss_MonitorInfo *info;
551 r.in.servername = "";
552 r.in.level = level;
553 r.in.buffer = NULL;
554 r.in.offered = 0;
555 r.out.needed = &needed;
556 r.out.count = &count;
557 r.out.info = &info;
559 torture_comment(tctx, "Testing EnumMonitors level %u\n", r.in.level);
561 status = dcerpc_spoolss_EnumMonitors(p, ctx, &r);
562 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EnumMonitors failed");
563 if (W_ERROR_IS_OK(r.out.result)) {
564 /* TODO: do some more checks here */
565 continue;
567 torture_assert_werr_equal(tctx, r.out.result, WERR_INSUFFICIENT_BUFFER,
568 "EnumMonitors failed");
570 blob = data_blob_talloc(ctx, NULL, needed);
571 data_blob_clear(&blob);
572 r.in.buffer = &blob;
573 r.in.offered = needed;
575 status = dcerpc_spoolss_EnumMonitors(p, ctx, &r);
576 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EnumMonitors failed");
578 torture_assert_werr_ok(tctx, r.out.result, "EnumMonitors failed");
580 CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumMonitors, info, r.in.level, count, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
582 ctx->monitor_count[level] = count;
583 ctx->monitors[level] = info;
586 for (i=1;i<ARRAY_SIZE(levels);i++) {
587 int level = levels[i];
588 int old_level = levels[i-1];
589 torture_assert_int_equal(tctx, ctx->monitor_count[level], ctx->monitor_count[old_level],
590 "EnumMonitors invalid value");
593 for (i=0;i<ARRAY_SIZE(levels);i++) {
594 int level = levels[i];
595 for (j=0;j<ctx->monitor_count[level];j++) {
596 union spoolss_MonitorInfo *cur = &ctx->monitors[level][j];
597 union spoolss_MonitorInfo *ref = &ctx->monitors[2][j];
598 switch (level) {
599 case 1:
600 COMPARE_STRING(tctx, cur->info1, ref->info2, monitor_name);
601 break;
602 case 2:
603 /* level 2 is our reference, and it makes no sense to compare it to itself */
604 break;
609 return true;
612 static bool test_EnumPrintProcessors(struct torture_context *tctx,
613 struct dcerpc_pipe *p,
614 struct test_spoolss_context *ctx)
616 NTSTATUS status;
617 struct spoolss_EnumPrintProcessors r;
618 uint16_t levels[] = { 1 };
619 int i, j;
621 for (i=0;i<ARRAY_SIZE(levels);i++) {
622 int level = levels[i];
623 DATA_BLOB blob;
624 uint32_t needed;
625 uint32_t count;
626 union spoolss_PrintProcessorInfo *info;
628 r.in.servername = "";
629 r.in.environment = SPOOLSS_ARCHITECTURE_NT_X86;
630 r.in.level = level;
631 r.in.buffer = NULL;
632 r.in.offered = 0;
633 r.out.needed = &needed;
634 r.out.count = &count;
635 r.out.info = &info;
637 torture_comment(tctx, "Testing EnumPrintProcessors level %u\n", r.in.level);
639 status = dcerpc_spoolss_EnumPrintProcessors(p, ctx, &r);
640 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EnumPrintProcessors failed");
641 if (W_ERROR_IS_OK(r.out.result)) {
642 /* TODO: do some more checks here */
643 continue;
645 torture_assert_werr_equal(tctx, r.out.result, WERR_INSUFFICIENT_BUFFER,
646 "EnumPrintProcessors unexpected return code");
648 blob = data_blob_talloc(ctx, NULL, needed);
649 data_blob_clear(&blob);
650 r.in.buffer = &blob;
651 r.in.offered = needed;
653 status = dcerpc_spoolss_EnumPrintProcessors(p, ctx, &r);
654 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EnumPrintProcessors failed");
656 torture_assert_werr_ok(tctx, r.out.result, "EnumPrintProcessors failed");
658 CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumPrintProcessors, info, r.in.level, count, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
660 ctx->print_processor_count[level] = count;
661 ctx->print_processors[level] = info;
664 for (i=1;i<ARRAY_SIZE(levels);i++) {
665 int level = levels[i];
666 int old_level = levels[i-1];
667 torture_assert_int_equal(tctx, ctx->print_processor_count[level], ctx->print_processor_count[old_level],
668 "EnumPrintProcessors failed");
671 for (i=0;i<ARRAY_SIZE(levels);i++) {
672 int level = levels[i];
673 for (j=0;j<ctx->print_processor_count[level];j++) {
674 #if 0
675 union spoolss_PrintProcessorInfo *cur = &ctx->print_processors[level][j];
676 union spoolss_PrintProcessorInfo *ref = &ctx->print_processors[1][j];
677 #endif
678 switch (level) {
679 case 1:
680 /* level 1 is our reference, and it makes no sense to compare it to itself */
681 break;
686 return true;
689 static bool test_EnumPrintProcDataTypes(struct torture_context *tctx,
690 struct dcerpc_pipe *p,
691 struct test_spoolss_context *ctx)
693 NTSTATUS status;
694 struct spoolss_EnumPrintProcDataTypes r;
695 uint16_t levels[] = { 1 };
696 int i;
698 for (i=0;i<ARRAY_SIZE(levels);i++) {
699 int level = levels[i];
700 DATA_BLOB blob;
701 uint32_t needed;
702 uint32_t count;
703 union spoolss_PrintProcDataTypesInfo *info;
705 r.in.servername = "";
706 r.in.print_processor_name = "winprint";
707 r.in.level = level;
708 r.in.buffer = NULL;
709 r.in.offered = 0;
710 r.out.needed = &needed;
711 r.out.count = &count;
712 r.out.info = &info;
714 torture_comment(tctx, "Testing EnumPrintProcDataTypes level %u\n", r.in.level);
716 status = dcerpc_spoolss_EnumPrintProcDataTypes(p, ctx, &r);
717 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EnumPrintProcDataType failed");
718 if (W_ERROR_IS_OK(r.out.result)) {
719 /* TODO: do some more checks here */
720 continue;
722 torture_assert_werr_equal(tctx, r.out.result, WERR_INSUFFICIENT_BUFFER,
723 "EnumPrintProcDataTypes unexpected return code");
725 blob = data_blob_talloc(ctx, NULL, needed);
726 data_blob_clear(&blob);
727 r.in.buffer = &blob;
728 r.in.offered = needed;
730 status = dcerpc_spoolss_EnumPrintProcDataTypes(p, ctx, &r);
731 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EnumPrintProcDataTypes failed");
733 torture_assert_werr_ok(tctx, r.out.result, "EnumPrintProcDataTypes failed");
735 CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumPrintProcDataTypes, info, r.in.level, count, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
739 return true;
743 static bool test_EnumPrinters(struct torture_context *tctx,
744 struct dcerpc_pipe *p,
745 struct test_spoolss_context *ctx)
747 struct spoolss_EnumPrinters r;
748 NTSTATUS status;
749 uint16_t levels[] = { 0, 1, 2, 4, 5 };
750 int i, j;
752 for (i=0;i<ARRAY_SIZE(levels);i++) {
753 int level = levels[i];
754 DATA_BLOB blob;
755 uint32_t needed;
756 uint32_t count;
757 union spoolss_PrinterInfo *info;
759 r.in.flags = PRINTER_ENUM_LOCAL;
760 r.in.server = "";
761 r.in.level = level;
762 r.in.buffer = NULL;
763 r.in.offered = 0;
764 r.out.needed = &needed;
765 r.out.count = &count;
766 r.out.info = &info;
768 torture_comment(tctx, "Testing EnumPrinters level %u\n", r.in.level);
770 status = dcerpc_spoolss_EnumPrinters(p, ctx, &r);
771 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EnumPrinters failed");
772 if (W_ERROR_IS_OK(r.out.result)) {
773 /* TODO: do some more checks here */
774 continue;
776 torture_assert_werr_equal(tctx, r.out.result, WERR_INSUFFICIENT_BUFFER,
777 "EnumPrinters unexpected return code");
779 blob = data_blob_talloc(ctx, NULL, needed);
780 data_blob_clear(&blob);
781 r.in.buffer = &blob;
782 r.in.offered = needed;
784 status = dcerpc_spoolss_EnumPrinters(p, ctx, &r);
785 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EnumPrinters failed");
787 torture_assert_werr_ok(tctx, r.out.result, "EnumPrinters failed");
789 CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumPrinters, info, r.in.level, count, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
791 ctx->printer_count[level] = count;
792 ctx->printers[level] = info;
795 for (i=1;i<ARRAY_SIZE(levels);i++) {
796 int level = levels[i];
797 int old_level = levels[i-1];
798 torture_assert_int_equal(tctx, ctx->printer_count[level], ctx->printer_count[old_level],
799 "EnumPrinters invalid value");
802 for (i=0;i<ARRAY_SIZE(levels);i++) {
803 int level = levels[i];
804 for (j=0;j<ctx->printer_count[level];j++) {
805 union spoolss_PrinterInfo *cur = &ctx->printers[level][j];
806 union spoolss_PrinterInfo *ref = &ctx->printers[2][j];
807 switch (level) {
808 case 0:
809 COMPARE_STRING(tctx, cur->info0, ref->info2, printername);
810 COMPARE_STRING(tctx, cur->info0, ref->info2, servername);
811 COMPARE_UINT32(tctx, cur->info0, ref->info2, cjobs);
812 /*COMPARE_UINT32(tctx, cur->info0, ref->info2, total_jobs);
813 COMPARE_UINT32(tctx, cur->info0, ref->info2, total_bytes);
814 COMPARE_SPOOLSS_TIME(cur->info0, ref->info2, spoolss_Time time);
815 COMPARE_UINT32(tctx, cur->info0, ref->info2, global_counter);
816 COMPARE_UINT32(tctx, cur->info0, ref->info2, total_pages);
817 COMPARE_UINT32(tctx, cur->info0, ref->info2, version);
818 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown10);
819 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown11);
820 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown12);
821 COMPARE_UINT32(tctx, cur->info0, ref->info2, session_counter);
822 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown14);
823 COMPARE_UINT32(tctx, cur->info0, ref->info2, printer_errors);
824 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown16);
825 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown17);
826 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown18);
827 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown19);
828 COMPARE_UINT32(tctx, cur->info0, ref->info2, change_id);
829 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown21);*/
830 COMPARE_UINT32(tctx, cur->info0, ref->info2, status);
831 /*COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown23);
832 COMPARE_UINT32(tctx, cur->info0, ref->info2, c_setprinter);
833 COMPARE_UINT16(cur->info0, ref->info2, unknown25);
834 COMPARE_UINT16(cur->info0, ref->info2, unknown26);
835 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown27);
836 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown28);
837 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown29);*/
838 break;
839 case 1:
840 /*COMPARE_UINT32(tctx, cur->info1, ref->info2, flags);*/
841 /*COMPARE_STRING(tctx, cur->info1, ref->info2, name);*/
842 /*COMPARE_STRING(tctx, cur->info1, ref->info2, description);*/
843 COMPARE_STRING(tctx, cur->info1, ref->info2, comment);
844 break;
845 case 2:
846 /* level 2 is our reference, and it makes no sense to compare it to itself */
847 break;
848 case 4:
849 COMPARE_STRING(tctx, cur->info4, ref->info2, printername);
850 COMPARE_STRING(tctx, cur->info4, ref->info2, servername);
851 COMPARE_UINT32(tctx, cur->info4, ref->info2, attributes);
852 break;
853 case 5:
854 COMPARE_STRING(tctx, cur->info5, ref->info2, printername);
855 COMPARE_STRING(tctx, cur->info5, ref->info2, portname);
856 COMPARE_UINT32(tctx, cur->info5, ref->info2, attributes);
857 /*COMPARE_UINT32(tctx, cur->info5, ref->info2, device_not_selected_timeout);
858 COMPARE_UINT32(tctx, cur->info5, ref->info2, transmission_retry_timeout);*/
859 break;
864 /* TODO:
865 * - verify that the port of a printer was in the list returned by EnumPorts
868 return true;
871 static bool test_GetPrinterDriver2(struct torture_context *tctx,
872 struct dcerpc_pipe *p,
873 struct policy_handle *handle,
874 const char *driver_name);
876 bool test_GetPrinter_level(struct torture_context *tctx,
877 struct dcerpc_pipe *p,
878 struct policy_handle *handle,
879 uint32_t level,
880 union spoolss_PrinterInfo *info)
882 struct spoolss_GetPrinter r;
883 uint32_t needed;
885 r.in.handle = handle;
886 r.in.level = level;
887 r.in.buffer = NULL;
888 r.in.offered = 0;
889 r.out.needed = &needed;
891 torture_comment(tctx, "Testing GetPrinter level %u\n", r.in.level);
893 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_GetPrinter(p, tctx, &r),
894 "GetPrinter failed");
896 if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
897 DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed);
898 data_blob_clear(&blob);
899 r.in.buffer = &blob;
900 r.in.offered = needed;
902 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_GetPrinter(p, tctx, &r),
903 "GetPrinter failed");
906 torture_assert_werr_ok(tctx, r.out.result, "GetPrinter failed");
908 CHECK_NEEDED_SIZE_LEVEL(spoolss_PrinterInfo, r.out.info, r.in.level, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
910 if (info && r.out.info) {
911 *info = *r.out.info;
914 return true;
918 static bool test_GetPrinter(struct torture_context *tctx,
919 struct dcerpc_pipe *p,
920 struct policy_handle *handle)
922 uint32_t levels[] = {0, 1, 2, 3, 4, 5, 6, 7, 8};
923 int i;
925 for (i=0;i<ARRAY_SIZE(levels);i++) {
927 union spoolss_PrinterInfo info;
929 ZERO_STRUCT(info);
931 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, levels[i], &info),
932 "failed to call GetPrinter");
934 if ((levels[i] == 2) && info.info2.drivername && strlen(info.info2.drivername)) {
935 torture_assert(tctx,
936 test_GetPrinterDriver2(tctx, p, handle, info.info2.drivername),
937 "failed to call test_GetPrinterDriver2");
941 return true;
944 static bool test_SetPrinter(struct torture_context *tctx,
945 struct dcerpc_pipe *p,
946 struct policy_handle *handle,
947 struct spoolss_SetPrinterInfoCtr *info_ctr,
948 struct spoolss_DevmodeContainer *devmode_ctr,
949 struct sec_desc_buf *secdesc_ctr,
950 enum spoolss_PrinterControl command)
952 struct spoolss_SetPrinter r;
954 r.in.handle = handle;
955 r.in.info_ctr = info_ctr;
956 r.in.devmode_ctr = devmode_ctr;
957 r.in.secdesc_ctr = secdesc_ctr;
958 r.in.command = command;
960 torture_comment(tctx, "Testing SetPrinter level %d\n", r.in.info_ctr->level);
962 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_SetPrinter(p, tctx, &r),
963 "failed to call SetPrinter");
964 torture_assert_werr_ok(tctx, r.out.result,
965 "failed to call SetPrinter");
967 return true;
970 static bool test_SetPrinter_errors(struct torture_context *tctx,
971 struct dcerpc_pipe *p,
972 struct policy_handle *handle)
974 struct spoolss_SetPrinter r;
975 uint16_t levels[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
976 int i;
978 struct spoolss_SetPrinterInfoCtr info_ctr;
979 struct spoolss_DevmodeContainer devmode_ctr;
980 struct sec_desc_buf secdesc_ctr;
982 info_ctr.level = 0;
983 info_ctr.info.info0 = NULL;
985 ZERO_STRUCT(devmode_ctr);
986 ZERO_STRUCT(secdesc_ctr);
988 r.in.handle = handle;
989 r.in.info_ctr = &info_ctr;
990 r.in.devmode_ctr = &devmode_ctr;
991 r.in.secdesc_ctr = &secdesc_ctr;
992 r.in.command = 0;
994 torture_comment(tctx, "Testing SetPrinter all zero\n");
996 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_SetPrinter(p, tctx, &r),
997 "failed to call SetPrinter");
998 torture_assert_werr_equal(tctx, r.out.result, WERR_INVALID_PARAM,
999 "failed to call SetPrinter");
1001 again:
1002 for (i=0; i < ARRAY_SIZE(levels); i++) {
1004 struct spoolss_SetPrinterInfo0 info0;
1005 struct spoolss_SetPrinterInfo1 info1;
1006 struct spoolss_SetPrinterInfo2 info2;
1007 struct spoolss_SetPrinterInfo3 info3;
1008 struct spoolss_SetPrinterInfo4 info4;
1009 struct spoolss_SetPrinterInfo5 info5;
1010 struct spoolss_SetPrinterInfo6 info6;
1011 struct spoolss_SetPrinterInfo7 info7;
1012 struct spoolss_SetPrinterInfo8 info8;
1013 struct spoolss_SetPrinterInfo9 info9;
1016 info_ctr.level = levels[i];
1017 switch (levels[i]) {
1018 case 0:
1019 ZERO_STRUCT(info0);
1020 info_ctr.info.info0 = &info0;
1021 break;
1022 case 1:
1023 ZERO_STRUCT(info1);
1024 info_ctr.info.info1 = &info1;
1025 break;
1026 case 2:
1027 ZERO_STRUCT(info2);
1028 info_ctr.info.info2 = &info2;
1029 break;
1030 case 3:
1031 ZERO_STRUCT(info3);
1032 info_ctr.info.info3 = &info3;
1033 break;
1034 case 4:
1035 ZERO_STRUCT(info4);
1036 info_ctr.info.info4 = &info4;
1037 break;
1038 case 5:
1039 ZERO_STRUCT(info5);
1040 info_ctr.info.info5 = &info5;
1041 break;
1042 case 6:
1043 ZERO_STRUCT(info6);
1044 info_ctr.info.info6 = &info6;
1045 break;
1046 case 7:
1047 ZERO_STRUCT(info7);
1048 info_ctr.info.info7 = &info7;
1049 break;
1050 case 8:
1051 ZERO_STRUCT(info8);
1052 info_ctr.info.info8 = &info8;
1053 break;
1054 case 9:
1055 ZERO_STRUCT(info9);
1056 info_ctr.info.info9 = &info9;
1057 break;
1060 torture_comment(tctx, "Testing SetPrinter level %d, command %d\n",
1061 info_ctr.level, r.in.command);
1063 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_SetPrinter(p, tctx, &r),
1064 "failed to call SetPrinter");
1066 switch (r.in.command) {
1067 case SPOOLSS_PRINTER_CONTROL_UNPAUSE: /* 0 */
1068 /* is ignored for all levels other then 0 */
1069 if (info_ctr.level > 0) {
1070 /* ignored then */
1071 break;
1073 case SPOOLSS_PRINTER_CONTROL_PAUSE: /* 1 */
1074 case SPOOLSS_PRINTER_CONTROL_RESUME: /* 2 */
1075 case SPOOLSS_PRINTER_CONTROL_PURGE: /* 3 */
1076 if (info_ctr.level > 0) {
1077 /* is invalid for all levels other then 0 */
1078 torture_assert_werr_equal(tctx, r.out.result, WERR_INVALID_PRINTER_COMMAND,
1079 "unexpected error code returned");
1080 continue;
1081 } else {
1082 torture_assert_werr_ok(tctx, r.out.result,
1083 "failed to call SetPrinter with non 0 command");
1084 continue;
1086 break;
1088 case SPOOLSS_PRINTER_CONTROL_SET_STATUS: /* 4 */
1089 /* FIXME: gd needs further investigation */
1090 default:
1091 torture_assert_werr_equal(tctx, r.out.result, WERR_INVALID_PRINTER_COMMAND,
1092 "unexpected error code returned");
1093 continue;
1096 switch (info_ctr.level) {
1097 case 1:
1098 torture_assert_werr_equal(tctx, r.out.result, WERR_UNKNOWN_LEVEL,
1099 "unexpected error code returned");
1100 break;
1101 case 2:
1102 torture_assert_werr_equal(tctx, r.out.result, WERR_UNKNOWN_PRINTER_DRIVER,
1103 "unexpected error code returned");
1104 break;
1105 case 3:
1106 case 4:
1107 case 5:
1108 case 7:
1109 torture_assert_werr_equal(tctx, r.out.result, WERR_INVALID_PARAM,
1110 "unexpected error code returned");
1111 break;
1112 case 9:
1113 torture_assert_werr_equal(tctx, r.out.result, WERR_NOT_SUPPORTED,
1114 "unexpected error code returned");
1115 break;
1116 default:
1117 torture_assert_werr_ok(tctx, r.out.result,
1118 "failed to call SetPrinter");
1119 break;
1123 if (r.in.command < 5) {
1124 r.in.command++;
1125 goto again;
1128 return true;
1131 static void clear_info2(struct spoolss_SetPrinterInfoCtr *r)
1133 if ((r->level == 2) && (r->info.info2)) {
1134 r->info.info2->secdesc_ptr = 0;
1135 r->info.info2->devmode_ptr = 0;
1139 static bool test_PrinterInfo(struct torture_context *tctx,
1140 struct dcerpc_pipe *p,
1141 struct policy_handle *handle)
1143 NTSTATUS status;
1144 struct spoolss_SetPrinter s;
1145 struct spoolss_GetPrinter q;
1146 struct spoolss_GetPrinter q0;
1147 struct spoolss_SetPrinterInfoCtr info_ctr;
1148 union spoolss_PrinterInfo info;
1149 struct spoolss_DevmodeContainer devmode_ctr;
1150 struct sec_desc_buf secdesc_ctr;
1151 uint32_t needed;
1152 bool ret = true;
1153 int i;
1155 uint32_t status_list[] = {
1156 /* these do not stick
1157 PRINTER_STATUS_PAUSED,
1158 PRINTER_STATUS_ERROR,
1159 PRINTER_STATUS_PENDING_DELETION, */
1160 PRINTER_STATUS_PAPER_JAM,
1161 PRINTER_STATUS_PAPER_OUT,
1162 PRINTER_STATUS_MANUAL_FEED,
1163 PRINTER_STATUS_PAPER_PROBLEM,
1164 PRINTER_STATUS_OFFLINE,
1165 PRINTER_STATUS_IO_ACTIVE,
1166 PRINTER_STATUS_BUSY,
1167 PRINTER_STATUS_PRINTING,
1168 PRINTER_STATUS_OUTPUT_BIN_FULL,
1169 PRINTER_STATUS_NOT_AVAILABLE,
1170 PRINTER_STATUS_WAITING,
1171 PRINTER_STATUS_PROCESSING,
1172 PRINTER_STATUS_INITIALIZING,
1173 PRINTER_STATUS_WARMING_UP,
1174 PRINTER_STATUS_TONER_LOW,
1175 PRINTER_STATUS_NO_TONER,
1176 PRINTER_STATUS_PAGE_PUNT,
1177 PRINTER_STATUS_USER_INTERVENTION,
1178 PRINTER_STATUS_OUT_OF_MEMORY,
1179 PRINTER_STATUS_DOOR_OPEN,
1180 PRINTER_STATUS_SERVER_UNKNOWN,
1181 PRINTER_STATUS_POWER_SAVE,
1182 /* these do not stick
1183 0x02000000,
1184 0x04000000,
1185 0x08000000,
1186 0x10000000,
1187 0x20000000,
1188 0x40000000,
1189 0x80000000 */
1191 uint32_t default_attribute = PRINTER_ATTRIBUTE_LOCAL;
1192 uint32_t attribute_list[] = {
1193 PRINTER_ATTRIBUTE_QUEUED,
1194 /* fails with WERR_INVALID_DATATYPE:
1195 PRINTER_ATTRIBUTE_DIRECT, */
1196 /* does not stick
1197 PRINTER_ATTRIBUTE_DEFAULT, */
1198 PRINTER_ATTRIBUTE_SHARED,
1199 /* does not stick
1200 PRINTER_ATTRIBUTE_NETWORK, */
1201 PRINTER_ATTRIBUTE_HIDDEN,
1202 PRINTER_ATTRIBUTE_LOCAL,
1203 PRINTER_ATTRIBUTE_ENABLE_DEVQ,
1204 PRINTER_ATTRIBUTE_KEEPPRINTEDJOBS,
1205 PRINTER_ATTRIBUTE_DO_COMPLETE_FIRST,
1206 PRINTER_ATTRIBUTE_WORK_OFFLINE,
1207 /* does not stick
1208 PRINTER_ATTRIBUTE_ENABLE_BIDI, */
1209 /* fails with WERR_INVALID_DATATYPE:
1210 PRINTER_ATTRIBUTE_RAW_ONLY, */
1211 /* these do not stick
1212 PRINTER_ATTRIBUTE_PUBLISHED,
1213 PRINTER_ATTRIBUTE_FAX,
1214 PRINTER_ATTRIBUTE_TS,
1215 0x00010000,
1216 0x00020000,
1217 0x00040000,
1218 0x00080000,
1219 0x00100000,
1220 0x00200000,
1221 0x00400000,
1222 0x00800000,
1223 0x01000000,
1224 0x02000000,
1225 0x04000000,
1226 0x08000000,
1227 0x10000000,
1228 0x20000000,
1229 0x40000000,
1230 0x80000000 */
1233 ZERO_STRUCT(devmode_ctr);
1234 ZERO_STRUCT(secdesc_ctr);
1236 s.in.handle = handle;
1237 s.in.command = 0;
1238 s.in.info_ctr = &info_ctr;
1239 s.in.devmode_ctr = &devmode_ctr;
1240 s.in.secdesc_ctr = &secdesc_ctr;
1242 q.in.handle = handle;
1243 q.out.info = &info;
1244 q0 = q;
1246 #define TESTGETCALL(call, r) \
1247 r.in.buffer = NULL; \
1248 r.in.offered = 0;\
1249 r.out.needed = &needed; \
1250 status = dcerpc_spoolss_ ##call(p, tctx, &r); \
1251 if (!NT_STATUS_IS_OK(status)) { \
1252 torture_comment(tctx, #call " level %u failed - %s (%s)\n", \
1253 r.in.level, nt_errstr(status), __location__); \
1254 ret = false; \
1255 break; \
1257 if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {\
1258 DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed); \
1259 data_blob_clear(&blob); \
1260 r.in.buffer = &blob; \
1261 r.in.offered = needed; \
1263 status = dcerpc_spoolss_ ##call(p, tctx, &r); \
1264 if (!NT_STATUS_IS_OK(status)) { \
1265 torture_comment(tctx, #call " level %u failed - %s (%s)\n", \
1266 r.in.level, nt_errstr(status), __location__); \
1267 ret = false; \
1268 break; \
1270 if (!W_ERROR_IS_OK(r.out.result)) { \
1271 torture_comment(tctx, #call " level %u failed - %s (%s)\n", \
1272 r.in.level, win_errstr(r.out.result), __location__); \
1273 ret = false; \
1274 break; \
1278 #define TESTSETCALL_EXP(call, r, err) \
1279 clear_info2(&info_ctr);\
1280 status = dcerpc_spoolss_ ##call(p, tctx, &r); \
1281 if (!NT_STATUS_IS_OK(status)) { \
1282 torture_comment(tctx, #call " level %u failed - %s (%s)\n", \
1283 r.in.info_ctr->level, nt_errstr(status), __location__); \
1284 ret = false; \
1285 break; \
1287 if (!W_ERROR_IS_OK(err)) { \
1288 if (!W_ERROR_EQUAL(err, r.out.result)) { \
1289 torture_comment(tctx, #call " level %u failed - %s, expected %s (%s)\n", \
1290 r.in.info_ctr->level, win_errstr(r.out.result), win_errstr(err), __location__); \
1291 ret = false; \
1293 break; \
1295 if (!W_ERROR_IS_OK(r.out.result)) { \
1296 torture_comment(tctx, #call " level %u failed - %s (%s)\n", \
1297 r.in.info_ctr->level, win_errstr(r.out.result), __location__); \
1298 ret = false; \
1299 break; \
1302 #define TESTSETCALL(call, r) \
1303 TESTSETCALL_EXP(call, r, WERR_OK)
1305 #define STRING_EQUAL(s1, s2, field) \
1306 if ((s1 && !s2) || (s2 && !s1) || strcmp(s1, s2)) { \
1307 torture_comment(tctx, "Failed to set %s to '%s' (%s)\n", \
1308 #field, s2, __location__); \
1309 ret = false; \
1310 break; \
1313 #define MEM_EQUAL(s1, s2, length, field) \
1314 if ((s1 && !s2) || (s2 && !s1) || memcmp(s1, s2, length)) { \
1315 torture_comment(tctx, "Failed to set %s to '%s' (%s)\n", \
1316 #field, (const char *)s2, __location__); \
1317 ret = false; \
1318 break; \
1321 #define INT_EQUAL(i1, i2, field) \
1322 if (i1 != i2) { \
1323 torture_comment(tctx, "Failed to set %s to 0x%llx - got 0x%llx (%s)\n", \
1324 #field, (unsigned long long)i2, (unsigned long long)i1, __location__); \
1325 ret = false; \
1326 break; \
1329 #define SD_EQUAL(sd1, sd2, field) \
1330 if (!security_descriptor_equal(sd1, sd2)) { \
1331 torture_comment(tctx, "Failed to set %s (%s)\n", \
1332 #field, __location__); \
1333 ret = false; \
1334 break; \
1337 #define TEST_PRINTERINFO_STRING_EXP_ERR(lvl1, field1, lvl2, field2, value, err) do { \
1338 torture_comment(tctx, "field test %d/%s vs %d/%s\n", lvl1, #field1, lvl2, #field2); \
1339 q.in.level = lvl1; \
1340 TESTGETCALL(GetPrinter, q) \
1341 info_ctr.level = lvl1; \
1342 info_ctr.info.info ## lvl1 = (struct spoolss_SetPrinterInfo ## lvl1 *)&q.out.info->info ## lvl1; \
1343 info_ctr.info.info ## lvl1->field1 = value;\
1344 TESTSETCALL_EXP(SetPrinter, s, err) \
1345 info_ctr.info.info ## lvl1->field1 = ""; \
1346 TESTGETCALL(GetPrinter, q) \
1347 info_ctr.info.info ## lvl1->field1 = value; \
1348 STRING_EQUAL(info_ctr.info.info ## lvl1->field1, value, field1); \
1349 q.in.level = lvl2; \
1350 TESTGETCALL(GetPrinter, q) \
1351 info_ctr.info.info ## lvl2 = (struct spoolss_SetPrinterInfo ## lvl2 *)&q.out.info->info ## lvl2; \
1352 STRING_EQUAL(info_ctr.info.info ## lvl2->field2, value, field2); \
1353 } while (0)
1355 #define TEST_PRINTERINFO_STRING(lvl1, field1, lvl2, field2, value) do { \
1356 TEST_PRINTERINFO_STRING_EXP_ERR(lvl1, field1, lvl2, field2, value, WERR_OK); \
1357 } while (0);
1359 #define TEST_PRINTERINFO_INT_EXP(lvl1, field1, lvl2, field2, value, exp_value) do { \
1360 torture_comment(tctx, "field test %d/%s vs %d/%s\n", lvl1, #field1, lvl2, #field2); \
1361 q.in.level = lvl1; \
1362 TESTGETCALL(GetPrinter, q) \
1363 info_ctr.level = lvl1; \
1364 info_ctr.info.info ## lvl1 = (struct spoolss_SetPrinterInfo ## lvl1 *)&q.out.info->info ## lvl1; \
1365 info_ctr.info.info ## lvl1->field1 = value; \
1366 TESTSETCALL(SetPrinter, s) \
1367 info_ctr.info.info ## lvl1->field1 = 0; \
1368 TESTGETCALL(GetPrinter, q) \
1369 info_ctr.info.info ## lvl1 = (struct spoolss_SetPrinterInfo ## lvl1 *)&q.out.info->info ## lvl1; \
1370 INT_EQUAL(info_ctr.info.info ## lvl1->field1, exp_value, field1); \
1371 q.in.level = lvl2; \
1372 TESTGETCALL(GetPrinter, q) \
1373 info_ctr.info.info ## lvl2 = (struct spoolss_SetPrinterInfo ## lvl2 *)&q.out.info->info ## lvl2; \
1374 INT_EQUAL(info_ctr.info.info ## lvl2->field2, exp_value, field1); \
1375 } while (0)
1377 #define TEST_PRINTERINFO_INT(lvl1, field1, lvl2, field2, value) do { \
1378 TEST_PRINTERINFO_INT_EXP(lvl1, field1, lvl2, field2, value, value); \
1379 } while (0)
1381 q0.in.level = 0;
1382 do { TESTGETCALL(GetPrinter, q0) } while (0);
1384 TEST_PRINTERINFO_STRING(2, comment, 1, comment, "xx2-1 comment");
1385 TEST_PRINTERINFO_STRING(2, comment, 2, comment, "xx2-2 comment");
1387 /* level 0 printername does not stick */
1388 /* TEST_PRINTERINFO_STRING(2, printername, 0, printername, "xx2-0 printer"); */
1389 TEST_PRINTERINFO_STRING(2, printername, 1, name, "xx2-1 printer");
1390 TEST_PRINTERINFO_STRING(2, printername, 2, printername, "xx2-2 printer");
1391 TEST_PRINTERINFO_STRING(2, printername, 4, printername, "xx2-4 printer");
1392 TEST_PRINTERINFO_STRING(2, printername, 5, printername, "xx2-5 printer");
1393 /* TEST_PRINTERINFO_STRING(4, printername, 0, printername, "xx4-0 printer"); */
1394 TEST_PRINTERINFO_STRING(4, printername, 1, name, "xx4-1 printer");
1395 TEST_PRINTERINFO_STRING(4, printername, 2, printername, "xx4-2 printer");
1396 TEST_PRINTERINFO_STRING(4, printername, 4, printername, "xx4-4 printer");
1397 TEST_PRINTERINFO_STRING(4, printername, 5, printername, "xx4-5 printer");
1398 /* TEST_PRINTERINFO_STRING(5, printername, 0, printername, "xx5-0 printer"); */
1399 TEST_PRINTERINFO_STRING(5, printername, 1, name, "xx5-1 printer");
1400 TEST_PRINTERINFO_STRING(5, printername, 2, printername, "xx5-2 printer");
1401 TEST_PRINTERINFO_STRING(5, printername, 4, printername, "xx5-4 printer");
1402 TEST_PRINTERINFO_STRING(5, printername, 5, printername, "xx5-5 printer");
1404 /* servername can be set but does not stick
1405 TEST_PRINTERINFO_STRING(2, servername, 0, servername, "xx2-0 servername");
1406 TEST_PRINTERINFO_STRING(2, servername, 2, servername, "xx2-2 servername");
1407 TEST_PRINTERINFO_STRING(2, servername, 4, servername, "xx2-4 servername");
1410 /* passing an invalid port will result in WERR_UNKNOWN_PORT */
1411 TEST_PRINTERINFO_STRING_EXP_ERR(2, portname, 2, portname, "xx2-2 portname", WERR_UNKNOWN_PORT);
1412 TEST_PRINTERINFO_STRING_EXP_ERR(2, portname, 5, portname, "xx2-5 portname", WERR_UNKNOWN_PORT);
1413 TEST_PRINTERINFO_STRING_EXP_ERR(5, portname, 2, portname, "xx5-2 portname", WERR_UNKNOWN_PORT);
1414 TEST_PRINTERINFO_STRING_EXP_ERR(5, portname, 5, portname, "xx5-5 portname", WERR_UNKNOWN_PORT);
1416 TEST_PRINTERINFO_STRING(2, sharename, 2, sharename, "xx2-2 sharename");
1417 /* passing an invalid driver will result in WERR_UNKNOWN_PRINTER_DRIVER */
1418 TEST_PRINTERINFO_STRING_EXP_ERR(2, drivername, 2, drivername, "xx2-2 drivername", WERR_UNKNOWN_PRINTER_DRIVER);
1419 TEST_PRINTERINFO_STRING(2, location, 2, location, "xx2-2 location");
1420 /* passing an invalid sepfile will result in WERR_INVALID_SEPARATOR_FILE */
1421 TEST_PRINTERINFO_STRING_EXP_ERR(2, sepfile, 2, sepfile, "xx2-2 sepfile", WERR_INVALID_SEPARATOR_FILE);
1422 /* passing an invalid printprocessor will result in WERR_UNKNOWN_PRINTPROCESSOR */
1423 TEST_PRINTERINFO_STRING_EXP_ERR(2, printprocessor, 2, printprocessor, "xx2-2 printprocessor", WERR_UNKNOWN_PRINTPROCESSOR);
1424 TEST_PRINTERINFO_STRING(2, datatype, 2, datatype, "xx2-2 datatype");
1425 TEST_PRINTERINFO_STRING(2, parameters, 2, parameters, "xx2-2 parameters");
1427 for (i=0; i < ARRAY_SIZE(attribute_list); i++) {
1428 /* TEST_PRINTERINFO_INT_EXP(2, attributes, 1, flags,
1429 attribute_list[i],
1430 (attribute_list[i] | default_attribute)
1431 ); */
1432 TEST_PRINTERINFO_INT_EXP(2, attributes, 2, attributes,
1433 attribute_list[i],
1434 (attribute_list[i] | default_attribute)
1436 TEST_PRINTERINFO_INT_EXP(2, attributes, 4, attributes,
1437 attribute_list[i],
1438 (attribute_list[i] | default_attribute)
1440 TEST_PRINTERINFO_INT_EXP(2, attributes, 5, attributes,
1441 attribute_list[i],
1442 (attribute_list[i] | default_attribute)
1444 /* TEST_PRINTERINFO_INT_EXP(4, attributes, 1, flags,
1445 attribute_list[i],
1446 (attribute_list[i] | default_attribute)
1447 ); */
1448 TEST_PRINTERINFO_INT_EXP(4, attributes, 2, attributes,
1449 attribute_list[i],
1450 (attribute_list[i] | default_attribute)
1452 TEST_PRINTERINFO_INT_EXP(4, attributes, 4, attributes,
1453 attribute_list[i],
1454 (attribute_list[i] | default_attribute)
1456 TEST_PRINTERINFO_INT_EXP(4, attributes, 5, attributes,
1457 attribute_list[i],
1458 (attribute_list[i] | default_attribute)
1460 /* TEST_PRINTERINFO_INT_EXP(5, attributes, 1, flags,
1461 attribute_list[i],
1462 (attribute_list[i] | default_attribute)
1463 ); */
1464 TEST_PRINTERINFO_INT_EXP(5, attributes, 2, attributes,
1465 attribute_list[i],
1466 (attribute_list[i] | default_attribute)
1468 TEST_PRINTERINFO_INT_EXP(5, attributes, 4, attributes,
1469 attribute_list[i],
1470 (attribute_list[i] | default_attribute)
1472 TEST_PRINTERINFO_INT_EXP(5, attributes, 5, attributes,
1473 attribute_list[i],
1474 (attribute_list[i] | default_attribute)
1478 for (i=0; i < ARRAY_SIZE(status_list); i++) {
1479 /* level 2 sets do not stick
1480 TEST_PRINTERINFO_INT(2, status, 0, status, status_list[i]);
1481 TEST_PRINTERINFO_INT(2, status, 2, status, status_list[i]);
1482 TEST_PRINTERINFO_INT(2, status, 6, status, status_list[i]); */
1483 TEST_PRINTERINFO_INT(6, status, 0, status, status_list[i]);
1484 TEST_PRINTERINFO_INT(6, status, 2, status, status_list[i]);
1485 TEST_PRINTERINFO_INT(6, status, 6, status, status_list[i]);
1488 /* priorities need to be between 0 and 99
1489 passing an invalid priority will result in WERR_INVALID_PRIORITY */
1490 TEST_PRINTERINFO_INT(2, priority, 2, priority, 0);
1491 TEST_PRINTERINFO_INT(2, priority, 2, priority, 1);
1492 TEST_PRINTERINFO_INT(2, priority, 2, priority, 99);
1493 /* TEST_PRINTERINFO_INT(2, priority, 2, priority, 100); */
1494 TEST_PRINTERINFO_INT(2, defaultpriority,2, defaultpriority, 0);
1495 TEST_PRINTERINFO_INT(2, defaultpriority,2, defaultpriority, 1);
1496 TEST_PRINTERINFO_INT(2, defaultpriority,2, defaultpriority, 99);
1497 /* TEST_PRINTERINFO_INT(2, defaultpriority,2, defaultpriority, 100); */
1499 TEST_PRINTERINFO_INT(2, starttime, 2, starttime, __LINE__);
1500 TEST_PRINTERINFO_INT(2, untiltime, 2, untiltime, __LINE__);
1502 /* does not stick
1503 TEST_PRINTERINFO_INT(2, cjobs, 2, cjobs, __LINE__);
1504 TEST_PRINTERINFO_INT(2, averageppm, 2, averageppm, __LINE__); */
1506 /* does not stick
1507 TEST_PRINTERINFO_INT(5, device_not_selected_timeout, 5, device_not_selected_timeout, __LINE__);
1508 TEST_PRINTERINFO_INT(5, transmission_retry_timeout, 5, transmission_retry_timeout, __LINE__); */
1510 /* FIXME: gd also test devmode and secdesc behavior */
1513 /* verify composition of level 1 description field */
1514 const char *description;
1515 const char *tmp;
1517 q0.in.level = 1;
1518 do { TESTGETCALL(GetPrinter, q0) } while (0);
1520 description = talloc_strdup(tctx, q0.out.info->info1.description);
1522 q0.in.level = 2;
1523 do { TESTGETCALL(GetPrinter, q0) } while (0);
1525 tmp = talloc_asprintf(tctx, "%s,%s,%s",
1526 q0.out.info->info2.printername,
1527 q0.out.info->info2.drivername,
1528 q0.out.info->info2.location);
1530 do { STRING_EQUAL(description, tmp, "description")} while (0);
1533 return ret;
1536 #define torture_assert_sid_equal(torture_ctx,got,expected,cmt)\
1537 do { struct dom_sid *__got = (got), *__expected = (expected); \
1538 if (!dom_sid_equal(__got, __expected)) { \
1539 torture_result(torture_ctx, TORTURE_FAIL, \
1540 __location__": "#got" was %s, expected %s: %s", \
1541 dom_sid_string(torture_ctx, __got), dom_sid_string(torture_ctx, __expected), cmt); \
1542 return false; \
1544 } while(0)
1546 static bool test_security_descriptor_equal(struct torture_context *tctx,
1547 const struct security_descriptor *sd1,
1548 const struct security_descriptor *sd2)
1550 if (sd1 == sd2) {
1551 return true;
1554 if (!sd1 || !sd2) {
1555 torture_comment(tctx, "%s\n", __location__);
1556 return false;
1559 torture_assert_int_equal(tctx, sd1->revision, sd2->revision, "revision mismatch");
1560 torture_assert_int_equal(tctx, sd1->type, sd2->type, "type mismatch");
1562 torture_assert_sid_equal(tctx, sd1->owner_sid, sd2->owner_sid, "owner mismatch");
1563 torture_assert_sid_equal(tctx, sd1->group_sid, sd2->group_sid, "group mismatch");
1565 if (!security_acl_equal(sd1->sacl, sd2->sacl)) {
1566 torture_comment(tctx, "%s: sacl mismatch\n", __location__);
1567 NDR_PRINT_DEBUG(security_acl, sd1->sacl);
1568 NDR_PRINT_DEBUG(security_acl, sd2->sacl);
1569 return false;
1571 if (!security_acl_equal(sd1->dacl, sd2->dacl)) {
1572 torture_comment(tctx, "%s: dacl mismatch\n", __location__);
1573 NDR_PRINT_DEBUG(security_acl, sd1->dacl);
1574 NDR_PRINT_DEBUG(security_acl, sd2->dacl);
1575 return false;
1578 return true;
1581 static bool test_sd_set_level(struct torture_context *tctx,
1582 struct dcerpc_pipe *p,
1583 struct policy_handle *handle,
1584 uint32_t level,
1585 struct security_descriptor *sd)
1587 struct spoolss_SetPrinterInfoCtr info_ctr;
1588 struct spoolss_DevmodeContainer devmode_ctr;
1589 struct sec_desc_buf secdesc_ctr;
1591 ZERO_STRUCT(devmode_ctr);
1592 ZERO_STRUCT(secdesc_ctr);
1594 switch (level) {
1595 case 2: {
1596 union spoolss_PrinterInfo info;
1597 struct spoolss_SetPrinterInfo2 info2;
1598 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 2, &info), "");
1600 info2.servername = info.info2.servername;
1601 info2.printername = info.info2.printername;
1602 info2.sharename = info.info2.sharename;
1603 info2.portname = info.info2.portname;
1604 info2.drivername = info.info2.drivername;
1605 info2.comment = info.info2.comment;
1606 info2.location = info.info2.location;
1607 info2.devmode_ptr = 0;
1608 info2.sepfile = info.info2.sepfile;
1609 info2.printprocessor = info.info2.printprocessor;
1610 info2.datatype = info.info2.datatype;
1611 info2.parameters = info.info2.parameters;
1612 info2.secdesc_ptr = 0;
1613 info2.attributes = info.info2.attributes;
1614 info2.priority = info.info2.priority;
1615 info2.defaultpriority = info.info2.defaultpriority;
1616 info2.starttime = info.info2.starttime;
1617 info2.untiltime = info.info2.untiltime;
1618 info2.status = info.info2.status;
1619 info2.cjobs = info.info2.cjobs;
1620 info2.averageppm = info.info2.averageppm;
1622 info_ctr.level = 2;
1623 info_ctr.info.info2 = &info2;
1625 break;
1627 case 3: {
1628 struct spoolss_SetPrinterInfo3 info3;
1630 info3.sec_desc_ptr = 0;
1632 info_ctr.level = 3;
1633 info_ctr.info.info3 = &info3;
1635 break;
1637 default:
1638 return false;
1641 secdesc_ctr.sd = sd;
1643 torture_assert(tctx,
1644 test_SetPrinter(tctx, p, handle, &info_ctr, &devmode_ctr, &secdesc_ctr, 0), "");
1646 return true;
1649 static bool test_PrinterInfo_SDs(struct torture_context *tctx,
1650 struct dcerpc_pipe *p,
1651 struct policy_handle *handle)
1653 union spoolss_PrinterInfo info;
1654 struct security_descriptor *sd1, *sd2;
1655 int i;
1657 /* just compare level 2 and level 3 */
1659 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 2, &info), "");
1661 sd1 = info.info2.secdesc;
1663 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 3, &info), "");
1665 sd2 = info.info3.secdesc;
1667 torture_assert(tctx, test_security_descriptor_equal(tctx, sd1, sd2),
1668 "SD level 2 != SD level 3");
1671 /* query level 2, set level 2, query level 2 */
1673 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 2, &info), "");
1675 sd1 = info.info2.secdesc;
1677 torture_assert(tctx, test_sd_set_level(tctx, p, handle, 2, sd1), "");
1679 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 2, &info), "");
1681 sd2 = info.info2.secdesc;
1682 if (sd1->type & SEC_DESC_DACL_DEFAULTED) {
1683 torture_comment(tctx, "removing SEC_DESC_DACL_DEFAULTED\n");
1684 sd1->type &= ~SEC_DESC_DACL_DEFAULTED;
1687 torture_assert(tctx, test_security_descriptor_equal(tctx, sd1, sd2),
1688 "SD level 2 != SD level 2 after SD has been set via level 2");
1691 /* query level 2, set level 3, query level 2 */
1693 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 2, &info), "");
1695 sd1 = info.info2.secdesc;
1697 torture_assert(tctx, test_sd_set_level(tctx, p, handle, 3, sd1), "");
1699 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 2, &info), "");
1701 sd2 = info.info2.secdesc;
1703 torture_assert(tctx, test_security_descriptor_equal(tctx, sd1, sd2),
1704 "SD level 2 != SD level 2 after SD has been set via level 3");
1706 /* set modified sd level 3, query level 2 */
1708 for (i=0; i < 93; i++) {
1709 struct security_ace a;
1710 const char *sid_string = talloc_asprintf(tctx, "S-1-5-32-9999%i", i);
1711 a.type = SEC_ACE_TYPE_ACCESS_ALLOWED;
1712 a.flags = 0;
1713 a.size = 0; /* autogenerated */
1714 a.access_mask = 0;
1715 a.trustee = *dom_sid_parse_talloc(tctx, sid_string);
1716 torture_assert_ntstatus_ok(tctx, security_descriptor_dacl_add(sd1, &a), "");
1719 torture_assert(tctx, test_sd_set_level(tctx, p, handle, 3, sd1), "");
1721 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 2, &info), "");
1722 sd2 = info.info2.secdesc;
1724 if (sd1->type & SEC_DESC_DACL_DEFAULTED) {
1725 torture_comment(tctx, "removing SEC_DESC_DACL_DEFAULTED\n");
1726 sd1->type &= ~SEC_DESC_DACL_DEFAULTED;
1729 torture_assert(tctx, test_security_descriptor_equal(tctx, sd1, sd2),
1730 "modified SD level 2 != SD level 2 after SD has been set via level 3");
1733 return true;
1737 * wrapper call that saves original sd, runs tests, and restores sd
1740 static bool test_PrinterInfo_SD(struct torture_context *tctx,
1741 struct dcerpc_pipe *p,
1742 struct policy_handle *handle)
1744 union spoolss_PrinterInfo info;
1745 struct security_descriptor *sd;
1746 bool ret = true;
1748 torture_comment(tctx, "\nTesting Printer Security Descriptors\n");
1750 /* save original sd */
1752 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 2, &info),
1753 "failed to get initial security descriptor");
1755 sd = security_descriptor_copy(tctx, info.info2.secdesc);
1757 /* run tests */
1759 ret = test_PrinterInfo_SDs(tctx, p, handle);
1761 /* restore original sd */
1763 torture_assert(tctx, test_sd_set_level(tctx, p, handle, 3, sd),
1764 "failed to restore initial security descriptor");
1766 torture_comment(tctx, "Printer Security Descriptors test %s\n",
1767 ret ? "succeeded" : "failed");
1770 return ret;
1773 static bool test_devmode_set_level(struct torture_context *tctx,
1774 struct dcerpc_pipe *p,
1775 struct policy_handle *handle,
1776 uint32_t level,
1777 struct spoolss_DeviceMode *devmode)
1779 struct spoolss_SetPrinterInfoCtr info_ctr;
1780 struct spoolss_DevmodeContainer devmode_ctr;
1781 struct sec_desc_buf secdesc_ctr;
1783 ZERO_STRUCT(devmode_ctr);
1784 ZERO_STRUCT(secdesc_ctr);
1786 switch (level) {
1787 case 2: {
1788 union spoolss_PrinterInfo info;
1789 struct spoolss_SetPrinterInfo2 info2;
1790 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 2, &info), "");
1792 info2.servername = info.info2.servername;
1793 info2.printername = info.info2.printername;
1794 info2.sharename = info.info2.sharename;
1795 info2.portname = info.info2.portname;
1796 info2.drivername = info.info2.drivername;
1797 info2.comment = info.info2.comment;
1798 info2.location = info.info2.location;
1799 info2.devmode_ptr = 0;
1800 info2.sepfile = info.info2.sepfile;
1801 info2.printprocessor = info.info2.printprocessor;
1802 info2.datatype = info.info2.datatype;
1803 info2.parameters = info.info2.parameters;
1804 info2.secdesc_ptr = 0;
1805 info2.attributes = info.info2.attributes;
1806 info2.priority = info.info2.priority;
1807 info2.defaultpriority = info.info2.defaultpriority;
1808 info2.starttime = info.info2.starttime;
1809 info2.untiltime = info.info2.untiltime;
1810 info2.status = info.info2.status;
1811 info2.cjobs = info.info2.cjobs;
1812 info2.averageppm = info.info2.averageppm;
1814 info_ctr.level = 2;
1815 info_ctr.info.info2 = &info2;
1817 break;
1819 case 8: {
1820 struct spoolss_SetPrinterInfo8 info8;
1822 info8.devmode_ptr = 0;
1824 info_ctr.level = 8;
1825 info_ctr.info.info8 = &info8;
1827 break;
1829 default:
1830 return false;
1833 devmode_ctr.devmode = devmode;
1835 torture_assert(tctx,
1836 test_SetPrinter(tctx, p, handle, &info_ctr, &devmode_ctr, &secdesc_ctr, 0), "");
1838 return true;
1842 static bool test_devicemode_equal(struct torture_context *tctx,
1843 const struct spoolss_DeviceMode *d1,
1844 const struct spoolss_DeviceMode *d2)
1846 if (d1 == d2) {
1847 return true;
1850 if (!d1 || !d2) {
1851 torture_comment(tctx, "%s\n", __location__);
1852 return false;
1854 torture_assert_str_equal(tctx, d1->devicename, d2->devicename, "devicename mismatch");
1855 torture_assert_int_equal(tctx, d1->specversion, d2->specversion, "specversion mismatch");
1856 torture_assert_int_equal(tctx, d1->driverversion, d2->driverversion, "driverversion mismatch");
1857 torture_assert_int_equal(tctx, d1->size, d2->size, "size mismatch");
1858 torture_assert_int_equal(tctx, d1->__driverextra_length, d2->__driverextra_length, "__driverextra_length mismatch");
1859 torture_assert_int_equal(tctx, d1->fields, d2->fields, "fields mismatch");
1860 torture_assert_int_equal(tctx, d1->orientation, d2->orientation, "orientation mismatch");
1861 torture_assert_int_equal(tctx, d1->papersize, d2->papersize, "papersize mismatch");
1862 torture_assert_int_equal(tctx, d1->paperlength, d2->paperlength, "paperlength mismatch");
1863 torture_assert_int_equal(tctx, d1->paperwidth, d2->paperwidth, "paperwidth mismatch");
1864 torture_assert_int_equal(tctx, d1->scale, d2->scale, "scale mismatch");
1865 torture_assert_int_equal(tctx, d1->copies, d2->copies, "copies mismatch");
1866 torture_assert_int_equal(tctx, d1->defaultsource, d2->defaultsource, "defaultsource mismatch");
1867 torture_assert_int_equal(tctx, d1->printquality, d2->printquality, "printquality mismatch");
1868 torture_assert_int_equal(tctx, d1->color, d2->color, "color mismatch");
1869 torture_assert_int_equal(tctx, d1->duplex, d2->duplex, "duplex mismatch");
1870 torture_assert_int_equal(tctx, d1->yresolution, d2->yresolution, "yresolution mismatch");
1871 torture_assert_int_equal(tctx, d1->ttoption, d2->ttoption, "ttoption mismatch");
1872 torture_assert_int_equal(tctx, d1->collate, d2->collate, "collate mismatch");
1873 torture_assert_str_equal(tctx, d1->formname, d2->formname, "formname mismatch");
1874 torture_assert_int_equal(tctx, d1->logpixels, d2->logpixels, "logpixels mismatch");
1875 torture_assert_int_equal(tctx, d1->bitsperpel, d2->bitsperpel, "bitsperpel mismatch");
1876 torture_assert_int_equal(tctx, d1->pelswidth, d2->pelswidth, "pelswidth mismatch");
1877 torture_assert_int_equal(tctx, d1->pelsheight, d2->pelsheight, "pelsheight mismatch");
1878 torture_assert_int_equal(tctx, d1->displayflags, d2->displayflags, "displayflags mismatch");
1879 torture_assert_int_equal(tctx, d1->displayfrequency, d2->displayfrequency, "displayfrequency mismatch");
1880 torture_assert_int_equal(tctx, d1->icmmethod, d2->icmmethod, "icmmethod mismatch");
1881 torture_assert_int_equal(tctx, d1->icmintent, d2->icmintent, "icmintent mismatch");
1882 torture_assert_int_equal(tctx, d1->mediatype, d2->mediatype, "mediatype mismatch");
1883 torture_assert_int_equal(tctx, d1->dithertype, d2->dithertype, "dithertype mismatch");
1884 torture_assert_int_equal(tctx, d1->reserved1, d2->reserved1, "reserved1 mismatch");
1885 torture_assert_int_equal(tctx, d1->reserved2, d2->reserved2, "reserved2 mismatch");
1886 torture_assert_int_equal(tctx, d1->panningwidth, d2->panningwidth, "panningwidth mismatch");
1887 torture_assert_int_equal(tctx, d1->panningheight, d2->panningheight, "panningheight mismatch");
1888 torture_assert_data_blob_equal(tctx, d1->driverextra_data, d2->driverextra_data, "driverextra_data mismatch");
1890 return true;
1893 static bool call_OpenPrinterEx(struct torture_context *tctx,
1894 struct dcerpc_pipe *p,
1895 const char *name,
1896 struct spoolss_DeviceMode *devmode,
1897 struct policy_handle *handle);
1899 static bool test_ClosePrinter(struct torture_context *tctx,
1900 struct dcerpc_pipe *p,
1901 struct policy_handle *handle);
1903 static bool test_PrinterInfo_DevModes(struct torture_context *tctx,
1904 struct dcerpc_pipe *p,
1905 struct policy_handle *handle,
1906 const char *name)
1908 union spoolss_PrinterInfo info;
1909 struct spoolss_DeviceMode *devmode;
1910 struct spoolss_DeviceMode *devmode2;
1911 struct policy_handle handle_devmode;
1913 /* simply compare level8 and level2 devmode */
1915 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 8, &info), "");
1917 devmode = info.info8.devmode;
1919 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 2, &info), "");
1921 devmode2 = info.info2.devmode;
1923 torture_assert(tctx, test_devicemode_equal(tctx, devmode, devmode2),
1924 "DM level 8 != DM level 2");
1927 /* set devicemode level 8 and see if it persists */
1929 devmode->copies = 93;
1930 devmode->formname = talloc_strdup(tctx, "Legal");
1932 torture_assert(tctx, test_devmode_set_level(tctx, p, handle, 8, devmode), "");
1934 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 8, &info), "");
1936 devmode2 = info.info8.devmode;
1938 torture_assert(tctx, test_devicemode_equal(tctx, devmode, devmode2),
1939 "modified DM level 8 != DM level 8 after DM has been set via level 8");
1941 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 2, &info), "");
1943 devmode2 = info.info2.devmode;
1945 torture_assert(tctx, test_devicemode_equal(tctx, devmode, devmode2),
1946 "modified DM level 8 != DM level 2");
1949 /* set devicemode level 2 and see if it persists */
1951 devmode->copies = 39;
1952 devmode->formname = talloc_strdup(tctx, "Executive");
1954 torture_assert(tctx, test_devmode_set_level(tctx, p, handle, 2, devmode), "");
1956 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 8, &info), "");
1958 devmode2 = info.info8.devmode;
1960 torture_assert(tctx, test_devicemode_equal(tctx, devmode, devmode2),
1961 "modified DM level 8 != DM level 8 after DM has been set via level 2");
1963 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 2, &info), "");
1965 devmode2 = info.info2.devmode;
1967 torture_assert(tctx, test_devicemode_equal(tctx, devmode, devmode2),
1968 "modified DM level 8 != DM level 2");
1971 /* change formname upon open and see if it persists in getprinter calls */
1973 devmode->formname = talloc_strdup(tctx, "A4");
1974 devmode->copies = 42;
1976 torture_assert(tctx, call_OpenPrinterEx(tctx, p, name, devmode, &handle_devmode),
1977 "failed to open printer handle");
1979 torture_assert(tctx, test_GetPrinter_level(tctx, p, &handle_devmode, 8, &info), "");
1981 devmode2 = info.info8.devmode;
1983 if (strequal(devmode->devicename, devmode2->devicename)) {
1984 torture_comment(tctx, "devicenames are the same\n");
1985 } else {
1986 torture_comment(tctx, "devicename passed in for open: %s\n", devmode->devicename);
1987 torture_comment(tctx, "devicename after level 8 get: %s\n", devmode2->devicename);
1990 if (strequal(devmode->formname, devmode2->formname)) {
1991 torture_warning(tctx, "formname are the same\n");
1992 } else {
1993 torture_comment(tctx, "formname passed in for open: %s\n", devmode->formname);
1994 torture_comment(tctx, "formname after level 8 get: %s\n", devmode2->formname);
1997 if (devmode->copies == devmode2->copies) {
1998 torture_warning(tctx, "copies are the same\n");
1999 } else {
2000 torture_comment(tctx, "copies passed in for open: %d\n", devmode->copies);
2001 torture_comment(tctx, "copies after level 8 get: %d\n", devmode2->copies);
2004 torture_assert(tctx, test_GetPrinter_level(tctx, p, &handle_devmode, 2, &info), "");
2006 devmode2 = info.info2.devmode;
2008 if (strequal(devmode->devicename, devmode2->devicename)) {
2009 torture_comment(tctx, "devicenames are the same\n");
2010 } else {
2011 torture_comment(tctx, "devicename passed in for open: %s\n", devmode->devicename);
2012 torture_comment(tctx, "devicename after level 2 get: %s\n", devmode2->devicename);
2015 if (strequal(devmode->formname, devmode2->formname)) {
2016 torture_warning(tctx, "formname is the same\n");
2017 } else {
2018 torture_comment(tctx, "formname passed in for open: %s\n", devmode->formname);
2019 torture_comment(tctx, "formname after level 2 get: %s\n", devmode2->formname);
2022 if (devmode->copies == devmode2->copies) {
2023 torture_warning(tctx, "copies are the same\n");
2024 } else {
2025 torture_comment(tctx, "copies passed in for open: %d\n", devmode->copies);
2026 torture_comment(tctx, "copies after level 2 get: %d\n", devmode2->copies);
2029 test_ClosePrinter(tctx, p, &handle_devmode);
2031 return true;
2035 * wrapper call that saves original devmode, runs tests, and restores devmode
2038 static bool test_PrinterInfo_DevMode(struct torture_context *tctx,
2039 struct dcerpc_pipe *p,
2040 struct policy_handle *handle,
2041 const char *name)
2043 union spoolss_PrinterInfo info;
2044 struct spoolss_DeviceMode *devmode;
2045 bool ret = true;
2047 torture_comment(tctx, "\nTesting Printer Devicemodes\n");
2049 /* save original devmode */
2051 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 8, &info),
2052 "failed to get initial global devicemode");
2054 devmode = info.info8.devmode;
2056 /* run tests */
2058 ret = test_PrinterInfo_DevModes(tctx, p, handle, name);
2060 /* restore original devmode */
2062 torture_assert(tctx, test_devmode_set_level(tctx, p, handle, 8, devmode),
2063 "failed to restore initial global device mode");
2065 torture_comment(tctx, "Printer Devicemodes test %s\n",
2066 ret ? "succeeded" : "failed");
2069 return ret;
2072 static bool test_ClosePrinter(struct torture_context *tctx,
2073 struct dcerpc_pipe *p,
2074 struct policy_handle *handle)
2076 NTSTATUS status;
2077 struct spoolss_ClosePrinter r;
2079 r.in.handle = handle;
2080 r.out.handle = handle;
2082 torture_comment(tctx, "Testing ClosePrinter\n");
2084 status = dcerpc_spoolss_ClosePrinter(p, tctx, &r);
2085 torture_assert_ntstatus_ok(tctx, status, "ClosePrinter failed");
2086 torture_assert_werr_ok(tctx, r.out.result, "ClosePrinter failed");
2088 return true;
2091 static bool test_GetForm(struct torture_context *tctx,
2092 struct dcerpc_pipe *p,
2093 struct policy_handle *handle,
2094 const char *form_name,
2095 uint32_t level)
2097 NTSTATUS status;
2098 struct spoolss_GetForm r;
2099 uint32_t needed;
2101 r.in.handle = handle;
2102 r.in.form_name = form_name;
2103 r.in.level = level;
2104 r.in.buffer = NULL;
2105 r.in.offered = 0;
2106 r.out.needed = &needed;
2108 torture_comment(tctx, "Testing GetForm level %d\n", r.in.level);
2110 status = dcerpc_spoolss_GetForm(p, tctx, &r);
2111 torture_assert_ntstatus_ok(tctx, status, "GetForm failed");
2113 if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
2114 DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed);
2115 data_blob_clear(&blob);
2116 r.in.buffer = &blob;
2117 r.in.offered = needed;
2118 status = dcerpc_spoolss_GetForm(p, tctx, &r);
2119 torture_assert_ntstatus_ok(tctx, status, "GetForm failed");
2121 torture_assert_werr_ok(tctx, r.out.result, "GetForm failed");
2123 torture_assert(tctx, r.out.info, "No form info returned");
2126 torture_assert_werr_ok(tctx, r.out.result, "GetForm failed");
2128 CHECK_NEEDED_SIZE_LEVEL(spoolss_FormInfo, r.out.info, r.in.level, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
2130 return true;
2133 static bool test_EnumForms(struct torture_context *tctx,
2134 struct dcerpc_pipe *p,
2135 struct policy_handle *handle, bool print_server)
2137 NTSTATUS status;
2138 struct spoolss_EnumForms r;
2139 bool ret = true;
2140 uint32_t needed;
2141 uint32_t count;
2142 uint32_t levels[] = { 1, 2 };
2143 int i;
2145 for (i=0; i<ARRAY_SIZE(levels); i++) {
2147 union spoolss_FormInfo *info;
2149 r.in.handle = handle;
2150 r.in.level = levels[i];
2151 r.in.buffer = NULL;
2152 r.in.offered = 0;
2153 r.out.needed = &needed;
2154 r.out.count = &count;
2155 r.out.info = &info;
2157 torture_comment(tctx, "Testing EnumForms level %d\n", levels[i]);
2159 status = dcerpc_spoolss_EnumForms(p, tctx, &r);
2160 torture_assert_ntstatus_ok(tctx, status, "EnumForms failed");
2162 if ((r.in.level == 2) && (W_ERROR_EQUAL(r.out.result, WERR_UNKNOWN_LEVEL))) {
2163 break;
2166 if (print_server && W_ERROR_EQUAL(r.out.result, WERR_BADFID))
2167 torture_fail(tctx, "EnumForms on the PrintServer isn't supported by test server (NT4)");
2169 if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
2170 int j;
2171 DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed);
2172 data_blob_clear(&blob);
2173 r.in.buffer = &blob;
2174 r.in.offered = needed;
2176 status = dcerpc_spoolss_EnumForms(p, tctx, &r);
2178 torture_assert(tctx, info, "No forms returned");
2180 for (j = 0; j < count; j++) {
2181 if (!print_server)
2182 ret &= test_GetForm(tctx, p, handle, info[j].info1.form_name, levels[i]);
2186 torture_assert_ntstatus_ok(tctx, status, "EnumForms failed");
2188 torture_assert_werr_ok(tctx, r.out.result, "EnumForms failed");
2190 CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumForms, info, r.in.level, count, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
2193 return true;
2196 static bool test_DeleteForm(struct torture_context *tctx,
2197 struct dcerpc_pipe *p,
2198 struct policy_handle *handle,
2199 const char *form_name)
2201 NTSTATUS status;
2202 struct spoolss_DeleteForm r;
2204 r.in.handle = handle;
2205 r.in.form_name = form_name;
2207 status = dcerpc_spoolss_DeleteForm(p, tctx, &r);
2209 torture_assert_ntstatus_ok(tctx, status, "DeleteForm failed");
2211 torture_assert_werr_ok(tctx, r.out.result, "DeleteForm failed");
2213 return true;
2216 static bool test_AddForm(struct torture_context *tctx,
2217 struct dcerpc_pipe *p,
2218 struct policy_handle *handle, bool print_server)
2220 struct spoolss_AddForm r;
2221 struct spoolss_AddFormInfo1 addform;
2222 const char *form_name = "testform3";
2223 NTSTATUS status;
2224 bool ret = true;
2226 r.in.handle = handle;
2227 r.in.level = 1;
2228 r.in.info.info1 = &addform;
2229 addform.flags = SPOOLSS_FORM_USER;
2230 addform.form_name = form_name;
2231 addform.size.width = 50;
2232 addform.size.height = 25;
2233 addform.area.left = 5;
2234 addform.area.top = 10;
2235 addform.area.right = 45;
2236 addform.area.bottom = 15;
2238 status = dcerpc_spoolss_AddForm(p, tctx, &r);
2240 torture_assert_ntstatus_ok(tctx, status, "AddForm failed");
2242 torture_assert_werr_ok(tctx, r.out.result, "AddForm failed");
2244 if (!print_server) ret &= test_GetForm(tctx, p, handle, form_name, 1);
2247 struct spoolss_SetForm sf;
2248 struct spoolss_AddFormInfo1 setform;
2250 sf.in.handle = handle;
2251 sf.in.form_name = form_name;
2252 sf.in.level = 1;
2253 sf.in.info.info1= &setform;
2254 setform.flags = addform.flags;
2255 setform.form_name = addform.form_name;
2256 setform.size = addform.size;
2257 setform.area = addform.area;
2259 setform.size.width = 1234;
2261 status = dcerpc_spoolss_SetForm(p, tctx, &sf);
2263 torture_assert_ntstatus_ok(tctx, status, "SetForm failed");
2265 torture_assert_werr_ok(tctx, r.out.result, "SetForm failed");
2268 if (!print_server) ret &= test_GetForm(tctx, p, handle, form_name, 1);
2271 struct spoolss_EnumForms e;
2272 union spoolss_FormInfo *info;
2273 uint32_t needed;
2274 uint32_t count;
2275 bool found = false;
2277 e.in.handle = handle;
2278 e.in.level = 1;
2279 e.in.buffer = NULL;
2280 e.in.offered = 0;
2281 e.out.needed = &needed;
2282 e.out.count = &count;
2283 e.out.info = &info;
2285 torture_comment(tctx, "Testing EnumForms level 1\n");
2287 status = dcerpc_spoolss_EnumForms(p, tctx, &e);
2288 torture_assert_ntstatus_ok(tctx, status, "EnumForms failed");
2290 if (print_server && W_ERROR_EQUAL(e.out.result, WERR_BADFID))
2291 torture_fail(tctx, "EnumForms on the PrintServer isn't supported by test server (NT4)");
2293 if (W_ERROR_EQUAL(e.out.result, WERR_INSUFFICIENT_BUFFER)) {
2294 int j;
2295 DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed);
2296 data_blob_clear(&blob);
2297 e.in.buffer = &blob;
2298 e.in.offered = needed;
2300 status = dcerpc_spoolss_EnumForms(p, tctx, &e);
2302 torture_assert(tctx, info, "No forms returned");
2304 for (j = 0; j < count; j++) {
2305 if (strequal(form_name, info[j].info1.form_name)) {
2306 found = true;
2307 break;
2311 torture_assert(tctx, found, "Newly added form not found in enum call");
2314 if (!test_DeleteForm(tctx, p, handle, form_name)) {
2315 ret = false;
2318 return ret;
2321 static bool test_EnumPorts_old(struct torture_context *tctx,
2322 struct dcerpc_pipe *p)
2324 NTSTATUS status;
2325 struct spoolss_EnumPorts r;
2326 uint32_t needed;
2327 uint32_t count;
2328 union spoolss_PortInfo *info;
2330 r.in.servername = talloc_asprintf(tctx, "\\\\%s",
2331 dcerpc_server_name(p));
2332 r.in.level = 2;
2333 r.in.buffer = NULL;
2334 r.in.offered = 0;
2335 r.out.needed = &needed;
2336 r.out.count = &count;
2337 r.out.info = &info;
2339 torture_comment(tctx, "Testing EnumPorts\n");
2341 status = dcerpc_spoolss_EnumPorts(p, tctx, &r);
2343 torture_assert_ntstatus_ok(tctx, status, "EnumPorts failed");
2345 if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
2346 DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed);
2347 data_blob_clear(&blob);
2348 r.in.buffer = &blob;
2349 r.in.offered = needed;
2351 status = dcerpc_spoolss_EnumPorts(p, tctx, &r);
2352 torture_assert_ntstatus_ok(tctx, status, "EnumPorts failed");
2353 torture_assert_werr_ok(tctx, r.out.result, "EnumPorts failed");
2355 torture_assert(tctx, info, "No ports returned");
2358 torture_assert_werr_ok(tctx, r.out.result, "EnumPorts failed");
2360 CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumPorts, info, 2, count, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
2362 return true;
2365 static bool test_AddPort(struct torture_context *tctx,
2366 struct dcerpc_pipe *p)
2368 NTSTATUS status;
2369 struct spoolss_AddPort r;
2371 r.in.server_name = talloc_asprintf(tctx, "\\\\%s",
2372 dcerpc_server_name(p));
2373 r.in.unknown = 0;
2374 r.in.monitor_name = "foo";
2376 torture_comment(tctx, "Testing AddPort\n");
2378 status = dcerpc_spoolss_AddPort(p, tctx, &r);
2380 torture_assert_ntstatus_ok(tctx, status, "AddPort failed");
2382 /* win2k3 returns WERR_NOT_SUPPORTED */
2384 #if 0
2386 if (!W_ERROR_IS_OK(r.out.result)) {
2387 printf("AddPort failed - %s\n", win_errstr(r.out.result));
2388 return false;
2391 #endif
2393 return true;
2396 static bool test_GetJob(struct torture_context *tctx,
2397 struct dcerpc_pipe *p,
2398 struct policy_handle *handle, uint32_t job_id)
2400 NTSTATUS status;
2401 struct spoolss_GetJob r;
2402 union spoolss_JobInfo info;
2403 uint32_t needed;
2404 uint32_t levels[] = {1, 2 /* 3, 4 */};
2405 uint32_t i;
2407 r.in.handle = handle;
2408 r.in.job_id = job_id;
2409 r.in.level = 0;
2410 r.in.buffer = NULL;
2411 r.in.offered = 0;
2412 r.out.needed = &needed;
2413 r.out.info = &info;
2415 torture_comment(tctx, "Testing GetJob level %d\n", r.in.level);
2417 status = dcerpc_spoolss_GetJob(p, tctx, &r);
2418 torture_assert_werr_equal(tctx, r.out.result, WERR_UNKNOWN_LEVEL, "Unexpected return code");
2420 for (i = 0; i < ARRAY_SIZE(levels); i++) {
2422 torture_comment(tctx, "Testing GetJob level %d\n", r.in.level);
2424 needed = 0;
2426 r.in.level = levels[i];
2427 r.in.offered = 0;
2428 r.in.buffer = NULL;
2430 status = dcerpc_spoolss_GetJob(p, tctx, &r);
2431 torture_assert_ntstatus_ok(tctx, status, "GetJob failed");
2433 if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
2434 DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed);
2435 data_blob_clear(&blob);
2436 r.in.buffer = &blob;
2437 r.in.offered = needed;
2439 status = dcerpc_spoolss_GetJob(p, tctx, &r);
2440 torture_assert_ntstatus_ok(tctx, status, "GetJob failed");
2443 torture_assert(tctx, r.out.info, "No job info returned");
2444 torture_assert_werr_ok(tctx, r.out.result, "GetJob failed");
2446 CHECK_NEEDED_SIZE_LEVEL(spoolss_JobInfo, r.out.info, r.in.level, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
2449 return true;
2452 static bool test_SetJob(struct torture_context *tctx,
2453 struct dcerpc_pipe *p,
2454 struct policy_handle *handle, uint32_t job_id,
2455 enum spoolss_JobControl command)
2457 NTSTATUS status;
2458 struct spoolss_SetJob r;
2460 r.in.handle = handle;
2461 r.in.job_id = job_id;
2462 r.in.ctr = NULL;
2463 r.in.command = command;
2465 switch (command) {
2466 case SPOOLSS_JOB_CONTROL_PAUSE:
2467 torture_comment(tctx, "Testing SetJob: SPOOLSS_JOB_CONTROL_PAUSE\n");
2468 break;
2469 case SPOOLSS_JOB_CONTROL_RESUME:
2470 torture_comment(tctx, "Testing SetJob: SPOOLSS_JOB_CONTROL_RESUME\n");
2471 break;
2472 case SPOOLSS_JOB_CONTROL_CANCEL:
2473 torture_comment(tctx, "Testing SetJob: SPOOLSS_JOB_CONTROL_CANCEL\n");
2474 break;
2475 case SPOOLSS_JOB_CONTROL_RESTART:
2476 torture_comment(tctx, "Testing SetJob: SPOOLSS_JOB_CONTROL_RESTART\n");
2477 break;
2478 case SPOOLSS_JOB_CONTROL_DELETE:
2479 torture_comment(tctx, "Testing SetJob: SPOOLSS_JOB_CONTROL_DELETE\n");
2480 break;
2481 case SPOOLSS_JOB_CONTROL_SEND_TO_PRINTER:
2482 torture_comment(tctx, "Testing SetJob: SPOOLSS_JOB_CONTROL_SEND_TO_PRINTER\n");
2483 break;
2484 case SPOOLSS_JOB_CONTROL_LAST_PAGE_EJECTED:
2485 torture_comment(tctx, "Testing SetJob: SPOOLSS_JOB_CONTROL_LAST_PAGE_EJECTED\n");
2486 break;
2487 case SPOOLSS_JOB_CONTROL_RETAIN:
2488 torture_comment(tctx, "Testing SetJob: SPOOLSS_JOB_CONTROL_RETAIN\n");
2489 break;
2490 case SPOOLSS_JOB_CONTROL_RELEASE:
2491 torture_comment(tctx, "Testing SetJob: SPOOLSS_JOB_CONTROL_RELEASE\n");
2492 break;
2493 default:
2494 torture_comment(tctx, "Testing SetJob\n");
2495 break;
2498 status = dcerpc_spoolss_SetJob(p, tctx, &r);
2499 torture_assert_ntstatus_ok(tctx, status, "SetJob failed");
2500 torture_assert_werr_ok(tctx, r.out.result, "SetJob failed");
2502 return true;
2505 static bool test_AddJob(struct torture_context *tctx,
2506 struct dcerpc_pipe *p,
2507 struct policy_handle *handle)
2509 NTSTATUS status;
2510 struct spoolss_AddJob r;
2511 uint32_t needed;
2513 r.in.level = 0;
2514 r.in.handle = handle;
2515 r.in.offered = 0;
2516 r.out.needed = &needed;
2517 r.in.buffer = r.out.buffer = NULL;
2519 torture_comment(tctx, "Testing AddJob\n");
2521 status = dcerpc_spoolss_AddJob(p, tctx, &r);
2522 torture_assert_werr_equal(tctx, r.out.result, WERR_UNKNOWN_LEVEL, "AddJob failed");
2524 r.in.level = 1;
2526 status = dcerpc_spoolss_AddJob(p, tctx, &r);
2527 torture_assert_werr_equal(tctx, r.out.result, WERR_INVALID_PARAM, "AddJob failed");
2529 return true;
2533 static bool test_EnumJobs(struct torture_context *tctx,
2534 struct dcerpc_pipe *p,
2535 struct policy_handle *handle)
2537 NTSTATUS status;
2538 struct spoolss_EnumJobs r;
2539 uint32_t needed;
2540 uint32_t count;
2541 union spoolss_JobInfo *info;
2543 r.in.handle = handle;
2544 r.in.firstjob = 0;
2545 r.in.numjobs = 0xffffffff;
2546 r.in.level = 1;
2547 r.in.buffer = NULL;
2548 r.in.offered = 0;
2549 r.out.needed = &needed;
2550 r.out.count = &count;
2551 r.out.info = &info;
2553 torture_comment(tctx, "Testing EnumJobs\n");
2555 status = dcerpc_spoolss_EnumJobs(p, tctx, &r);
2557 torture_assert_ntstatus_ok(tctx, status, "EnumJobs failed");
2559 if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
2560 int j;
2561 DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed);
2562 data_blob_clear(&blob);
2563 r.in.buffer = &blob;
2564 r.in.offered = needed;
2566 status = dcerpc_spoolss_EnumJobs(p, tctx, &r);
2568 torture_assert_ntstatus_ok(tctx, status, "EnumJobs failed");
2569 torture_assert_werr_ok(tctx, r.out.result, "EnumJobs failed");
2570 torture_assert(tctx, info, "No jobs returned");
2572 CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumJobs, *r.out.info, r.in.level, count, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
2574 for (j = 0; j < count; j++) {
2576 torture_assert(tctx, test_GetJob(tctx, p, handle, info[j].info1.job_id),
2577 "failed to call test_GetJob");
2579 /* FIXME - gd */
2580 if (!torture_setting_bool(tctx, "samba3", false)) {
2581 test_SetJob(tctx, p, handle, info[j].info1.job_id, SPOOLSS_JOB_CONTROL_PAUSE);
2582 test_SetJob(tctx, p, handle, info[j].info1.job_id, SPOOLSS_JOB_CONTROL_RESUME);
2586 } else {
2587 torture_assert_werr_ok(tctx, r.out.result, "EnumJobs failed");
2590 return true;
2593 static bool test_DoPrintTest(struct torture_context *tctx,
2594 struct dcerpc_pipe *p,
2595 struct policy_handle *handle)
2597 bool ret = true;
2598 NTSTATUS status;
2599 struct spoolss_StartDocPrinter s;
2600 struct spoolss_DocumentInfo1 info1;
2601 struct spoolss_StartPagePrinter sp;
2602 struct spoolss_WritePrinter w;
2603 struct spoolss_EndPagePrinter ep;
2604 struct spoolss_EndDocPrinter e;
2605 int i;
2606 uint32_t job_id;
2607 uint32_t num_written;
2609 torture_comment(tctx, "Testing StartDocPrinter\n");
2611 s.in.handle = handle;
2612 s.in.level = 1;
2613 s.in.info.info1 = &info1;
2614 s.out.job_id = &job_id;
2615 info1.document_name = "TorturePrintJob";
2616 info1.output_file = NULL;
2617 info1.datatype = "RAW";
2619 status = dcerpc_spoolss_StartDocPrinter(p, tctx, &s);
2620 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_StartDocPrinter failed");
2621 torture_assert_werr_ok(tctx, s.out.result, "StartDocPrinter failed");
2623 for (i=1; i < 4; i++) {
2624 torture_comment(tctx, "Testing StartPagePrinter: Page[%d]\n", i);
2626 sp.in.handle = handle;
2628 status = dcerpc_spoolss_StartPagePrinter(p, tctx, &sp);
2629 torture_assert_ntstatus_ok(tctx, status,
2630 "dcerpc_spoolss_StartPagePrinter failed");
2631 torture_assert_werr_ok(tctx, sp.out.result, "StartPagePrinter failed");
2633 torture_comment(tctx, "Testing WritePrinter: Page[%d]\n", i);
2635 w.in.handle = handle;
2636 w.in.data = data_blob_string_const(talloc_asprintf(tctx,"TortureTestPage: %d\nData\n",i));
2637 w.out.num_written = &num_written;
2639 status = dcerpc_spoolss_WritePrinter(p, tctx, &w);
2640 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_WritePrinter failed");
2641 torture_assert_werr_ok(tctx, w.out.result, "WritePrinter failed");
2643 torture_comment(tctx, "Testing EndPagePrinter: Page[%d]\n", i);
2645 ep.in.handle = handle;
2647 status = dcerpc_spoolss_EndPagePrinter(p, tctx, &ep);
2648 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EndPagePrinter failed");
2649 torture_assert_werr_ok(tctx, ep.out.result, "EndPagePrinter failed");
2652 torture_comment(tctx, "Testing EndDocPrinter\n");
2654 e.in.handle = handle;
2656 status = dcerpc_spoolss_EndDocPrinter(p, tctx, &e);
2657 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EndDocPrinter failed");
2658 torture_assert_werr_ok(tctx, e.out.result, "EndDocPrinter failed");
2660 ret &= test_AddJob(tctx, p, handle);
2661 ret &= test_EnumJobs(tctx, p, handle);
2663 ret &= test_SetJob(tctx, p, handle, job_id, SPOOLSS_JOB_CONTROL_DELETE);
2665 return ret;
2668 static bool test_PausePrinter(struct torture_context *tctx,
2669 struct dcerpc_pipe *p,
2670 struct policy_handle *handle)
2672 NTSTATUS status;
2673 struct spoolss_SetPrinter r;
2674 struct spoolss_SetPrinterInfoCtr info_ctr;
2675 struct spoolss_DevmodeContainer devmode_ctr;
2676 struct sec_desc_buf secdesc_ctr;
2678 info_ctr.level = 0;
2679 info_ctr.info.info0 = NULL;
2681 ZERO_STRUCT(devmode_ctr);
2682 ZERO_STRUCT(secdesc_ctr);
2684 r.in.handle = handle;
2685 r.in.info_ctr = &info_ctr;
2686 r.in.devmode_ctr = &devmode_ctr;
2687 r.in.secdesc_ctr = &secdesc_ctr;
2688 r.in.command = SPOOLSS_PRINTER_CONTROL_PAUSE;
2690 torture_comment(tctx, "Testing SetPrinter: SPOOLSS_PRINTER_CONTROL_PAUSE\n");
2692 status = dcerpc_spoolss_SetPrinter(p, tctx, &r);
2694 torture_assert_ntstatus_ok(tctx, status, "SetPrinter failed");
2696 torture_assert_werr_ok(tctx, r.out.result, "SetPrinter failed");
2698 return true;
2701 static bool test_ResumePrinter(struct torture_context *tctx,
2702 struct dcerpc_pipe *p,
2703 struct policy_handle *handle)
2705 NTSTATUS status;
2706 struct spoolss_SetPrinter r;
2707 struct spoolss_SetPrinterInfoCtr info_ctr;
2708 struct spoolss_DevmodeContainer devmode_ctr;
2709 struct sec_desc_buf secdesc_ctr;
2711 info_ctr.level = 0;
2712 info_ctr.info.info0 = NULL;
2714 ZERO_STRUCT(devmode_ctr);
2715 ZERO_STRUCT(secdesc_ctr);
2717 r.in.handle = handle;
2718 r.in.info_ctr = &info_ctr;
2719 r.in.devmode_ctr = &devmode_ctr;
2720 r.in.secdesc_ctr = &secdesc_ctr;
2721 r.in.command = SPOOLSS_PRINTER_CONTROL_RESUME;
2723 torture_comment(tctx, "Testing SetPrinter: SPOOLSS_PRINTER_CONTROL_RESUME\n");
2725 status = dcerpc_spoolss_SetPrinter(p, tctx, &r);
2727 torture_assert_ntstatus_ok(tctx, status, "SetPrinter failed");
2729 torture_assert_werr_ok(tctx, r.out.result, "SetPrinter failed");
2731 return true;
2734 static bool test_GetPrinterData(struct torture_context *tctx,
2735 struct dcerpc_pipe *p,
2736 struct policy_handle *handle,
2737 const char *value_name,
2738 enum winreg_Type *type_p,
2739 union spoolss_PrinterData *data_p)
2741 NTSTATUS status;
2742 struct spoolss_GetPrinterData r;
2743 uint32_t needed;
2744 enum winreg_Type type;
2745 union spoolss_PrinterData data;
2747 r.in.handle = handle;
2748 r.in.value_name = value_name;
2749 r.in.offered = 0;
2750 r.out.needed = &needed;
2751 r.out.type = &type;
2752 r.out.data = &data;
2754 torture_comment(tctx, "Testing GetPrinterData(%s)\n", r.in.value_name);
2756 status = dcerpc_spoolss_GetPrinterData(p, tctx, &r);
2757 torture_assert_ntstatus_ok(tctx, status, "GetPrinterData failed");
2759 if (W_ERROR_EQUAL(r.out.result, WERR_MORE_DATA)) {
2760 r.in.offered = needed;
2762 status = dcerpc_spoolss_GetPrinterData(p, tctx, &r);
2763 torture_assert_ntstatus_ok(tctx, status, "GetPrinterData failed");
2766 torture_assert_werr_ok(tctx, r.out.result,
2767 talloc_asprintf(tctx, "GetPrinterData(%s) failed", r.in.value_name));
2769 CHECK_NEEDED_SIZE_LEVEL(spoolss_PrinterData, &data, type, lp_iconv_convenience(tctx->lp_ctx), needed, 1);
2771 if (type_p) {
2772 *type_p = type;
2775 if (data_p) {
2776 *data_p = data;
2779 return true;
2782 static bool test_GetPrinterDataEx(struct torture_context *tctx,
2783 struct dcerpc_pipe *p,
2784 struct policy_handle *handle,
2785 const char *key_name,
2786 const char *value_name,
2787 enum winreg_Type *type_p,
2788 union spoolss_PrinterData *data_p)
2790 NTSTATUS status;
2791 struct spoolss_GetPrinterDataEx r;
2792 enum winreg_Type type;
2793 uint32_t needed;
2794 union spoolss_PrinterData data;
2796 r.in.handle = handle;
2797 r.in.key_name = key_name;
2798 r.in.value_name = value_name;
2799 r.in.offered = 0;
2800 r.out.type = &type;
2801 r.out.needed = &needed;
2802 r.out.data = &data;
2804 torture_comment(tctx, "Testing GetPrinterDataEx(%s - %s)\n",
2805 r.in.key_name, r.in.value_name);
2807 status = dcerpc_spoolss_GetPrinterDataEx(p, tctx, &r);
2808 if (!NT_STATUS_IS_OK(status)) {
2809 if (NT_STATUS_EQUAL(status,NT_STATUS_NET_WRITE_FAULT) &&
2810 p->last_fault_code == DCERPC_FAULT_OP_RNG_ERROR) {
2811 torture_skip(tctx, "GetPrinterDataEx not supported by server\n");
2813 torture_assert_ntstatus_ok(tctx, status, "GetPrinterDataEx failed");
2816 if (W_ERROR_EQUAL(r.out.result, WERR_MORE_DATA)) {
2817 r.in.offered = needed;
2818 status = dcerpc_spoolss_GetPrinterDataEx(p, tctx, &r);
2819 torture_assert_ntstatus_ok(tctx, status, "GetPrinterDataEx failed");
2822 torture_assert_werr_ok(tctx, r.out.result,
2823 talloc_asprintf(tctx, "GetPrinterDataEx(%s - %s) failed", r.in.key_name, r.in.value_name));
2825 CHECK_NEEDED_SIZE_LEVEL(spoolss_PrinterData, &data, type, lp_iconv_convenience(tctx->lp_ctx), needed, 1);
2827 if (type_p) {
2828 *type_p = type;
2831 if (data_p) {
2832 *data_p = data;
2835 return true;
2838 static bool test_GetPrinterData_list(struct torture_context *tctx,
2839 struct dcerpc_pipe *p,
2840 struct policy_handle *handle)
2842 const char *list[] = {
2843 "W3SvcInstalled",
2844 "BeepEnabled",
2845 "EventLog",
2846 /* "NetPopup", not on w2k8 */
2847 /* "NetPopupToComputer", not on w2k8 */
2848 "MajorVersion",
2849 "MinorVersion",
2850 "DefaultSpoolDirectory",
2851 "Architecture",
2852 "DsPresent",
2853 "OSVersion",
2854 /* "OSVersionEx", not on s3 */
2855 "DNSMachineName"
2857 int i;
2859 for (i=0; i < ARRAY_SIZE(list); i++) {
2860 enum winreg_Type type, type_ex;
2861 union spoolss_PrinterData data, data_ex;
2863 torture_assert(tctx, test_GetPrinterData(tctx, p, handle, list[i], &type, &data),
2864 talloc_asprintf(tctx, "GetPrinterData failed on %s\n", list[i]));
2865 torture_assert(tctx, test_GetPrinterDataEx(tctx, p, handle, "random_string", list[i], &type_ex, &data_ex),
2866 talloc_asprintf(tctx, "GetPrinterDataEx failed on %s\n", list[i]));
2867 torture_assert_int_equal(tctx, type, type_ex, "type mismatch");
2868 switch (type) {
2869 case REG_SZ:
2870 torture_assert_str_equal(tctx, data.string, data_ex.string, "REG_SZ mismatch");
2871 break;
2872 case REG_DWORD:
2873 torture_assert_int_equal(tctx, data.value, data_ex.value, "REG_DWORD mismatch");
2874 break;
2875 case REG_BINARY:
2876 torture_assert_data_blob_equal(tctx, data.binary, data_ex.binary, "REG_BINARY mismatch");
2877 break;
2878 default:
2879 break;
2883 return true;
2886 static bool test_EnumPrinterData(struct torture_context *tctx, struct dcerpc_pipe *p,
2887 struct policy_handle *handle)
2889 NTSTATUS status;
2890 struct spoolss_EnumPrinterData r;
2892 ZERO_STRUCT(r);
2893 r.in.handle = handle;
2894 r.in.enum_index = 0;
2896 do {
2897 uint32_t value_size = 0;
2898 uint32_t data_size = 0;
2899 enum winreg_Type type = 0;
2901 r.in.value_offered = value_size;
2902 r.out.value_needed = &value_size;
2903 r.in.data_offered = data_size;
2904 r.out.data_needed = &data_size;
2906 r.out.type = &type;
2907 r.out.data = talloc_zero_array(tctx, uint8_t, 0);
2909 torture_comment(tctx, "Testing EnumPrinterData\n");
2911 status = dcerpc_spoolss_EnumPrinterData(p, tctx, &r);
2913 torture_assert_ntstatus_ok(tctx, status, "EnumPrinterData failed");
2914 if (W_ERROR_EQUAL(r.out.result, WERR_NO_MORE_ITEMS)) {
2915 break;
2917 torture_assert_werr_ok(tctx, r.out.result, "EnumPrinterData");
2919 r.in.value_offered = value_size;
2920 r.out.value_name = talloc_zero_array(tctx, const char, value_size);
2921 r.in.data_offered = data_size;
2922 r.out.data = talloc_zero_array(tctx, uint8_t, data_size);
2924 status = dcerpc_spoolss_EnumPrinterData(p, tctx, &r);
2926 torture_assert_ntstatus_ok(tctx, status, "EnumPrinterData failed");
2927 if (W_ERROR_EQUAL(r.out.result, WERR_NO_MORE_ITEMS)) {
2928 break;
2931 torture_assert_werr_ok(tctx, r.out.result, "EnumPrinterData failed");
2933 torture_assert(tctx, test_GetPrinterData(tctx, p, handle, r.out.value_name, NULL, NULL),
2934 talloc_asprintf(tctx, "failed to call GetPrinterData for %s\n", r.out.value_name));
2936 torture_assert(tctx, test_GetPrinterDataEx(tctx, p, handle, "PrinterDriverData", r.out.value_name, NULL, NULL),
2937 talloc_asprintf(tctx, "failed to call GetPrinterDataEx on PrinterDriverData for %s\n", r.out.value_name));
2939 r.in.enum_index++;
2941 } while (W_ERROR_IS_OK(r.out.result));
2943 return true;
2946 static bool test_EnumPrinterDataEx(struct torture_context *tctx,
2947 struct dcerpc_pipe *p,
2948 struct policy_handle *handle,
2949 const char *key_name)
2951 struct spoolss_EnumPrinterDataEx r;
2952 struct spoolss_PrinterEnumValues *info;
2953 uint32_t needed;
2954 uint32_t count;
2956 r.in.handle = handle;
2957 r.in.key_name = key_name;
2958 r.in.offered = 0;
2959 r.out.needed = &needed;
2960 r.out.count = &count;
2961 r.out.info = &info;
2963 torture_comment(tctx, "Testing EnumPrinterDataEx(%s)\n", key_name);
2965 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_EnumPrinterDataEx(p, tctx, &r),
2966 "EnumPrinterDataEx failed");
2967 if (W_ERROR_EQUAL(r.out.result, WERR_MORE_DATA)) {
2968 r.in.offered = needed;
2969 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_EnumPrinterDataEx(p, tctx, &r),
2970 "EnumPrinterDataEx failed");
2973 torture_assert_werr_ok(tctx, r.out.result, "EnumPrinterDataEx failed");
2975 CHECK_NEEDED_SIZE_ENUM(spoolss_EnumPrinterDataEx, info, count, lp_iconv_convenience(tctx->lp_ctx), needed, 1);
2977 return true;
2981 static bool test_DeletePrinterData(struct torture_context *tctx,
2982 struct dcerpc_pipe *p,
2983 struct policy_handle *handle,
2984 const char *value_name)
2986 NTSTATUS status;
2987 struct spoolss_DeletePrinterData r;
2989 r.in.handle = handle;
2990 r.in.value_name = value_name;
2992 torture_comment(tctx, "Testing DeletePrinterData(%s)\n",
2993 r.in.value_name);
2995 status = dcerpc_spoolss_DeletePrinterData(p, tctx, &r);
2997 torture_assert_ntstatus_ok(tctx, status, "DeletePrinterData failed");
2998 torture_assert_werr_ok(tctx, r.out.result, "DeletePrinterData failed");
3000 return true;
3003 static bool test_DeletePrinterDataEx(struct torture_context *tctx,
3004 struct dcerpc_pipe *p,
3005 struct policy_handle *handle,
3006 const char *key_name,
3007 const char *value_name)
3009 struct spoolss_DeletePrinterDataEx r;
3011 r.in.handle = handle;
3012 r.in.key_name = key_name;
3013 r.in.value_name = value_name;
3015 torture_comment(tctx, "Testing DeletePrinterDataEx(%s - %s)\n",
3016 r.in.key_name, r.in.value_name);
3018 torture_assert_ntstatus_ok(tctx,
3019 dcerpc_spoolss_DeletePrinterDataEx(p, tctx, &r),
3020 "DeletePrinterDataEx failed");
3021 torture_assert_werr_ok(tctx, r.out.result,
3022 "DeletePrinterDataEx failed");
3024 return true;
3027 static bool test_DeletePrinterKey(struct torture_context *tctx,
3028 struct dcerpc_pipe *p,
3029 struct policy_handle *handle,
3030 const char *key_name)
3032 struct spoolss_DeletePrinterKey r;
3034 r.in.handle = handle;
3035 r.in.key_name = key_name;
3037 torture_comment(tctx, "Testing DeletePrinterKey(%s)\n", r.in.key_name);
3039 if (strequal(key_name, "") && !torture_setting_bool(tctx, "dangerous", false)) {
3040 torture_skip(tctx, "not wiping out printer registry - enable dangerous tests to use\n");
3041 return true;
3044 torture_assert_ntstatus_ok(tctx,
3045 dcerpc_spoolss_DeletePrinterKey(p, tctx, &r),
3046 "DeletePrinterKey failed");
3047 torture_assert_werr_ok(tctx, r.out.result,
3048 "DeletePrinterKey failed");
3050 return true;
3053 static bool test_SetPrinterData(struct torture_context *tctx,
3054 struct dcerpc_pipe *p,
3055 struct policy_handle *handle)
3057 NTSTATUS status;
3058 struct spoolss_SetPrinterData r;
3059 const char *values[] = {
3060 "spootyfoot",
3061 "spooty\\foot",
3062 #if 0
3063 /* FIXME: not working with s3 atm. */
3064 "spooty,foot",
3065 "spooty,fo,ot",
3066 #endif
3067 "spooty foot",
3068 #if 0
3069 /* FIXME: not working with s3 atm. */
3070 "spooty\\fo,ot",
3071 "spooty,fo\\ot"
3072 #endif
3074 int i;
3076 for (i=0; i < ARRAY_SIZE(values); i++) {
3078 enum winreg_Type type;
3079 union spoolss_PrinterData data;
3081 r.in.handle = handle;
3082 r.in.value_name = values[i];
3083 r.in.type = REG_SZ;
3084 r.in.data.string = "dog";
3086 torture_comment(tctx, "Testing SetPrinterData(%s)\n",
3087 r.in.value_name);
3089 status = dcerpc_spoolss_SetPrinterData(p, tctx, &r);
3091 torture_assert_ntstatus_ok(tctx, status, "SetPrinterData failed");
3092 torture_assert_werr_ok(tctx, r.out.result, "SetPrinterData failed");
3094 if (!test_GetPrinterData(tctx, p, handle, r.in.value_name, &type, &data)) {
3095 return false;
3098 torture_assert_int_equal(tctx, r.in.type, type, "type mismatch");
3099 torture_assert_str_equal(tctx, r.in.data.string, data.string, "data mismatch");
3101 if (!test_DeletePrinterData(tctx, p, handle, r.in.value_name)) {
3102 return false;
3106 return true;
3109 static bool test_EnumPrinterKey(struct torture_context *tctx,
3110 struct dcerpc_pipe *p,
3111 struct policy_handle *handle,
3112 const char *key_name,
3113 const char ***array);
3115 static bool test_SetPrinterDataEx(struct torture_context *tctx,
3116 struct dcerpc_pipe *p,
3117 struct policy_handle *handle)
3119 NTSTATUS status;
3120 struct spoolss_SetPrinterDataEx r;
3121 const char *value_name = "dog";
3122 const char *keys[] = {
3123 "torturedataex",
3124 "torture data ex",
3125 #if 0
3126 /* FIXME: not working with s3 atm. */
3127 "torturedataex_with_subkey\\subkey",
3128 "torturedataex_with_subkey\\subkey:0",
3129 "torturedataex_with_subkey\\subkey:1",
3130 "torturedataex_with_subkey\\subkey\\subsubkey",
3131 "torturedataex_with_subkey\\subkey\\subsubkey:0",
3132 "torturedataex_with_subkey\\subkey\\subsubkey:1",
3133 #endif
3134 "torture,data",
3135 #if 0
3136 /* FIXME: not working with s3 atm. */
3138 "torture,data,ex",
3139 "torture,data\\ex",
3140 "torture\\data,ex"
3141 #endif
3143 int i;
3144 DATA_BLOB blob = data_blob_string_const("catfoobar");
3147 for (i=0; i < ARRAY_SIZE(keys); i++) {
3149 char *c;
3150 const char *key;
3151 enum winreg_Type type;
3152 const char **subkeys;
3153 union spoolss_PrinterData data;
3155 r.in.handle = handle;
3156 r.in.key_name = keys[i];
3157 r.in.value_name = value_name;
3158 r.in.type = REG_BINARY;
3159 r.in.data.binary = blob;
3161 torture_comment(tctx, "Testing SetPrinterDataEx(%s - %s)\n", r.in.key_name, value_name);
3163 status = dcerpc_spoolss_SetPrinterDataEx(p, tctx, &r);
3165 torture_assert_ntstatus_ok(tctx, status, "SetPrinterDataEx failed");
3166 torture_assert_werr_ok(tctx, r.out.result, "SetPrinterDataEx failed");
3168 key = talloc_strdup(tctx, r.in.key_name);
3170 if (!test_GetPrinterDataEx(tctx, p, handle, r.in.key_name, value_name, &type, &data)) {
3171 return false;
3174 torture_assert_int_equal(tctx, r.in.type, type, "type mismatch");
3175 torture_assert_data_blob_equal(tctx, blob, data.binary, "data mismatch");
3177 if (!test_EnumPrinterDataEx(tctx, p, handle, r.in.key_name)) {
3178 return false;
3181 if (!test_DeletePrinterDataEx(tctx, p, handle, r.in.key_name, value_name)) {
3182 return false;
3185 c = strchr(key, '\\');
3186 if (c) {
3187 int i;
3189 /* we have subkeys */
3191 *c = 0;
3193 if (!test_EnumPrinterKey(tctx, p, handle, key, &subkeys)) {
3194 return false;
3197 for (i=0; subkeys && subkeys[i]; i++) {
3199 const char *current_key = talloc_asprintf(tctx, "%s\\%s", key, subkeys[i]);
3201 if (!test_DeletePrinterKey(tctx, p, handle, current_key)) {
3202 return false;
3206 if (!test_DeletePrinterKey(tctx, p, handle, key)) {
3207 return false;
3210 } else {
3211 if (!test_DeletePrinterKey(tctx, p, handle, key)) {
3212 return false;
3217 return true;
3220 static bool test_GetChangeID_PrinterData(struct torture_context *tctx,
3221 struct dcerpc_pipe *p,
3222 struct policy_handle *handle,
3223 uint32_t *change_id)
3225 enum winreg_Type type;
3226 union spoolss_PrinterData data;
3228 torture_assert(tctx,
3229 test_GetPrinterData(tctx, p, handle, "ChangeID", &type, &data),
3230 "failed to call GetPrinterData");
3232 torture_assert(tctx, type == REG_DWORD, "unexpected type");
3234 *change_id = data.value;
3236 return true;
3239 static bool test_GetChangeID_PrinterDataEx(struct torture_context *tctx,
3240 struct dcerpc_pipe *p,
3241 struct policy_handle *handle,
3242 uint32_t *change_id)
3244 enum winreg_Type type;
3245 union spoolss_PrinterData data;
3247 torture_assert(tctx,
3248 test_GetPrinterDataEx(tctx, p, handle, "PrinterDriverData", "ChangeID", &type, &data),
3249 "failed to call GetPrinterData");
3251 torture_assert(tctx, type == REG_DWORD, "unexpected type");
3253 *change_id = data.value;
3255 return true;
3258 static bool test_GetChangeID_PrinterInfo(struct torture_context *tctx,
3259 struct dcerpc_pipe *p,
3260 struct policy_handle *handle,
3261 uint32_t *change_id)
3263 union spoolss_PrinterInfo info;
3265 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 0, &info),
3266 "failed to query Printer level 0");
3268 *change_id = info.info0.change_id;
3270 return true;
3273 static bool test_ChangeID(struct torture_context *tctx,
3274 struct dcerpc_pipe *p,
3275 struct policy_handle *handle)
3277 uint32_t change_id, change_id_ex, change_id_info;
3278 uint32_t change_id2, change_id_ex2, change_id_info2;
3279 union spoolss_PrinterInfo info;
3280 const char *comment;
3283 torture_comment(tctx, "Testing ChangeID: id change test #1\n");
3285 torture_assert(tctx, test_GetChangeID_PrinterData(tctx, p, handle, &change_id),
3286 "failed to query for ChangeID");
3287 torture_assert(tctx, test_GetChangeID_PrinterDataEx(tctx, p, handle, &change_id_ex),
3288 "failed to query for ChangeID");
3289 torture_assert(tctx, test_GetChangeID_PrinterInfo(tctx, p, handle, &change_id_info),
3290 "failed to query for ChangeID");
3292 torture_assert_int_equal(tctx, change_id, change_id_ex,
3293 "change_ids should all be equal");
3294 torture_assert_int_equal(tctx, change_id_ex, change_id_info,
3295 "change_ids should all be equal");
3298 torture_comment(tctx, "Testing ChangeID: id change test #2\n");
3300 torture_assert(tctx, test_GetChangeID_PrinterData(tctx, p, handle, &change_id),
3301 "failed to query for ChangeID");
3302 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 2, &info),
3303 "failed to query Printer level 2");
3304 torture_assert(tctx, test_GetChangeID_PrinterDataEx(tctx, p, handle, &change_id_ex),
3305 "failed to query for ChangeID");
3306 torture_assert(tctx, test_GetChangeID_PrinterInfo(tctx, p, handle, &change_id_info),
3307 "failed to query for ChangeID");
3308 torture_assert_int_equal(tctx, change_id, change_id_ex,
3309 "change_id should not have changed");
3310 torture_assert_int_equal(tctx, change_id_ex, change_id_info,
3311 "change_id should not have changed");
3314 torture_comment(tctx, "Testing ChangeID: id change test #3\n");
3316 torture_assert(tctx, test_GetChangeID_PrinterData(tctx, p, handle, &change_id),
3317 "failed to query for ChangeID");
3318 torture_assert(tctx, test_GetChangeID_PrinterDataEx(tctx, p, handle, &change_id_ex),
3319 "failed to query for ChangeID");
3320 torture_assert(tctx, test_GetChangeID_PrinterInfo(tctx, p, handle, &change_id_info),
3321 "failed to query for ChangeID");
3322 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 2, &info),
3323 "failed to query Printer level 2");
3324 comment = talloc_strdup(tctx, info.info2.comment);
3327 struct spoolss_SetPrinterInfoCtr info_ctr;
3328 struct spoolss_DevmodeContainer devmode_ctr;
3329 struct sec_desc_buf secdesc_ctr;
3330 struct spoolss_SetPrinterInfo2 info2;
3332 ZERO_STRUCT(info_ctr);
3333 ZERO_STRUCT(devmode_ctr);
3334 ZERO_STRUCT(secdesc_ctr);
3336 info2.servername = info.info2.servername;
3337 info2.printername = info.info2.printername;
3338 info2.sharename = info.info2.sharename;
3339 info2.portname = info.info2.portname;
3340 info2.drivername = info.info2.drivername;
3341 info2.comment = "torture_comment";
3342 info2.location = info.info2.location;
3343 info2.devmode_ptr = 0;
3344 info2.sepfile = info.info2.sepfile;
3345 info2.printprocessor = info.info2.printprocessor;
3346 info2.datatype = info.info2.datatype;
3347 info2.parameters = info.info2.parameters;
3348 info2.secdesc_ptr = 0;
3349 info2.attributes = info.info2.attributes;
3350 info2.priority = info.info2.priority;
3351 info2.defaultpriority = info.info2.defaultpriority;
3352 info2.starttime = info.info2.starttime;
3353 info2.untiltime = info.info2.untiltime;
3354 info2.status = info.info2.status;
3355 info2.cjobs = info.info2.cjobs;
3356 info2.averageppm = info.info2.averageppm;
3358 info_ctr.level = 2;
3359 info_ctr.info.info2 = &info2;
3361 torture_assert(tctx, test_SetPrinter(tctx, p, handle, &info_ctr, &devmode_ctr, &secdesc_ctr, 0),
3362 "failed to call SetPrinter");
3364 info2.comment = comment;
3366 torture_assert(tctx, test_SetPrinter(tctx, p, handle, &info_ctr, &devmode_ctr, &secdesc_ctr, 0),
3367 "failed to call SetPrinter");
3371 torture_assert(tctx, test_GetChangeID_PrinterData(tctx, p, handle, &change_id2),
3372 "failed to query for ChangeID");
3373 torture_assert(tctx, test_GetChangeID_PrinterDataEx(tctx, p, handle, &change_id_ex2),
3374 "failed to query for ChangeID");
3375 torture_assert(tctx, test_GetChangeID_PrinterInfo(tctx, p, handle, &change_id_info2),
3376 "failed to query for ChangeID");
3378 torture_assert_int_equal(tctx, change_id2, change_id_ex2,
3379 "change_ids should all be equal");
3380 torture_assert_int_equal(tctx, change_id_ex2, change_id_info2,
3381 "change_ids should all be equal");
3383 torture_assert(tctx, (change_id < change_id2),
3384 talloc_asprintf(tctx, "change_id %d needs to be larger than change_id %d",
3385 change_id2, change_id));
3386 torture_assert(tctx, (change_id_ex < change_id_ex2),
3387 talloc_asprintf(tctx, "change_id %d needs to be larger than change_id %d",
3388 change_id_ex2, change_id_ex));
3389 torture_assert(tctx, (change_id_info < change_id_info2),
3390 talloc_asprintf(tctx, "change_id %d needs to be larger than change_id %d",
3391 change_id_info2, change_id_info));
3393 return true;
3396 static bool test_SecondaryClosePrinter(struct torture_context *tctx,
3397 struct dcerpc_pipe *p,
3398 struct policy_handle *handle)
3400 NTSTATUS status;
3401 struct dcerpc_binding *b;
3402 struct dcerpc_pipe *p2;
3403 struct spoolss_ClosePrinter cp;
3405 /* only makes sense on SMB */
3406 if (p->conn->transport.transport != NCACN_NP) {
3407 return true;
3410 torture_comment(tctx, "testing close on secondary pipe\n");
3412 status = dcerpc_parse_binding(tctx, p->conn->binding_string, &b);
3413 torture_assert_ntstatus_ok(tctx, status, "Failed to parse dcerpc binding");
3415 status = dcerpc_secondary_connection(p, &p2, b);
3416 torture_assert_ntstatus_ok(tctx, status, "Failed to create secondary connection");
3418 status = dcerpc_bind_auth_none(p2, &ndr_table_spoolss);
3419 torture_assert_ntstatus_ok(tctx, status, "Failed to create bind on secondary connection");
3421 cp.in.handle = handle;
3422 cp.out.handle = handle;
3424 status = dcerpc_spoolss_ClosePrinter(p2, tctx, &cp);
3425 torture_assert_ntstatus_equal(tctx, status, NT_STATUS_NET_WRITE_FAULT,
3426 "ERROR: Allowed close on secondary connection");
3428 torture_assert_int_equal(tctx, p2->last_fault_code, DCERPC_FAULT_CONTEXT_MISMATCH,
3429 "Unexpected fault code");
3431 talloc_free(p2);
3433 return true;
3436 static bool test_OpenPrinter_badname(struct torture_context *tctx,
3437 struct dcerpc_pipe *p, const char *name)
3439 NTSTATUS status;
3440 struct spoolss_OpenPrinter op;
3441 struct spoolss_OpenPrinterEx opEx;
3442 struct policy_handle handle;
3443 bool ret = true;
3445 op.in.printername = name;
3446 op.in.datatype = NULL;
3447 op.in.devmode_ctr.devmode= NULL;
3448 op.in.access_mask = 0;
3449 op.out.handle = &handle;
3451 torture_comment(tctx, "\nTesting OpenPrinter(%s) with bad name\n", op.in.printername);
3453 status = dcerpc_spoolss_OpenPrinter(p, tctx, &op);
3454 torture_assert_ntstatus_ok(tctx, status, "OpenPrinter failed");
3455 if (!W_ERROR_EQUAL(WERR_INVALID_PRINTER_NAME,op.out.result)) {
3456 torture_comment(tctx, "OpenPrinter(%s) unexpected result[%s] should be WERR_INVALID_PRINTER_NAME\n",
3457 name, win_errstr(op.out.result));
3460 if (W_ERROR_IS_OK(op.out.result)) {
3461 ret &=test_ClosePrinter(tctx, p, &handle);
3464 opEx.in.printername = name;
3465 opEx.in.datatype = NULL;
3466 opEx.in.devmode_ctr.devmode = NULL;
3467 opEx.in.access_mask = 0;
3468 opEx.in.level = 1;
3469 opEx.in.userlevel.level1 = NULL;
3470 opEx.out.handle = &handle;
3472 torture_comment(tctx, "Testing OpenPrinterEx(%s) with bad name\n", opEx.in.printername);
3474 status = dcerpc_spoolss_OpenPrinterEx(p, tctx, &opEx);
3475 torture_assert_ntstatus_ok(tctx, status, "OpenPrinterEx failed");
3476 if (!W_ERROR_EQUAL(WERR_INVALID_PARAM,opEx.out.result)) {
3477 torture_comment(tctx, "OpenPrinterEx(%s) unexpected result[%s] should be WERR_INVALID_PARAM\n",
3478 name, win_errstr(opEx.out.result));
3481 if (W_ERROR_IS_OK(opEx.out.result)) {
3482 ret &=test_ClosePrinter(tctx, p, &handle);
3485 return ret;
3488 static bool test_OpenPrinter(struct torture_context *tctx,
3489 struct dcerpc_pipe *p,
3490 const char *name)
3492 NTSTATUS status;
3493 struct spoolss_OpenPrinter r;
3494 struct policy_handle handle;
3495 bool ret = true;
3497 r.in.printername = talloc_asprintf(tctx, "\\\\%s\\%s", dcerpc_server_name(p), name);
3498 r.in.datatype = NULL;
3499 r.in.devmode_ctr.devmode= NULL;
3500 r.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
3501 r.out.handle = &handle;
3503 torture_comment(tctx, "Testing OpenPrinter(%s)\n", r.in.printername);
3505 status = dcerpc_spoolss_OpenPrinter(p, tctx, &r);
3507 torture_assert_ntstatus_ok(tctx, status, "OpenPrinter failed");
3509 torture_assert_werr_ok(tctx, r.out.result, "OpenPrinter failed");
3511 if (!test_GetPrinter(tctx, p, &handle)) {
3512 ret = false;
3515 if (!torture_setting_bool(tctx, "samba3", false)) {
3516 if (!test_SecondaryClosePrinter(tctx, p, &handle)) {
3517 ret = false;
3521 if (!test_ClosePrinter(tctx, p, &handle)) {
3522 ret = false;
3525 return ret;
3528 static bool call_OpenPrinterEx(struct torture_context *tctx,
3529 struct dcerpc_pipe *p,
3530 const char *name,
3531 struct spoolss_DeviceMode *devmode,
3532 struct policy_handle *handle)
3534 struct spoolss_OpenPrinterEx r;
3535 struct spoolss_UserLevel1 userlevel1;
3536 NTSTATUS status;
3538 if (name && name[0]) {
3539 r.in.printername = talloc_asprintf(tctx, "\\\\%s\\%s",
3540 dcerpc_server_name(p), name);
3541 } else {
3542 r.in.printername = talloc_asprintf(tctx, "\\\\%s",
3543 dcerpc_server_name(p));
3546 r.in.datatype = NULL;
3547 r.in.devmode_ctr.devmode= devmode;
3548 r.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
3549 r.in.level = 1;
3550 r.in.userlevel.level1 = &userlevel1;
3551 r.out.handle = handle;
3553 userlevel1.size = 1234;
3554 userlevel1.client = "hello";
3555 userlevel1.user = "spottyfoot!";
3556 userlevel1.build = 1;
3557 userlevel1.major = 2;
3558 userlevel1.minor = 3;
3559 userlevel1.processor = 4;
3561 torture_comment(tctx, "Testing OpenPrinterEx(%s)\n", r.in.printername);
3563 status = dcerpc_spoolss_OpenPrinterEx(p, tctx, &r);
3565 torture_assert_ntstatus_ok(tctx, status, "OpenPrinterEx failed");
3567 torture_assert_werr_ok(tctx, r.out.result, "OpenPrinterEx failed");
3569 return true;
3572 static bool test_OpenPrinterEx(struct torture_context *tctx,
3573 struct dcerpc_pipe *p,
3574 const char *name)
3576 struct policy_handle handle;
3577 bool ret = true;
3579 if (!call_OpenPrinterEx(tctx, p, name, NULL, &handle)) {
3580 return false;
3583 if (!test_PrinterInfo_SD(tctx, p, &handle)) {
3584 ret = false;
3587 if (!test_GetPrinter(tctx, p, &handle)) {
3588 ret = false;
3591 if (!test_EnumForms(tctx, p, &handle, false)) {
3592 ret = false;
3595 if (!test_AddForm(tctx, p, &handle, false)) {
3596 ret = false;
3599 if (!test_EnumPrinterData(tctx, p, &handle)) {
3600 ret = false;
3603 if (!test_EnumPrinterDataEx(tctx, p, &handle, "PrinterDriverData")) {
3604 ret = false;
3607 if (!test_printer_keys(tctx, p, &handle)) {
3608 ret = false;
3611 if (!test_PausePrinter(tctx, p, &handle)) {
3612 ret = false;
3615 if (!test_DoPrintTest(tctx, p, &handle)) {
3616 ret = false;
3619 if (!test_ResumePrinter(tctx, p, &handle)) {
3620 ret = false;
3623 if (!test_SetPrinterData(tctx, p, &handle)) {
3624 ret = false;
3627 if (!test_SetPrinterDataEx(tctx, p, &handle)) {
3628 ret = false;
3631 if (!test_ChangeID(tctx, p, &handle)) {
3632 ret = false;
3635 if (!torture_setting_bool(tctx, "samba3", false)) {
3636 if (!test_SecondaryClosePrinter(tctx, p, &handle)) {
3637 ret = false;
3641 if (!test_ClosePrinter(tctx, p, &handle)) {
3642 ret = false;
3645 return ret;
3648 static bool test_EnumPrinters_old(struct torture_context *tctx, struct dcerpc_pipe *p)
3650 struct spoolss_EnumPrinters r;
3651 NTSTATUS status;
3652 uint16_t levels[] = {1, 2, 4, 5};
3653 int i;
3654 bool ret = true;
3656 for (i=0;i<ARRAY_SIZE(levels);i++) {
3657 union spoolss_PrinterInfo *info;
3658 int j;
3659 uint32_t needed;
3660 uint32_t count;
3662 r.in.flags = PRINTER_ENUM_LOCAL;
3663 r.in.server = "";
3664 r.in.level = levels[i];
3665 r.in.buffer = NULL;
3666 r.in.offered = 0;
3667 r.out.needed = &needed;
3668 r.out.count = &count;
3669 r.out.info = &info;
3671 torture_comment(tctx, "Testing EnumPrinters level %u\n", r.in.level);
3673 status = dcerpc_spoolss_EnumPrinters(p, tctx, &r);
3674 torture_assert_ntstatus_ok(tctx, status, "EnumPrinters failed");
3676 if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
3677 DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed);
3678 data_blob_clear(&blob);
3679 r.in.buffer = &blob;
3680 r.in.offered = needed;
3681 status = dcerpc_spoolss_EnumPrinters(p, tctx, &r);
3684 torture_assert_ntstatus_ok(tctx, status, "EnumPrinters failed");
3686 torture_assert_werr_ok(tctx, r.out.result, "EnumPrinters failed");
3688 CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumPrinters, info, r.in.level, count, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
3690 if (!info) {
3691 torture_comment(tctx, "No printers returned\n");
3692 return true;
3695 for (j=0;j<count;j++) {
3696 if (r.in.level == 1) {
3697 char *unc = talloc_strdup(tctx, info[j].info1.name);
3698 char *slash, *name;
3699 name = unc;
3700 if (unc[0] == '\\' && unc[1] == '\\') {
3701 unc +=2;
3703 slash = strchr(unc, '\\');
3704 if (slash) {
3705 slash++;
3706 name = slash;
3708 if (!test_OpenPrinter(tctx, p, name)) {
3709 ret = false;
3711 if (!test_OpenPrinterEx(tctx, p, name)) {
3712 ret = false;
3718 return ret;
3721 static bool test_GetPrinterDriver(struct torture_context *tctx,
3722 struct dcerpc_pipe *p,
3723 struct policy_handle *handle,
3724 const char *driver_name)
3726 struct spoolss_GetPrinterDriver r;
3727 uint32_t needed;
3729 r.in.handle = handle;
3730 r.in.architecture = "W32X86";
3731 r.in.level = 1;
3732 r.in.buffer = NULL;
3733 r.in.offered = 0;
3734 r.out.needed = &needed;
3736 torture_comment(tctx, "Testing GetPrinterDriver level %d\n", r.in.level);
3738 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_GetPrinterDriver(p, tctx, &r),
3739 "failed to call GetPrinterDriver");
3740 if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
3741 DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed);
3742 data_blob_clear(&blob);
3743 r.in.buffer = &blob;
3744 r.in.offered = needed;
3745 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_GetPrinterDriver(p, tctx, &r),
3746 "failed to call GetPrinterDriver");
3749 torture_assert_werr_ok(tctx, r.out.result,
3750 "failed to call GetPrinterDriver");
3752 CHECK_NEEDED_SIZE_LEVEL(spoolss_DriverInfo, r.out.info, r.in.level, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
3754 return true;
3757 static bool test_GetPrinterDriver2(struct torture_context *tctx,
3758 struct dcerpc_pipe *p,
3759 struct policy_handle *handle,
3760 const char *driver_name)
3762 struct spoolss_GetPrinterDriver2 r;
3763 uint16_t levels[] = {1, 2, 3, 4, 5, 6, 8, 101 };
3764 uint32_t needed;
3765 uint32_t server_major_version;
3766 uint32_t server_minor_version;
3767 int i;
3769 r.in.handle = handle;
3770 r.in.architecture = SPOOLSS_ARCHITECTURE_NT_X86;
3771 r.in.client_major_version = 3;
3772 r.in.client_minor_version = 0;
3773 r.out.needed = &needed;
3774 r.out.server_major_version = &server_major_version;
3775 r.out.server_minor_version = &server_minor_version;
3777 for (i=0;i<ARRAY_SIZE(levels);i++) {
3779 r.in.buffer = NULL;
3780 r.in.offered = 0;
3781 r.in.level = levels[i];
3783 torture_comment(tctx, "Testing GetPrinterDriver2(%s) level %d\n",
3784 driver_name, r.in.level);
3786 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_GetPrinterDriver2(p, tctx, &r),
3787 "failed to call GetPrinterDriver2");
3788 if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
3789 DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed);
3790 data_blob_clear(&blob);
3791 r.in.buffer = &blob;
3792 r.in.offered = needed;
3793 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_GetPrinterDriver2(p, tctx, &r),
3794 "failed to call GetPrinterDriver2");
3797 if (W_ERROR_EQUAL(r.out.result, WERR_INVALID_LEVEL)) {
3798 switch (r.in.level) {
3799 case 101:
3800 case 8:
3801 continue;
3802 default:
3803 break;
3807 torture_assert_werr_ok(tctx, r.out.result,
3808 "failed to call GetPrinterDriver2");
3810 CHECK_NEEDED_SIZE_LEVEL(spoolss_DriverInfo, r.out.info, r.in.level, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
3813 return true;
3816 static bool test_EnumPrinterDrivers_old(struct torture_context *tctx,
3817 struct dcerpc_pipe *p)
3819 struct spoolss_EnumPrinterDrivers r;
3820 NTSTATUS status;
3821 uint16_t levels[] = {1, 2, 3, 4, 5, 6};
3822 int i;
3824 for (i=0;i<ARRAY_SIZE(levels);i++) {
3826 uint32_t needed;
3827 uint32_t count;
3828 union spoolss_DriverInfo *info;
3830 r.in.server = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
3831 r.in.environment = SPOOLSS_ARCHITECTURE_NT_X86;
3832 r.in.level = levels[i];
3833 r.in.buffer = NULL;
3834 r.in.offered = 0;
3835 r.out.needed = &needed;
3836 r.out.count = &count;
3837 r.out.info = &info;
3839 torture_comment(tctx, "Testing EnumPrinterDrivers level %u\n", r.in.level);
3841 status = dcerpc_spoolss_EnumPrinterDrivers(p, tctx, &r);
3843 torture_assert_ntstatus_ok(tctx, status, "EnumPrinterDrivers failed");
3845 if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
3846 DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed);
3847 data_blob_clear(&blob);
3848 r.in.buffer = &blob;
3849 r.in.offered = needed;
3850 status = dcerpc_spoolss_EnumPrinterDrivers(p, tctx, &r);
3853 torture_assert_ntstatus_ok(tctx, status, "EnumPrinterDrivers failed");
3855 torture_assert_werr_ok(tctx, r.out.result, "EnumPrinterDrivers failed");
3857 if (!info) {
3858 torture_comment(tctx, "No printer drivers returned\n");
3859 break;
3862 CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumPrinterDrivers, info, r.in.level, count, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
3865 return true;
3868 static bool test_DeletePrinter(struct torture_context *tctx,
3869 struct dcerpc_pipe *p,
3870 struct policy_handle *handle)
3872 struct spoolss_DeletePrinter r;
3874 torture_comment(tctx, "Testing DeletePrinter\n");
3876 r.in.handle = handle;
3878 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_DeletePrinter(p, tctx, &r),
3879 "failed to delete printer");
3880 torture_assert_werr_ok(tctx, r.out.result,
3881 "failed to delete printer");
3883 return true;
3886 static bool test_EnumPrinters_findname(struct torture_context *tctx,
3887 struct dcerpc_pipe *p,
3888 uint32_t flags,
3889 uint32_t level,
3890 const char *name,
3891 bool *found)
3893 struct spoolss_EnumPrinters e;
3894 uint32_t count;
3895 union spoolss_PrinterInfo *info;
3896 uint32_t needed;
3897 int i;
3899 *found = false;
3901 e.in.flags = flags;
3902 e.in.server = NULL;
3903 e.in.level = level;
3904 e.in.buffer = NULL;
3905 e.in.offered = 0;
3906 e.out.count = &count;
3907 e.out.info = &info;
3908 e.out.needed = &needed;
3910 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_EnumPrinters(p, tctx, &e),
3911 "failed to enum printers");
3913 if (W_ERROR_EQUAL(e.out.result, WERR_INSUFFICIENT_BUFFER)) {
3914 DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed);
3915 data_blob_clear(&blob);
3916 e.in.buffer = &blob;
3917 e.in.offered = needed;
3919 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_EnumPrinters(p, tctx, &e),
3920 "failed to enum printers");
3923 torture_assert_werr_ok(tctx, e.out.result,
3924 "failed to enum printers");
3926 for (i=0; i < count; i++) {
3928 const char *current = NULL;
3929 const char *p;
3931 switch (level) {
3932 case 1:
3933 current = info[i].info1.name;
3934 break;
3937 if (strequal(current, name)) {
3938 *found = true;
3939 break;
3942 p = strrchr(current, '\\');
3943 if (p) {
3944 if (!e.in.server) {
3945 torture_warning(tctx,
3946 "server returns printername %s incl. servername although we did not set servername", current);
3948 p++;
3949 if (strequal(p, name)) {
3950 *found = true;
3951 break;
3956 return true;
3959 static bool test_AddPrinter_wellknown(struct torture_context *tctx,
3960 struct dcerpc_pipe *p,
3961 const char *printername,
3962 bool ex)
3964 WERROR result;
3965 struct spoolss_AddPrinter r;
3966 struct spoolss_AddPrinterEx rex;
3967 struct spoolss_SetPrinterInfoCtr info_ctr;
3968 struct spoolss_SetPrinterInfo1 info1;
3969 struct spoolss_DevmodeContainer devmode_ctr;
3970 struct sec_desc_buf secdesc_ctr;
3971 struct spoolss_UserLevelCtr userlevel_ctr;
3972 struct policy_handle handle;
3973 bool found = false;
3975 ZERO_STRUCT(devmode_ctr);
3976 ZERO_STRUCT(secdesc_ctr);
3977 ZERO_STRUCT(userlevel_ctr);
3978 ZERO_STRUCT(info1);
3980 torture_comment(tctx, "Testing AddPrinter%s level 1\n", ex ? "Ex":"");
3982 /* try to add printer to wellknown printer list (level 1) */
3984 userlevel_ctr.level = 1;
3986 info_ctr.info.info1 = &info1;
3987 info_ctr.level = 1;
3989 rex.in.server = NULL;
3990 rex.in.info_ctr = &info_ctr;
3991 rex.in.devmode_ctr = &devmode_ctr;
3992 rex.in.secdesc_ctr = &secdesc_ctr;
3993 rex.in.userlevel_ctr = &userlevel_ctr;
3994 rex.out.handle = &handle;
3996 r.in.server = NULL;
3997 r.in.info_ctr = &info_ctr;
3998 r.in.devmode_ctr = &devmode_ctr;
3999 r.in.secdesc_ctr = &secdesc_ctr;
4000 r.out.handle = &handle;
4002 torture_assert_ntstatus_ok(tctx, ex ? dcerpc_spoolss_AddPrinterEx(p, tctx, &rex) :
4003 dcerpc_spoolss_AddPrinter(p, tctx, &r),
4004 "failed to add printer");
4005 result = ex ? rex.out.result : r.out.result;
4006 torture_assert_werr_equal(tctx, result, WERR_INVALID_PRINTER_NAME,
4007 "unexpected result code");
4009 info1.name = printername;
4010 info1.flags = PRINTER_ATTRIBUTE_SHARED;
4012 torture_assert_ntstatus_ok(tctx, ex ? dcerpc_spoolss_AddPrinterEx(p, tctx, &rex) :
4013 dcerpc_spoolss_AddPrinter(p, tctx, &r),
4014 "failed to add printer");
4015 result = ex ? rex.out.result : r.out.result;
4016 torture_assert_werr_equal(tctx, result, WERR_PRINTER_ALREADY_EXISTS,
4017 "unexpected result code");
4019 /* bizarre protocol, WERR_PRINTER_ALREADY_EXISTS means success here,
4020 better do a real check to see the printer is really there */
4022 torture_assert(tctx, test_EnumPrinters_findname(tctx, p,
4023 PRINTER_ENUM_NETWORK, 1,
4024 printername,
4025 &found),
4026 "failed to enum printers");
4028 torture_assert(tctx, found, "failed to find newly added printer");
4030 info1.flags = 0;
4032 torture_assert_ntstatus_ok(tctx, ex ? dcerpc_spoolss_AddPrinterEx(p, tctx, &rex) :
4033 dcerpc_spoolss_AddPrinter(p, tctx, &r),
4034 "failed to add printer");
4035 result = ex ? rex.out.result : r.out.result;
4036 torture_assert_werr_equal(tctx, result, WERR_PRINTER_ALREADY_EXISTS,
4037 "unexpected result code");
4039 /* bizarre protocol, WERR_PRINTER_ALREADY_EXISTS means success here,
4040 better do a real check to see the printer has really been removed
4041 from the well known printer list */
4043 found = false;
4045 torture_assert(tctx, test_EnumPrinters_findname(tctx, p,
4046 PRINTER_ENUM_NETWORK, 1,
4047 printername,
4048 &found),
4049 "failed to enum printers");
4050 #if 0
4051 torture_assert(tctx, !found, "printer still in well known printer list");
4052 #endif
4053 return true;
4056 static bool test_AddPrinter_normal(struct torture_context *tctx,
4057 struct dcerpc_pipe *p,
4058 struct policy_handle *handle_p,
4059 const char *printername,
4060 const char *drivername,
4061 const char *portname,
4062 bool ex)
4064 WERROR result;
4065 struct spoolss_AddPrinter r;
4066 struct spoolss_AddPrinterEx rex;
4067 struct spoolss_SetPrinterInfoCtr info_ctr;
4068 struct spoolss_SetPrinterInfo2 info2;
4069 struct spoolss_DevmodeContainer devmode_ctr;
4070 struct sec_desc_buf secdesc_ctr;
4071 struct spoolss_UserLevelCtr userlevel_ctr;
4072 struct policy_handle handle;
4073 bool found = false;
4074 bool existing_printer_deleted = false;
4076 ZERO_STRUCT(devmode_ctr);
4077 ZERO_STRUCT(secdesc_ctr);
4078 ZERO_STRUCT(userlevel_ctr);
4080 torture_comment(tctx, "Testing AddPrinter%s level 2\n", ex ? "Ex":"");
4082 userlevel_ctr.level = 1;
4084 rex.in.server = NULL;
4085 rex.in.info_ctr = &info_ctr;
4086 rex.in.devmode_ctr = &devmode_ctr;
4087 rex.in.secdesc_ctr = &secdesc_ctr;
4088 rex.in.userlevel_ctr = &userlevel_ctr;
4089 rex.out.handle = &handle;
4091 r.in.server = NULL;
4092 r.in.info_ctr = &info_ctr;
4093 r.in.devmode_ctr = &devmode_ctr;
4094 r.in.secdesc_ctr = &secdesc_ctr;
4095 r.out.handle = &handle;
4097 again:
4099 /* try to add printer to printer list (level 2) */
4101 ZERO_STRUCT(info2);
4103 info_ctr.info.info2 = &info2;
4104 info_ctr.level = 2;
4106 torture_assert_ntstatus_ok(tctx, ex ? dcerpc_spoolss_AddPrinterEx(p, tctx, &rex) :
4107 dcerpc_spoolss_AddPrinter(p, tctx, &r),
4108 "failed to add printer");
4109 result = ex ? rex.out.result : r.out.result;
4110 torture_assert_werr_equal(tctx, result, WERR_INVALID_PRINTER_NAME,
4111 "unexpected result code");
4113 info2.printername = printername;
4115 torture_assert_ntstatus_ok(tctx, ex ? dcerpc_spoolss_AddPrinterEx(p, tctx, &rex) :
4116 dcerpc_spoolss_AddPrinter(p, tctx, &r),
4117 "failed to add printer");
4118 result = ex ? rex.out.result : r.out.result;
4120 if (W_ERROR_EQUAL(result, WERR_PRINTER_ALREADY_EXISTS)) {
4121 struct policy_handle printer_handle;
4123 if (existing_printer_deleted) {
4124 torture_fail(tctx, "already deleted printer still existing?");
4127 torture_assert(tctx, call_OpenPrinterEx(tctx, p, printername, NULL, &printer_handle),
4128 "failed to open printer handle");
4130 torture_assert(tctx, test_DeletePrinter(tctx, p, &printer_handle),
4131 "failed to delete printer");
4133 torture_assert(tctx, test_ClosePrinter(tctx, p, &printer_handle),
4134 "failed to close server handle");
4136 existing_printer_deleted = true;
4138 goto again;
4141 torture_assert_werr_equal(tctx, result, WERR_UNKNOWN_PORT,
4142 "unexpected result code");
4144 info2.portname = portname;
4146 torture_assert_ntstatus_ok(tctx, ex ? dcerpc_spoolss_AddPrinterEx(p, tctx, &rex) :
4147 dcerpc_spoolss_AddPrinter(p, tctx, &r),
4148 "failed to add printer");
4149 result = ex ? rex.out.result : r.out.result;
4150 torture_assert_werr_equal(tctx, result, WERR_UNKNOWN_PRINTER_DRIVER,
4151 "unexpected result code");
4153 info2.drivername = drivername;
4155 torture_assert_ntstatus_ok(tctx, ex ? dcerpc_spoolss_AddPrinterEx(p, tctx, &rex) :
4156 dcerpc_spoolss_AddPrinter(p, tctx, &r),
4157 "failed to add printer");
4158 result = ex ? rex.out.result : r.out.result;
4160 /* w2k8r2 allows to add printer w/o defining printprocessor */
4162 if (!W_ERROR_IS_OK(result)) {
4163 torture_assert_werr_equal(tctx, result, WERR_UNKNOWN_PRINTPROCESSOR,
4164 "unexpected result code");
4166 info2.printprocessor = "winprint";
4168 torture_assert_ntstatus_ok(tctx, ex ? dcerpc_spoolss_AddPrinterEx(p, tctx, &rex) :
4169 dcerpc_spoolss_AddPrinter(p, tctx, &r),
4170 "failed to add printer");
4171 result = ex ? rex.out.result : r.out.result;
4172 torture_assert_werr_ok(tctx, result,
4173 "failed to add printer");
4176 *handle_p = handle;
4178 /* we are paranoid, really check if the printer is there now */
4180 torture_assert(tctx, test_EnumPrinters_findname(tctx, p,
4181 PRINTER_ENUM_LOCAL, 1,
4182 printername,
4183 &found),
4184 "failed to enum printers");
4185 torture_assert(tctx, found, "failed to find newly added printer");
4187 torture_assert_ntstatus_ok(tctx, ex ? dcerpc_spoolss_AddPrinterEx(p, tctx, &rex) :
4188 dcerpc_spoolss_AddPrinter(p, tctx, &r),
4189 "failed to add printer");
4190 result = ex ? rex.out.result : r.out.result;
4191 torture_assert_werr_equal(tctx, result, WERR_PRINTER_ALREADY_EXISTS,
4192 "unexpected result code");
4194 return true;
4197 static bool test_AddPrinterEx(struct torture_context *tctx,
4198 struct dcerpc_pipe *p,
4199 struct policy_handle *handle_p,
4200 const char *printername,
4201 const char *drivername,
4202 const char *portname)
4204 bool ret = true;
4206 if (!torture_setting_bool(tctx, "samba3", false)) {
4207 if (!test_AddPrinter_wellknown(tctx, p, TORTURE_WELLKNOWN_PRINTER_EX, true)) {
4208 torture_comment(tctx, "failed to add printer to well known list\n");
4209 ret = false;
4213 if (!test_AddPrinter_normal(tctx, p, handle_p,
4214 printername, drivername, portname,
4215 true)) {
4216 torture_comment(tctx, "failed to add printer to printer list\n");
4217 ret = false;
4220 return ret;
4223 static bool test_AddPrinter(struct torture_context *tctx,
4224 struct dcerpc_pipe *p,
4225 struct policy_handle *handle_p,
4226 const char *printername,
4227 const char *drivername,
4228 const char *portname)
4230 bool ret = true;
4232 if (!torture_setting_bool(tctx, "samba3", false)) {
4233 if (!test_AddPrinter_wellknown(tctx, p, TORTURE_WELLKNOWN_PRINTER, false)) {
4234 torture_comment(tctx, "failed to add printer to well known list\n");
4235 ret = false;
4239 if (!test_AddPrinter_normal(tctx, p, handle_p,
4240 printername, drivername, portname,
4241 false)) {
4242 torture_comment(tctx, "failed to add printer to printer list\n");
4243 ret = false;
4246 return ret;
4249 static bool test_printer_info(struct torture_context *tctx,
4250 struct dcerpc_pipe *p,
4251 struct policy_handle *handle)
4253 bool ret = true;
4255 if (torture_setting_bool(tctx, "samba3", false)) {
4256 torture_skip(tctx, "skipping printer info cross tests against samba 3");
4259 if (!test_PrinterInfo(tctx, p, handle)) {
4260 ret = false;
4263 if (!test_SetPrinter_errors(tctx, p, handle)) {
4264 ret = false;
4267 return ret;
4270 static bool test_EnumPrinterKey(struct torture_context *tctx,
4271 struct dcerpc_pipe *p,
4272 struct policy_handle *handle,
4273 const char *key_name,
4274 const char ***array)
4276 struct spoolss_EnumPrinterKey r;
4277 uint32_t needed = 0;
4278 union spoolss_KeyNames key_buffer;
4279 int32_t offered[] = { 0, 1, 2, 3, 4, 5, -1, -2, -3, -4, -5, 256, 512, 1024, 2048 };
4280 uint32_t _ndr_size;
4281 int i;
4283 r.in.handle = handle;
4284 r.in.key_name = key_name;
4285 r.out.key_buffer = &key_buffer;
4286 r.out.needed = &needed;
4287 r.out._ndr_size = &_ndr_size;
4289 for (i=0; i < ARRAY_SIZE(offered); i++) {
4291 if (offered[i] < 0 && needed) {
4292 if (needed <= 4) {
4293 continue;
4295 r.in.offered = needed + offered[i];
4296 } else {
4297 r.in.offered = offered[i];
4300 ZERO_STRUCT(key_buffer);
4302 torture_comment(tctx, "Testing EnumPrinterKey(%s) with %d offered\n", r.in.key_name, r.in.offered);
4304 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_EnumPrinterKey(p, tctx, &r),
4305 "failed to call EnumPrinterKey");
4306 if (W_ERROR_EQUAL(r.out.result, WERR_MORE_DATA)) {
4308 torture_assert(tctx, (_ndr_size == r.in.offered/2),
4309 talloc_asprintf(tctx, "EnumPrinterKey size mismatch, _ndr_size %d (expected %d)",
4310 _ndr_size, r.in.offered/2));
4312 r.in.offered = needed;
4313 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_EnumPrinterKey(p, tctx, &r),
4314 "failed to call EnumPrinterKey");
4317 if (offered[i] > 0) {
4318 torture_assert_werr_ok(tctx, r.out.result,
4319 "failed to call EnumPrinterKey");
4322 torture_assert(tctx, (_ndr_size == r.in.offered/2),
4323 talloc_asprintf(tctx, "EnumPrinterKey size mismatch, _ndr_size %d (expected %d)",
4324 _ndr_size, r.in.offered/2));
4326 torture_assert(tctx, (*r.out.needed <= r.in.offered),
4327 talloc_asprintf(tctx, "EnumPrinterKey size mismatch: needed %d is not <= offered %d", *r.out.needed, r.in.offered));
4329 torture_assert(tctx, (*r.out.needed <= _ndr_size * 2),
4330 talloc_asprintf(tctx, "EnumPrinterKey size mismatch: needed %d is not <= _ndr_size %d * 2", *r.out.needed, _ndr_size));
4332 if (key_buffer.string_array) {
4333 uint32_t calc_needed = 0;
4334 int s;
4335 for (s=0; key_buffer.string_array[s]; s++) {
4336 calc_needed += strlen_m_term(key_buffer.string_array[s])*2;
4338 if (!key_buffer.string_array[0]) {
4339 calc_needed += 2;
4341 calc_needed += 2;
4343 torture_assert_int_equal(tctx, *r.out.needed, calc_needed,
4344 "EnumPrinterKey unexpected size");
4348 if (array) {
4349 *array = key_buffer.string_array;
4352 return true;
4355 bool test_printer_keys(struct torture_context *tctx,
4356 struct dcerpc_pipe *p,
4357 struct policy_handle *handle)
4359 const char **key_array = NULL;
4360 int i;
4362 torture_comment(tctx, "\nTesting Printer Keys\n");
4364 torture_assert(tctx, test_EnumPrinterKey(tctx, p, handle, "", &key_array),
4365 "failed to call test_EnumPrinterKey");
4367 for (i=0; key_array && key_array[i]; i++) {
4368 torture_assert(tctx, test_EnumPrinterKey(tctx, p, handle, key_array[i], NULL),
4369 "failed to call test_EnumPrinterKey");
4371 for (i=0; key_array && key_array[i]; i++) {
4372 torture_assert(tctx, test_EnumPrinterDataEx(tctx, p, handle, key_array[i]),
4373 "failed to call test_EnumPrinterDataEx");
4376 return true;
4379 static bool test_one_printer(struct torture_context *tctx,
4380 struct dcerpc_pipe *p,
4381 struct policy_handle *handle,
4382 const char *name)
4384 bool ret = true;
4386 if (!test_printer_info(tctx, p, handle)) {
4387 ret = false;
4390 if (!test_PrinterInfo_SD(tctx, p, handle)) {
4391 ret = false;
4394 if (!test_PrinterInfo_DevMode(tctx, p, handle, name)) {
4395 ret = false;
4398 if (!test_printer_keys(tctx, p, handle)) {
4399 ret = false;
4402 return ret;
4405 static bool test_printer(struct torture_context *tctx,
4406 struct dcerpc_pipe *p)
4408 bool ret = true;
4409 struct policy_handle handle[2];
4410 bool found = false;
4411 const char *drivername = "Microsoft XPS Document Writer";
4412 const char *portname = "LPT1:";
4414 /* test printer created via AddPrinter */
4416 if (!test_AddPrinter(tctx, p, &handle[0], TORTURE_PRINTER, drivername, portname)) {
4417 return false;
4420 if (!test_one_printer(tctx, p, &handle[0], TORTURE_PRINTER)) {
4421 ret = false;
4424 if (!test_DeletePrinter(tctx, p, &handle[0])) {
4425 ret = false;
4428 if (!test_EnumPrinters_findname(tctx, p, PRINTER_ENUM_LOCAL, 1,
4429 TORTURE_PRINTER, &found)) {
4430 ret = false;
4433 torture_assert(tctx, !found, "deleted printer still there");
4435 /* test printer created via AddPrinterEx */
4437 if (!test_AddPrinterEx(tctx, p, &handle[1], TORTURE_PRINTER_EX, drivername, portname)) {
4438 return false;
4441 if (!test_one_printer(tctx, p, &handle[1], TORTURE_PRINTER_EX)) {
4442 ret = false;
4445 if (!test_DeletePrinter(tctx, p, &handle[1])) {
4446 ret = false;
4449 if (!test_EnumPrinters_findname(tctx, p, PRINTER_ENUM_LOCAL, 1,
4450 TORTURE_PRINTER_EX, &found)) {
4451 ret = false;
4454 torture_assert(tctx, !found, "deleted printer still there");
4456 return ret;
4459 bool torture_rpc_spoolss(struct torture_context *torture)
4461 NTSTATUS status;
4462 struct dcerpc_pipe *p;
4463 bool ret = true;
4464 struct test_spoolss_context *ctx;
4466 status = torture_rpc_connection(torture, &p, &ndr_table_spoolss);
4467 if (!NT_STATUS_IS_OK(status)) {
4468 return false;
4471 ctx = talloc_zero(torture, struct test_spoolss_context);
4473 ret &= test_OpenPrinter_server(torture, p, &ctx->server_handle);
4474 ret &= test_GetPrinterData_list(torture, p, &ctx->server_handle);
4475 ret &= test_EnumForms(torture, p, &ctx->server_handle, true);
4476 ret &= test_AddForm(torture, p, &ctx->server_handle, true);
4477 ret &= test_EnumPorts(torture, p, ctx);
4478 ret &= test_GetPrinterDriverDirectory(torture, p, ctx);
4479 ret &= test_GetPrintProcessorDirectory(torture, p, ctx);
4480 ret &= test_EnumPrinterDrivers(torture, p, ctx, SPOOLSS_ARCHITECTURE_NT_X86);
4481 ret &= test_EnumPrinterDrivers(torture, p, ctx, SPOOLSS_ARCHITECTURE_ALL);
4482 ret &= test_EnumMonitors(torture, p, ctx);
4483 ret &= test_EnumPrintProcessors(torture, p, ctx);
4484 ret &= test_EnumPrintProcDataTypes(torture, p, ctx);
4485 ret &= test_EnumPrinters(torture, p, ctx);
4486 ret &= test_OpenPrinter_badname(torture, p, "__INVALID_PRINTER__");
4487 ret &= test_OpenPrinter_badname(torture, p, "\\\\__INVALID_HOST__");
4488 ret &= test_OpenPrinter_badname(torture, p, "");
4489 ret &= test_OpenPrinter_badname(torture, p, "\\\\\\");
4490 ret &= test_OpenPrinter_badname(torture, p, "\\\\\\__INVALID_PRINTER__");
4491 ret &= test_OpenPrinter_badname(torture, p, talloc_asprintf(torture, "\\\\%s\\", dcerpc_server_name(p)));
4492 ret &= test_OpenPrinter_badname(torture, p,
4493 talloc_asprintf(torture, "\\\\%s\\__INVALID_PRINTER__", dcerpc_server_name(p)));
4496 ret &= test_AddPort(torture, p);
4497 ret &= test_EnumPorts_old(torture, p);
4498 ret &= test_EnumPrinters_old(torture, p);
4499 ret &= test_EnumPrinterDrivers_old(torture, p);
4501 return ret;
4504 struct torture_suite *torture_rpc_spoolss_printer(TALLOC_CTX *mem_ctx)
4506 struct torture_suite *suite = torture_suite_create(mem_ctx, "SPOOLSS-PRINTER");
4508 struct torture_rpc_tcase *tcase = torture_suite_add_rpc_iface_tcase(suite,
4509 "printer", &ndr_table_spoolss);
4511 torture_rpc_tcase_add_test(tcase, "printer", test_printer);
4513 return suite;