s4-smbtorture: avoid potential loop while adding a new printer in RPC-SPOOLSS-PRINTER.
[Samba/cd1.git] / source4 / torture / rpc / spoolss.c
blob82469e9ef39cd513d2799a6e08464fbbe922976d
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 uint32_t size = ndr_size_##fn##_info(tctx, ic, level, count, info);\
124 uint32_t round_size = DO_ROUND(size, align);\
125 if (round_size != needed) {\
126 torture_warning(tctx, __location__": "#fn" level %d (count: %d) got unexpected needed size: %d, we calculated: %d", level, count, needed, round_size);\
127 CHECK_ALIGN(size, align);\
129 } while(0)
131 #define CHECK_NEEDED_SIZE_ENUM(fn, info, count, ic, needed, align) do { \
132 uint32_t size = ndr_size_##fn##_info(tctx, ic, count, info);\
133 uint32_t round_size = DO_ROUND(size, align);\
134 if (round_size != needed) {\
135 torture_warning(tctx, __location__": "#fn" (count: %d) got unexpected needed size: %d, we calculated: %d", count, needed, round_size);\
136 CHECK_ALIGN(size, align);\
138 } while(0)
140 #define CHECK_NEEDED_SIZE_LEVEL(fn, info, level, ic, needed, align) do { \
141 uint32_t size = ndr_size_##fn(info, level, ic, 0);\
142 uint32_t round_size = DO_ROUND(size, align);\
143 if (round_size != needed) {\
144 torture_warning(tctx, __location__": "#fn" level %d got unexpected needed size: %d, we calculated: %d", level, needed, round_size);\
145 CHECK_ALIGN(size, align);\
147 } while(0)
149 static bool test_OpenPrinter_server(struct torture_context *tctx,
150 struct dcerpc_pipe *p,
151 struct policy_handle *server_handle)
153 NTSTATUS status;
154 struct spoolss_OpenPrinter op;
156 op.in.printername = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
157 op.in.datatype = NULL;
158 op.in.devmode_ctr.devmode= NULL;
159 op.in.access_mask = 0;
160 op.out.handle = server_handle;
162 torture_comment(tctx, "Testing OpenPrinter(%s)\n", op.in.printername);
164 status = dcerpc_spoolss_OpenPrinter(p, tctx, &op);
165 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_OpenPrinter failed");
166 torture_assert_werr_ok(tctx, op.out.result, "dcerpc_spoolss_OpenPrinter failed");
168 return true;
171 static bool test_EnumPorts(struct torture_context *tctx,
172 struct dcerpc_pipe *p,
173 struct test_spoolss_context *ctx)
175 NTSTATUS status;
176 struct spoolss_EnumPorts r;
177 uint16_t levels[] = { 1, 2 };
178 int i, j;
180 for (i=0;i<ARRAY_SIZE(levels);i++) {
181 int level = levels[i];
182 DATA_BLOB blob;
183 uint32_t needed;
184 uint32_t count;
185 union spoolss_PortInfo *info;
187 r.in.servername = "";
188 r.in.level = level;
189 r.in.buffer = NULL;
190 r.in.offered = 0;
191 r.out.needed = &needed;
192 r.out.count = &count;
193 r.out.info = &info;
195 torture_comment(tctx, "Testing EnumPorts level %u\n", r.in.level);
197 status = dcerpc_spoolss_EnumPorts(p, ctx, &r);
198 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EnumPorts failed");
199 if (W_ERROR_IS_OK(r.out.result)) {
200 /* TODO: do some more checks here */
201 continue;
203 torture_assert_werr_equal(tctx, r.out.result, WERR_INSUFFICIENT_BUFFER,
204 "EnumPorts unexpected return code");
206 blob = data_blob_talloc(ctx, NULL, needed);
207 data_blob_clear(&blob);
208 r.in.buffer = &blob;
209 r.in.offered = needed;
211 status = dcerpc_spoolss_EnumPorts(p, ctx, &r);
212 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EnumPorts failed");
214 torture_assert_werr_ok(tctx, r.out.result, "EnumPorts failed");
216 torture_assert(tctx, info, "EnumPorts returned no info");
218 CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumPorts, info, r.in.level, count, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
220 ctx->port_count[level] = count;
221 ctx->ports[level] = info;
224 for (i=1;i<ARRAY_SIZE(levels);i++) {
225 int level = levels[i];
226 int old_level = levels[i-1];
227 torture_assert_int_equal(tctx, ctx->port_count[level], ctx->port_count[old_level],
228 "EnumPorts invalid value");
230 /* if the array sizes are not the same we would maybe segfault in the following code */
232 for (i=0;i<ARRAY_SIZE(levels);i++) {
233 int level = levels[i];
234 for (j=0;j<ctx->port_count[level];j++) {
235 union spoolss_PortInfo *cur = &ctx->ports[level][j];
236 union spoolss_PortInfo *ref = &ctx->ports[2][j];
237 switch (level) {
238 case 1:
239 COMPARE_STRING(tctx, cur->info1, ref->info2, port_name);
240 break;
241 case 2:
242 /* level 2 is our reference, and it makes no sense to compare it to itself */
243 break;
248 return true;
251 static bool test_GetPrintProcessorDirectory(struct torture_context *tctx,
252 struct dcerpc_pipe *p,
253 struct test_spoolss_context *ctx)
255 NTSTATUS status;
256 struct spoolss_GetPrintProcessorDirectory r;
257 struct {
258 uint16_t level;
259 const char *server;
260 } levels[] = {{
261 .level = 1,
262 .server = NULL
264 .level = 1,
265 .server = ""
267 .level = 78,
268 .server = ""
270 .level = 1,
271 .server = talloc_asprintf(ctx, "\\\\%s", dcerpc_server_name(p))
273 .level = 1024,
274 .server = talloc_asprintf(ctx, "\\\\%s", dcerpc_server_name(p))
277 int i;
278 uint32_t needed;
280 for (i=0;i<ARRAY_SIZE(levels);i++) {
281 int level = levels[i].level;
282 DATA_BLOB blob;
284 r.in.server = levels[i].server;
285 r.in.environment = SPOOLSS_ARCHITECTURE_NT_X86;
286 r.in.level = level;
287 r.in.buffer = NULL;
288 r.in.offered = 0;
289 r.out.needed = &needed;
291 torture_comment(tctx, "Testing GetPrintProcessorDirectory level %u\n", r.in.level);
293 status = dcerpc_spoolss_GetPrintProcessorDirectory(p, ctx, &r);
294 torture_assert_ntstatus_ok(tctx, status,
295 "dcerpc_spoolss_GetPrintProcessorDirectory failed");
296 torture_assert_werr_equal(tctx, r.out.result, WERR_INSUFFICIENT_BUFFER,
297 "GetPrintProcessorDirectory unexpected return code");
299 blob = data_blob_talloc(ctx, NULL, needed);
300 data_blob_clear(&blob);
301 r.in.buffer = &blob;
302 r.in.offered = needed;
304 status = dcerpc_spoolss_GetPrintProcessorDirectory(p, ctx, &r);
305 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_GetPrintProcessorDirectory failed");
307 torture_assert_werr_ok(tctx, r.out.result, "GetPrintProcessorDirectory failed");
309 CHECK_NEEDED_SIZE_LEVEL(spoolss_PrintProcessorDirectoryInfo, r.out.info, r.in.level, lp_iconv_convenience(tctx->lp_ctx), needed, 2);
312 return true;
316 static bool test_GetPrinterDriverDirectory(struct torture_context *tctx,
317 struct dcerpc_pipe *p,
318 struct test_spoolss_context *ctx)
320 NTSTATUS status;
321 struct spoolss_GetPrinterDriverDirectory r;
322 struct {
323 uint16_t level;
324 const char *server;
325 } levels[] = {{
326 .level = 1,
327 .server = NULL
329 .level = 1,
330 .server = ""
332 .level = 78,
333 .server = ""
335 .level = 1,
336 .server = talloc_asprintf(ctx, "\\\\%s", dcerpc_server_name(p))
338 .level = 1024,
339 .server = talloc_asprintf(ctx, "\\\\%s", dcerpc_server_name(p))
342 int i;
343 uint32_t needed;
345 for (i=0;i<ARRAY_SIZE(levels);i++) {
346 int level = levels[i].level;
347 DATA_BLOB blob;
349 r.in.server = levels[i].server;
350 r.in.environment = SPOOLSS_ARCHITECTURE_NT_X86;
351 r.in.level = level;
352 r.in.buffer = NULL;
353 r.in.offered = 0;
354 r.out.needed = &needed;
356 torture_comment(tctx, "Testing GetPrinterDriverDirectory level %u\n", r.in.level);
358 status = dcerpc_spoolss_GetPrinterDriverDirectory(p, ctx, &r);
359 torture_assert_ntstatus_ok(tctx, status,
360 "dcerpc_spoolss_GetPrinterDriverDirectory failed");
361 torture_assert_werr_equal(tctx, r.out.result, WERR_INSUFFICIENT_BUFFER,
362 "GetPrinterDriverDirectory unexpected return code");
364 blob = data_blob_talloc(ctx, NULL, needed);
365 data_blob_clear(&blob);
366 r.in.buffer = &blob;
367 r.in.offered = needed;
369 status = dcerpc_spoolss_GetPrinterDriverDirectory(p, ctx, &r);
370 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_GetPrinterDriverDirectory failed");
372 torture_assert_werr_ok(tctx, r.out.result, "GetPrinterDriverDirectory failed");
374 CHECK_NEEDED_SIZE_LEVEL(spoolss_DriverDirectoryInfo, r.out.info, r.in.level, lp_iconv_convenience(tctx->lp_ctx), needed, 2);
377 return true;
380 static bool test_EnumPrinterDrivers(struct torture_context *tctx,
381 struct dcerpc_pipe *p,
382 struct test_spoolss_context *ctx,
383 const char *architecture)
385 NTSTATUS status;
386 struct spoolss_EnumPrinterDrivers r;
387 uint16_t levels[] = { 1, 2, 3, 4, 5, 6, 8 };
388 int i, j;
390 for (i=0;i<ARRAY_SIZE(levels);i++) {
391 int level = levels[i];
392 DATA_BLOB blob;
393 uint32_t needed;
394 uint32_t count;
395 union spoolss_DriverInfo *info;
397 /* FIXME: gd, come back and fix "" as server, and handle
398 * priority of returned error codes in torture test and samba 3
399 * server */
401 r.in.server = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
402 r.in.environment = architecture;
403 r.in.level = level;
404 r.in.buffer = NULL;
405 r.in.offered = 0;
406 r.out.needed = &needed;
407 r.out.count = &count;
408 r.out.info = &info;
410 torture_comment(tctx, "Testing EnumPrinterDrivers level %u (%s)\n", r.in.level, r.in.environment);
412 status = dcerpc_spoolss_EnumPrinterDrivers(p, ctx, &r);
413 torture_assert_ntstatus_ok(tctx, status,
414 "dcerpc_spoolss_EnumPrinterDrivers failed");
415 if (W_ERROR_IS_OK(r.out.result)) {
416 /* TODO: do some more checks here */
417 continue;
419 if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
420 blob = data_blob_talloc(ctx, NULL, needed);
421 data_blob_clear(&blob);
422 r.in.buffer = &blob;
423 r.in.offered = needed;
425 status = dcerpc_spoolss_EnumPrinterDrivers(p, ctx, &r);
426 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EnumPrinterDrivers failed");
429 torture_assert_werr_ok(tctx, r.out.result, "EnumPrinterDrivers failed");
431 CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumPrinterDrivers, info, r.in.level, count, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
433 ctx->driver_count[level] = count;
434 ctx->drivers[level] = info;
437 for (i=1;i<ARRAY_SIZE(levels);i++) {
438 int level = levels[i];
439 int old_level = levels[i-1];
441 torture_assert_int_equal(tctx, ctx->driver_count[level], ctx->driver_count[old_level],
442 "EnumPrinterDrivers invalid value");
445 for (i=0;i<ARRAY_SIZE(levels);i++) {
446 int level = levels[i];
448 for (j=0;j<ctx->driver_count[level];j++) {
449 union spoolss_DriverInfo *cur = &ctx->drivers[level][j];
450 union spoolss_DriverInfo *ref = &ctx->drivers[8][j];
452 switch (level) {
453 case 1:
454 COMPARE_STRING(tctx, cur->info1, ref->info8, driver_name);
455 break;
456 case 2:
457 COMPARE_UINT32(tctx, cur->info2, ref->info8, version);
458 COMPARE_STRING(tctx, cur->info2, ref->info8, driver_name);
459 COMPARE_STRING(tctx, cur->info2, ref->info8, architecture);
460 COMPARE_STRING(tctx, cur->info2, ref->info8, driver_path);
461 COMPARE_STRING(tctx, cur->info2, ref->info8, data_file);
462 COMPARE_STRING(tctx, cur->info2, ref->info8, config_file);
463 break;
464 case 3:
465 COMPARE_UINT32(tctx, cur->info3, ref->info8, version);
466 COMPARE_STRING(tctx, cur->info3, ref->info8, driver_name);
467 COMPARE_STRING(tctx, cur->info3, ref->info8, architecture);
468 COMPARE_STRING(tctx, cur->info3, ref->info8, driver_path);
469 COMPARE_STRING(tctx, cur->info3, ref->info8, data_file);
470 COMPARE_STRING(tctx, cur->info3, ref->info8, config_file);
471 COMPARE_STRING(tctx, cur->info3, ref->info8, help_file);
472 COMPARE_STRING_ARRAY(tctx, cur->info3, ref->info8, dependent_files);
473 COMPARE_STRING(tctx, cur->info3, ref->info8, monitor_name);
474 COMPARE_STRING(tctx, cur->info3, ref->info8, default_datatype);
475 break;
476 case 4:
477 COMPARE_UINT32(tctx, cur->info4, ref->info8, version);
478 COMPARE_STRING(tctx, cur->info4, ref->info8, driver_name);
479 COMPARE_STRING(tctx, cur->info4, ref->info8, architecture);
480 COMPARE_STRING(tctx, cur->info4, ref->info8, driver_path);
481 COMPARE_STRING(tctx, cur->info4, ref->info8, data_file);
482 COMPARE_STRING(tctx, cur->info4, ref->info8, config_file);
483 COMPARE_STRING(tctx, cur->info4, ref->info8, help_file);
484 COMPARE_STRING_ARRAY(tctx, cur->info4, ref->info8, dependent_files);
485 COMPARE_STRING(tctx, cur->info4, ref->info8, monitor_name);
486 COMPARE_STRING(tctx, cur->info4, ref->info8, default_datatype);
487 COMPARE_STRING_ARRAY(tctx, cur->info4, ref->info8, previous_names);
488 break;
489 case 5:
490 COMPARE_UINT32(tctx, cur->info5, ref->info8, version);
491 COMPARE_STRING(tctx, cur->info5, ref->info8, driver_name);
492 COMPARE_STRING(tctx, cur->info5, ref->info8, architecture);
493 COMPARE_STRING(tctx, cur->info5, ref->info8, driver_path);
494 COMPARE_STRING(tctx, cur->info5, ref->info8, data_file);
495 COMPARE_STRING(tctx, cur->info5, ref->info8, config_file);
496 /*COMPARE_UINT32(tctx, cur->info5, ref->info8, driver_attributes);*/
497 /*COMPARE_UINT32(tctx, cur->info5, ref->info8, config_version);*/
498 /*TODO: ! COMPARE_UINT32(tctx, cur->info5, ref->info8, driver_version); */
499 break;
500 case 6:
501 COMPARE_UINT32(tctx, cur->info6, ref->info8, version);
502 COMPARE_STRING(tctx, cur->info6, ref->info8, driver_name);
503 COMPARE_STRING(tctx, cur->info6, ref->info8, architecture);
504 COMPARE_STRING(tctx, cur->info6, ref->info8, driver_path);
505 COMPARE_STRING(tctx, cur->info6, ref->info8, data_file);
506 COMPARE_STRING(tctx, cur->info6, ref->info8, config_file);
507 COMPARE_STRING(tctx, cur->info6, ref->info8, help_file);
508 COMPARE_STRING_ARRAY(tctx, cur->info6, ref->info8, dependent_files);
509 COMPARE_STRING(tctx, cur->info6, ref->info8, monitor_name);
510 COMPARE_STRING(tctx, cur->info6, ref->info8, default_datatype);
511 COMPARE_STRING_ARRAY(tctx, cur->info6, ref->info8, previous_names);
512 COMPARE_NTTIME(tctx, cur->info6, ref->info8, driver_date);
513 COMPARE_UINT64(tctx, cur->info6, ref->info8, driver_version);
514 COMPARE_STRING(tctx, cur->info6, ref->info8, manufacturer_name);
515 COMPARE_STRING(tctx, cur->info6, ref->info8, manufacturer_url);
516 COMPARE_STRING(tctx, cur->info6, ref->info8, hardware_id);
517 COMPARE_STRING(tctx, cur->info6, ref->info8, provider);
518 break;
519 case 8:
520 /* level 8 is our reference, and it makes no sense to compare it to itself */
521 break;
526 return true;
529 static bool test_EnumMonitors(struct torture_context *tctx,
530 struct dcerpc_pipe *p,
531 struct test_spoolss_context *ctx)
533 NTSTATUS status;
534 struct spoolss_EnumMonitors r;
535 uint16_t levels[] = { 1, 2 };
536 int i, j;
538 for (i=0;i<ARRAY_SIZE(levels);i++) {
539 int level = levels[i];
540 DATA_BLOB blob;
541 uint32_t needed;
542 uint32_t count;
543 union spoolss_MonitorInfo *info;
545 r.in.servername = "";
546 r.in.level = level;
547 r.in.buffer = NULL;
548 r.in.offered = 0;
549 r.out.needed = &needed;
550 r.out.count = &count;
551 r.out.info = &info;
553 torture_comment(tctx, "Testing EnumMonitors level %u\n", r.in.level);
555 status = dcerpc_spoolss_EnumMonitors(p, ctx, &r);
556 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EnumMonitors failed");
557 if (W_ERROR_IS_OK(r.out.result)) {
558 /* TODO: do some more checks here */
559 continue;
561 torture_assert_werr_equal(tctx, r.out.result, WERR_INSUFFICIENT_BUFFER,
562 "EnumMonitors failed");
564 blob = data_blob_talloc(ctx, NULL, needed);
565 data_blob_clear(&blob);
566 r.in.buffer = &blob;
567 r.in.offered = needed;
569 status = dcerpc_spoolss_EnumMonitors(p, ctx, &r);
570 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EnumMonitors failed");
572 torture_assert_werr_ok(tctx, r.out.result, "EnumMonitors failed");
574 CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumMonitors, info, r.in.level, count, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
576 ctx->monitor_count[level] = count;
577 ctx->monitors[level] = info;
580 for (i=1;i<ARRAY_SIZE(levels);i++) {
581 int level = levels[i];
582 int old_level = levels[i-1];
583 torture_assert_int_equal(tctx, ctx->monitor_count[level], ctx->monitor_count[old_level],
584 "EnumMonitors invalid value");
587 for (i=0;i<ARRAY_SIZE(levels);i++) {
588 int level = levels[i];
589 for (j=0;j<ctx->monitor_count[level];j++) {
590 union spoolss_MonitorInfo *cur = &ctx->monitors[level][j];
591 union spoolss_MonitorInfo *ref = &ctx->monitors[2][j];
592 switch (level) {
593 case 1:
594 COMPARE_STRING(tctx, cur->info1, ref->info2, monitor_name);
595 break;
596 case 2:
597 /* level 2 is our reference, and it makes no sense to compare it to itself */
598 break;
603 return true;
606 static bool test_EnumPrintProcessors(struct torture_context *tctx,
607 struct dcerpc_pipe *p,
608 struct test_spoolss_context *ctx)
610 NTSTATUS status;
611 struct spoolss_EnumPrintProcessors r;
612 uint16_t levels[] = { 1 };
613 int i, j;
615 for (i=0;i<ARRAY_SIZE(levels);i++) {
616 int level = levels[i];
617 DATA_BLOB blob;
618 uint32_t needed;
619 uint32_t count;
620 union spoolss_PrintProcessorInfo *info;
622 r.in.servername = "";
623 r.in.environment = SPOOLSS_ARCHITECTURE_NT_X86;
624 r.in.level = level;
625 r.in.buffer = NULL;
626 r.in.offered = 0;
627 r.out.needed = &needed;
628 r.out.count = &count;
629 r.out.info = &info;
631 torture_comment(tctx, "Testing EnumPrintProcessors level %u\n", r.in.level);
633 status = dcerpc_spoolss_EnumPrintProcessors(p, ctx, &r);
634 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EnumPrintProcessors failed");
635 if (W_ERROR_IS_OK(r.out.result)) {
636 /* TODO: do some more checks here */
637 continue;
639 torture_assert_werr_equal(tctx, r.out.result, WERR_INSUFFICIENT_BUFFER,
640 "EnumPrintProcessors unexpected return code");
642 blob = data_blob_talloc(ctx, NULL, needed);
643 data_blob_clear(&blob);
644 r.in.buffer = &blob;
645 r.in.offered = needed;
647 status = dcerpc_spoolss_EnumPrintProcessors(p, ctx, &r);
648 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EnumPrintProcessors failed");
650 torture_assert_werr_ok(tctx, r.out.result, "EnumPrintProcessors failed");
652 CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumPrintProcessors, info, r.in.level, count, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
654 ctx->print_processor_count[level] = count;
655 ctx->print_processors[level] = info;
658 for (i=1;i<ARRAY_SIZE(levels);i++) {
659 int level = levels[i];
660 int old_level = levels[i-1];
661 torture_assert_int_equal(tctx, ctx->print_processor_count[level], ctx->print_processor_count[old_level],
662 "EnumPrintProcessors failed");
665 for (i=0;i<ARRAY_SIZE(levels);i++) {
666 int level = levels[i];
667 for (j=0;j<ctx->print_processor_count[level];j++) {
668 #if 0
669 union spoolss_PrintProcessorInfo *cur = &ctx->print_processors[level][j];
670 union spoolss_PrintProcessorInfo *ref = &ctx->print_processors[1][j];
671 #endif
672 switch (level) {
673 case 1:
674 /* level 1 is our reference, and it makes no sense to compare it to itself */
675 break;
680 return true;
683 static bool test_EnumPrintProcDataTypes(struct torture_context *tctx,
684 struct dcerpc_pipe *p,
685 struct test_spoolss_context *ctx)
687 NTSTATUS status;
688 struct spoolss_EnumPrintProcDataTypes r;
689 uint16_t levels[] = { 1 };
690 int i;
692 for (i=0;i<ARRAY_SIZE(levels);i++) {
693 int level = levels[i];
694 DATA_BLOB blob;
695 uint32_t needed;
696 uint32_t count;
697 union spoolss_PrintProcDataTypesInfo *info;
699 r.in.servername = "";
700 r.in.print_processor_name = "winprint";
701 r.in.level = level;
702 r.in.buffer = NULL;
703 r.in.offered = 0;
704 r.out.needed = &needed;
705 r.out.count = &count;
706 r.out.info = &info;
708 torture_comment(tctx, "Testing EnumPrintProcDataTypes level %u\n", r.in.level);
710 status = dcerpc_spoolss_EnumPrintProcDataTypes(p, ctx, &r);
711 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EnumPrintProcDataType failed");
712 if (W_ERROR_IS_OK(r.out.result)) {
713 /* TODO: do some more checks here */
714 continue;
716 torture_assert_werr_equal(tctx, r.out.result, WERR_INSUFFICIENT_BUFFER,
717 "EnumPrintProcDataTypes unexpected return code");
719 blob = data_blob_talloc(ctx, NULL, needed);
720 data_blob_clear(&blob);
721 r.in.buffer = &blob;
722 r.in.offered = needed;
724 status = dcerpc_spoolss_EnumPrintProcDataTypes(p, ctx, &r);
725 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EnumPrintProcDataTypes failed");
727 torture_assert_werr_ok(tctx, r.out.result, "EnumPrintProcDataTypes failed");
729 CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumPrintProcDataTypes, info, r.in.level, count, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
733 return true;
737 static bool test_EnumPrinters(struct torture_context *tctx,
738 struct dcerpc_pipe *p,
739 struct test_spoolss_context *ctx)
741 struct spoolss_EnumPrinters r;
742 NTSTATUS status;
743 uint16_t levels[] = { 0, 1, 2, 4, 5 };
744 int i, j;
746 for (i=0;i<ARRAY_SIZE(levels);i++) {
747 int level = levels[i];
748 DATA_BLOB blob;
749 uint32_t needed;
750 uint32_t count;
751 union spoolss_PrinterInfo *info;
753 r.in.flags = PRINTER_ENUM_LOCAL;
754 r.in.server = "";
755 r.in.level = level;
756 r.in.buffer = NULL;
757 r.in.offered = 0;
758 r.out.needed = &needed;
759 r.out.count = &count;
760 r.out.info = &info;
762 torture_comment(tctx, "Testing EnumPrinters level %u\n", r.in.level);
764 status = dcerpc_spoolss_EnumPrinters(p, ctx, &r);
765 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EnumPrinters failed");
766 if (W_ERROR_IS_OK(r.out.result)) {
767 /* TODO: do some more checks here */
768 continue;
770 torture_assert_werr_equal(tctx, r.out.result, WERR_INSUFFICIENT_BUFFER,
771 "EnumPrinters unexpected return code");
773 blob = data_blob_talloc(ctx, NULL, needed);
774 data_blob_clear(&blob);
775 r.in.buffer = &blob;
776 r.in.offered = needed;
778 status = dcerpc_spoolss_EnumPrinters(p, ctx, &r);
779 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EnumPrinters failed");
781 torture_assert_werr_ok(tctx, r.out.result, "EnumPrinters failed");
783 CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumPrinters, info, r.in.level, count, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
785 ctx->printer_count[level] = count;
786 ctx->printers[level] = info;
789 for (i=1;i<ARRAY_SIZE(levels);i++) {
790 int level = levels[i];
791 int old_level = levels[i-1];
792 torture_assert_int_equal(tctx, ctx->printer_count[level], ctx->printer_count[old_level],
793 "EnumPrinters invalid value");
796 for (i=0;i<ARRAY_SIZE(levels);i++) {
797 int level = levels[i];
798 for (j=0;j<ctx->printer_count[level];j++) {
799 union spoolss_PrinterInfo *cur = &ctx->printers[level][j];
800 union spoolss_PrinterInfo *ref = &ctx->printers[2][j];
801 switch (level) {
802 case 0:
803 COMPARE_STRING(tctx, cur->info0, ref->info2, printername);
804 COMPARE_STRING(tctx, cur->info0, ref->info2, servername);
805 COMPARE_UINT32(tctx, cur->info0, ref->info2, cjobs);
806 /*COMPARE_UINT32(tctx, cur->info0, ref->info2, total_jobs);
807 COMPARE_UINT32(tctx, cur->info0, ref->info2, total_bytes);
808 COMPARE_SPOOLSS_TIME(cur->info0, ref->info2, spoolss_Time time);
809 COMPARE_UINT32(tctx, cur->info0, ref->info2, global_counter);
810 COMPARE_UINT32(tctx, cur->info0, ref->info2, total_pages);
811 COMPARE_UINT32(tctx, cur->info0, ref->info2, version);
812 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown10);
813 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown11);
814 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown12);
815 COMPARE_UINT32(tctx, cur->info0, ref->info2, session_counter);
816 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown14);
817 COMPARE_UINT32(tctx, cur->info0, ref->info2, printer_errors);
818 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown16);
819 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown17);
820 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown18);
821 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown19);
822 COMPARE_UINT32(tctx, cur->info0, ref->info2, change_id);
823 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown21);*/
824 COMPARE_UINT32(tctx, cur->info0, ref->info2, status);
825 /*COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown23);
826 COMPARE_UINT32(tctx, cur->info0, ref->info2, c_setprinter);
827 COMPARE_UINT16(cur->info0, ref->info2, unknown25);
828 COMPARE_UINT16(cur->info0, ref->info2, unknown26);
829 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown27);
830 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown28);
831 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown29);*/
832 break;
833 case 1:
834 /*COMPARE_UINT32(tctx, cur->info1, ref->info2, flags);*/
835 /*COMPARE_STRING(tctx, cur->info1, ref->info2, name);*/
836 /*COMPARE_STRING(tctx, cur->info1, ref->info2, description);*/
837 COMPARE_STRING(tctx, cur->info1, ref->info2, comment);
838 break;
839 case 2:
840 /* level 2 is our reference, and it makes no sense to compare it to itself */
841 break;
842 case 4:
843 COMPARE_STRING(tctx, cur->info4, ref->info2, printername);
844 COMPARE_STRING(tctx, cur->info4, ref->info2, servername);
845 COMPARE_UINT32(tctx, cur->info4, ref->info2, attributes);
846 break;
847 case 5:
848 COMPARE_STRING(tctx, cur->info5, ref->info2, printername);
849 COMPARE_STRING(tctx, cur->info5, ref->info2, portname);
850 COMPARE_UINT32(tctx, cur->info5, ref->info2, attributes);
851 /*COMPARE_UINT32(tctx, cur->info5, ref->info2, device_not_selected_timeout);
852 COMPARE_UINT32(tctx, cur->info5, ref->info2, transmission_retry_timeout);*/
853 break;
858 /* TODO:
859 * - verify that the port of a printer was in the list returned by EnumPorts
862 return true;
865 static bool test_GetPrinterDriver2(struct torture_context *tctx,
866 struct dcerpc_pipe *p,
867 struct policy_handle *handle,
868 const char *driver_name);
870 bool test_GetPrinter_level(struct torture_context *tctx,
871 struct dcerpc_pipe *p,
872 struct policy_handle *handle,
873 uint32_t level,
874 union spoolss_PrinterInfo *info)
876 struct spoolss_GetPrinter r;
877 uint32_t needed;
879 r.in.handle = handle;
880 r.in.level = level;
881 r.in.buffer = NULL;
882 r.in.offered = 0;
883 r.out.needed = &needed;
885 torture_comment(tctx, "Testing GetPrinter level %u\n", r.in.level);
887 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_GetPrinter(p, tctx, &r),
888 "GetPrinter failed");
890 if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
891 DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed);
892 data_blob_clear(&blob);
893 r.in.buffer = &blob;
894 r.in.offered = needed;
896 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_GetPrinter(p, tctx, &r),
897 "GetPrinter failed");
900 torture_assert_werr_ok(tctx, r.out.result, "GetPrinter failed");
902 CHECK_NEEDED_SIZE_LEVEL(spoolss_PrinterInfo, r.out.info, r.in.level, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
904 if (info && r.out.info) {
905 *info = *r.out.info;
908 return true;
912 static bool test_GetPrinter(struct torture_context *tctx,
913 struct dcerpc_pipe *p,
914 struct policy_handle *handle)
916 uint32_t levels[] = {0, 1, 2, 3, 4, 5, 6, 7, 8};
917 int i;
919 for (i=0;i<ARRAY_SIZE(levels);i++) {
921 union spoolss_PrinterInfo info;
923 ZERO_STRUCT(info);
925 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, levels[i], &info),
926 "failed to call GetPrinter");
928 if ((levels[i] == 2) && info.info2.drivername && strlen(info.info2.drivername)) {
929 torture_assert(tctx,
930 test_GetPrinterDriver2(tctx, p, handle, info.info2.drivername),
931 "failed to call test_GetPrinterDriver2");
935 return true;
938 static bool test_SetPrinter(struct torture_context *tctx,
939 struct dcerpc_pipe *p,
940 struct policy_handle *handle,
941 struct spoolss_SetPrinterInfoCtr *info_ctr,
942 struct spoolss_DevmodeContainer *devmode_ctr,
943 struct sec_desc_buf *secdesc_ctr,
944 enum spoolss_PrinterControl command)
946 struct spoolss_SetPrinter r;
948 r.in.handle = handle;
949 r.in.info_ctr = info_ctr;
950 r.in.devmode_ctr = devmode_ctr;
951 r.in.secdesc_ctr = secdesc_ctr;
952 r.in.command = command;
954 torture_comment(tctx, "Testing SetPrinter level %d\n", r.in.info_ctr->level);
956 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_SetPrinter(p, tctx, &r),
957 "failed to call SetPrinter");
958 torture_assert_werr_ok(tctx, r.out.result,
959 "failed to call SetPrinter");
961 return true;
964 static bool test_SetPrinter_errors(struct torture_context *tctx,
965 struct dcerpc_pipe *p,
966 struct policy_handle *handle)
968 struct spoolss_SetPrinter r;
969 uint16_t levels[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
970 int i;
972 struct spoolss_SetPrinterInfoCtr info_ctr;
973 struct spoolss_DevmodeContainer devmode_ctr;
974 struct sec_desc_buf secdesc_ctr;
976 info_ctr.level = 0;
977 info_ctr.info.info0 = NULL;
979 ZERO_STRUCT(devmode_ctr);
980 ZERO_STRUCT(secdesc_ctr);
982 r.in.handle = handle;
983 r.in.info_ctr = &info_ctr;
984 r.in.devmode_ctr = &devmode_ctr;
985 r.in.secdesc_ctr = &secdesc_ctr;
986 r.in.command = 0;
988 torture_comment(tctx, "Testing SetPrinter all zero\n");
990 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_SetPrinter(p, tctx, &r),
991 "failed to call SetPrinter");
992 torture_assert_werr_equal(tctx, r.out.result, WERR_INVALID_PARAM,
993 "failed to call SetPrinter");
995 again:
996 for (i=0; i < ARRAY_SIZE(levels); i++) {
998 struct spoolss_SetPrinterInfo0 info0;
999 struct spoolss_SetPrinterInfo1 info1;
1000 struct spoolss_SetPrinterInfo2 info2;
1001 struct spoolss_SetPrinterInfo3 info3;
1002 struct spoolss_SetPrinterInfo4 info4;
1003 struct spoolss_SetPrinterInfo5 info5;
1004 struct spoolss_SetPrinterInfo6 info6;
1005 struct spoolss_SetPrinterInfo7 info7;
1006 struct spoolss_SetPrinterInfo8 info8;
1007 struct spoolss_SetPrinterInfo9 info9;
1010 info_ctr.level = levels[i];
1011 switch (levels[i]) {
1012 case 0:
1013 ZERO_STRUCT(info0);
1014 info_ctr.info.info0 = &info0;
1015 break;
1016 case 1:
1017 ZERO_STRUCT(info1);
1018 info_ctr.info.info1 = &info1;
1019 break;
1020 case 2:
1021 ZERO_STRUCT(info2);
1022 info_ctr.info.info2 = &info2;
1023 break;
1024 case 3:
1025 ZERO_STRUCT(info3);
1026 info_ctr.info.info3 = &info3;
1027 break;
1028 case 4:
1029 ZERO_STRUCT(info4);
1030 info_ctr.info.info4 = &info4;
1031 break;
1032 case 5:
1033 ZERO_STRUCT(info5);
1034 info_ctr.info.info5 = &info5;
1035 break;
1036 case 6:
1037 ZERO_STRUCT(info6);
1038 info_ctr.info.info6 = &info6;
1039 break;
1040 case 7:
1041 ZERO_STRUCT(info7);
1042 info_ctr.info.info7 = &info7;
1043 break;
1044 case 8:
1045 ZERO_STRUCT(info8);
1046 info_ctr.info.info8 = &info8;
1047 break;
1048 case 9:
1049 ZERO_STRUCT(info9);
1050 info_ctr.info.info9 = &info9;
1051 break;
1054 torture_comment(tctx, "Testing SetPrinter level %d, command %d\n",
1055 info_ctr.level, r.in.command);
1057 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_SetPrinter(p, tctx, &r),
1058 "failed to call SetPrinter");
1060 switch (r.in.command) {
1061 case SPOOLSS_PRINTER_CONTROL_UNPAUSE: /* 0 */
1062 /* is ignored for all levels other then 0 */
1063 if (info_ctr.level > 0) {
1064 /* ignored then */
1065 break;
1067 case SPOOLSS_PRINTER_CONTROL_PAUSE: /* 1 */
1068 case SPOOLSS_PRINTER_CONTROL_RESUME: /* 2 */
1069 case SPOOLSS_PRINTER_CONTROL_PURGE: /* 3 */
1070 if (info_ctr.level > 0) {
1071 /* is invalid for all levels other then 0 */
1072 torture_assert_werr_equal(tctx, r.out.result, WERR_INVALID_PRINTER_COMMAND,
1073 "unexpected error code returned");
1074 continue;
1075 } else {
1076 torture_assert_werr_ok(tctx, r.out.result,
1077 "failed to call SetPrinter with non 0 command");
1078 continue;
1080 break;
1082 case SPOOLSS_PRINTER_CONTROL_SET_STATUS: /* 4 */
1083 /* FIXME: gd needs further investigation */
1084 default:
1085 torture_assert_werr_equal(tctx, r.out.result, WERR_INVALID_PRINTER_COMMAND,
1086 "unexpected error code returned");
1087 continue;
1090 switch (info_ctr.level) {
1091 case 1:
1092 torture_assert_werr_equal(tctx, r.out.result, WERR_UNKNOWN_LEVEL,
1093 "unexpected error code returned");
1094 break;
1095 case 2:
1096 torture_assert_werr_equal(tctx, r.out.result, WERR_UNKNOWN_PRINTER_DRIVER,
1097 "unexpected error code returned");
1098 break;
1099 case 3:
1100 case 4:
1101 case 5:
1102 case 7:
1103 torture_assert_werr_equal(tctx, r.out.result, WERR_INVALID_PARAM,
1104 "unexpected error code returned");
1105 break;
1106 case 9:
1107 torture_assert_werr_equal(tctx, r.out.result, WERR_NOT_SUPPORTED,
1108 "unexpected error code returned");
1109 break;
1110 default:
1111 torture_assert_werr_ok(tctx, r.out.result,
1112 "failed to call SetPrinter");
1113 break;
1117 if (r.in.command < 5) {
1118 r.in.command++;
1119 goto again;
1122 return true;
1125 static void clear_info2(struct spoolss_SetPrinterInfoCtr *r)
1127 if ((r->level == 2) && (r->info.info2)) {
1128 r->info.info2->secdesc_ptr = 0;
1129 r->info.info2->devmode_ptr = 0;
1133 static bool test_PrinterInfo(struct torture_context *tctx,
1134 struct dcerpc_pipe *p,
1135 struct policy_handle *handle)
1137 NTSTATUS status;
1138 struct spoolss_SetPrinter s;
1139 struct spoolss_GetPrinter q;
1140 struct spoolss_GetPrinter q0;
1141 struct spoolss_SetPrinterInfoCtr info_ctr;
1142 union spoolss_PrinterInfo info;
1143 struct spoolss_DevmodeContainer devmode_ctr;
1144 struct sec_desc_buf secdesc_ctr;
1145 uint32_t needed;
1146 bool ret = true;
1147 int i;
1149 uint32_t status_list[] = {
1150 /* these do not stick
1151 PRINTER_STATUS_PAUSED,
1152 PRINTER_STATUS_ERROR,
1153 PRINTER_STATUS_PENDING_DELETION, */
1154 PRINTER_STATUS_PAPER_JAM,
1155 PRINTER_STATUS_PAPER_OUT,
1156 PRINTER_STATUS_MANUAL_FEED,
1157 PRINTER_STATUS_PAPER_PROBLEM,
1158 PRINTER_STATUS_OFFLINE,
1159 PRINTER_STATUS_IO_ACTIVE,
1160 PRINTER_STATUS_BUSY,
1161 PRINTER_STATUS_PRINTING,
1162 PRINTER_STATUS_OUTPUT_BIN_FULL,
1163 PRINTER_STATUS_NOT_AVAILABLE,
1164 PRINTER_STATUS_WAITING,
1165 PRINTER_STATUS_PROCESSING,
1166 PRINTER_STATUS_INITIALIZING,
1167 PRINTER_STATUS_WARMING_UP,
1168 PRINTER_STATUS_TONER_LOW,
1169 PRINTER_STATUS_NO_TONER,
1170 PRINTER_STATUS_PAGE_PUNT,
1171 PRINTER_STATUS_USER_INTERVENTION,
1172 PRINTER_STATUS_OUT_OF_MEMORY,
1173 PRINTER_STATUS_DOOR_OPEN,
1174 PRINTER_STATUS_SERVER_UNKNOWN,
1175 PRINTER_STATUS_POWER_SAVE,
1176 /* these do not stick
1177 0x02000000,
1178 0x04000000,
1179 0x08000000,
1180 0x10000000,
1181 0x20000000,
1182 0x40000000,
1183 0x80000000 */
1185 uint32_t default_attribute = PRINTER_ATTRIBUTE_LOCAL;
1186 uint32_t attribute_list[] = {
1187 PRINTER_ATTRIBUTE_QUEUED,
1188 /* fails with WERR_INVALID_DATATYPE:
1189 PRINTER_ATTRIBUTE_DIRECT, */
1190 /* does not stick
1191 PRINTER_ATTRIBUTE_DEFAULT, */
1192 PRINTER_ATTRIBUTE_SHARED,
1193 /* does not stick
1194 PRINTER_ATTRIBUTE_NETWORK, */
1195 PRINTER_ATTRIBUTE_HIDDEN,
1196 PRINTER_ATTRIBUTE_LOCAL,
1197 PRINTER_ATTRIBUTE_ENABLE_DEVQ,
1198 PRINTER_ATTRIBUTE_KEEPPRINTEDJOBS,
1199 PRINTER_ATTRIBUTE_DO_COMPLETE_FIRST,
1200 PRINTER_ATTRIBUTE_WORK_OFFLINE,
1201 /* does not stick
1202 PRINTER_ATTRIBUTE_ENABLE_BIDI, */
1203 /* fails with WERR_INVALID_DATATYPE:
1204 PRINTER_ATTRIBUTE_RAW_ONLY, */
1205 /* these do not stick
1206 PRINTER_ATTRIBUTE_PUBLISHED,
1207 PRINTER_ATTRIBUTE_FAX,
1208 PRINTER_ATTRIBUTE_TS,
1209 0x00010000,
1210 0x00020000,
1211 0x00040000,
1212 0x00080000,
1213 0x00100000,
1214 0x00200000,
1215 0x00400000,
1216 0x00800000,
1217 0x01000000,
1218 0x02000000,
1219 0x04000000,
1220 0x08000000,
1221 0x10000000,
1222 0x20000000,
1223 0x40000000,
1224 0x80000000 */
1227 ZERO_STRUCT(devmode_ctr);
1228 ZERO_STRUCT(secdesc_ctr);
1230 s.in.handle = handle;
1231 s.in.command = 0;
1232 s.in.info_ctr = &info_ctr;
1233 s.in.devmode_ctr = &devmode_ctr;
1234 s.in.secdesc_ctr = &secdesc_ctr;
1236 q.in.handle = handle;
1237 q.out.info = &info;
1238 q0 = q;
1240 #define TESTGETCALL(call, r) \
1241 r.in.buffer = NULL; \
1242 r.in.offered = 0;\
1243 r.out.needed = &needed; \
1244 status = dcerpc_spoolss_ ##call(p, tctx, &r); \
1245 if (!NT_STATUS_IS_OK(status)) { \
1246 torture_comment(tctx, #call " level %u failed - %s (%s)\n", \
1247 r.in.level, nt_errstr(status), __location__); \
1248 ret = false; \
1249 break; \
1251 if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {\
1252 DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed); \
1253 data_blob_clear(&blob); \
1254 r.in.buffer = &blob; \
1255 r.in.offered = needed; \
1257 status = dcerpc_spoolss_ ##call(p, tctx, &r); \
1258 if (!NT_STATUS_IS_OK(status)) { \
1259 torture_comment(tctx, #call " level %u failed - %s (%s)\n", \
1260 r.in.level, nt_errstr(status), __location__); \
1261 ret = false; \
1262 break; \
1264 if (!W_ERROR_IS_OK(r.out.result)) { \
1265 torture_comment(tctx, #call " level %u failed - %s (%s)\n", \
1266 r.in.level, win_errstr(r.out.result), __location__); \
1267 ret = false; \
1268 break; \
1272 #define TESTSETCALL_EXP(call, r, err) \
1273 clear_info2(&info_ctr);\
1274 status = dcerpc_spoolss_ ##call(p, tctx, &r); \
1275 if (!NT_STATUS_IS_OK(status)) { \
1276 torture_comment(tctx, #call " level %u failed - %s (%s)\n", \
1277 r.in.info_ctr->level, nt_errstr(status), __location__); \
1278 ret = false; \
1279 break; \
1281 if (!W_ERROR_IS_OK(err)) { \
1282 if (!W_ERROR_EQUAL(err, r.out.result)) { \
1283 torture_comment(tctx, #call " level %u failed - %s, expected %s (%s)\n", \
1284 r.in.info_ctr->level, win_errstr(r.out.result), win_errstr(err), __location__); \
1285 ret = false; \
1287 break; \
1289 if (!W_ERROR_IS_OK(r.out.result)) { \
1290 torture_comment(tctx, #call " level %u failed - %s (%s)\n", \
1291 r.in.info_ctr->level, win_errstr(r.out.result), __location__); \
1292 ret = false; \
1293 break; \
1296 #define TESTSETCALL(call, r) \
1297 TESTSETCALL_EXP(call, r, WERR_OK)
1299 #define STRING_EQUAL(s1, s2, field) \
1300 if ((s1 && !s2) || (s2 && !s1) || strcmp(s1, s2)) { \
1301 torture_comment(tctx, "Failed to set %s to '%s' (%s)\n", \
1302 #field, s2, __location__); \
1303 ret = false; \
1304 break; \
1307 #define MEM_EQUAL(s1, s2, length, field) \
1308 if ((s1 && !s2) || (s2 && !s1) || memcmp(s1, s2, length)) { \
1309 torture_comment(tctx, "Failed to set %s to '%s' (%s)\n", \
1310 #field, (const char *)s2, __location__); \
1311 ret = false; \
1312 break; \
1315 #define INT_EQUAL(i1, i2, field) \
1316 if (i1 != i2) { \
1317 torture_comment(tctx, "Failed to set %s to 0x%llx - got 0x%llx (%s)\n", \
1318 #field, (unsigned long long)i2, (unsigned long long)i1, __location__); \
1319 ret = false; \
1320 break; \
1323 #define SD_EQUAL(sd1, sd2, field) \
1324 if (!security_descriptor_equal(sd1, sd2)) { \
1325 torture_comment(tctx, "Failed to set %s (%s)\n", \
1326 #field, __location__); \
1327 ret = false; \
1328 break; \
1331 #define TEST_PRINTERINFO_STRING_EXP_ERR(lvl1, field1, lvl2, field2, value, err) do { \
1332 torture_comment(tctx, "field test %d/%s vs %d/%s\n", lvl1, #field1, lvl2, #field2); \
1333 q.in.level = lvl1; \
1334 TESTGETCALL(GetPrinter, q) \
1335 info_ctr.level = lvl1; \
1336 info_ctr.info.info ## lvl1 = (struct spoolss_SetPrinterInfo ## lvl1 *)&q.out.info->info ## lvl1; \
1337 info_ctr.info.info ## lvl1->field1 = value;\
1338 TESTSETCALL_EXP(SetPrinter, s, err) \
1339 info_ctr.info.info ## lvl1->field1 = ""; \
1340 TESTGETCALL(GetPrinter, q) \
1341 info_ctr.info.info ## lvl1->field1 = value; \
1342 STRING_EQUAL(info_ctr.info.info ## lvl1->field1, value, field1); \
1343 q.in.level = lvl2; \
1344 TESTGETCALL(GetPrinter, q) \
1345 info_ctr.info.info ## lvl2 = (struct spoolss_SetPrinterInfo ## lvl2 *)&q.out.info->info ## lvl2; \
1346 STRING_EQUAL(info_ctr.info.info ## lvl2->field2, value, field2); \
1347 } while (0)
1349 #define TEST_PRINTERINFO_STRING(lvl1, field1, lvl2, field2, value) do { \
1350 TEST_PRINTERINFO_STRING_EXP_ERR(lvl1, field1, lvl2, field2, value, WERR_OK); \
1351 } while (0);
1353 #define TEST_PRINTERINFO_INT_EXP(lvl1, field1, lvl2, field2, value, exp_value) do { \
1354 torture_comment(tctx, "field test %d/%s vs %d/%s\n", lvl1, #field1, lvl2, #field2); \
1355 q.in.level = lvl1; \
1356 TESTGETCALL(GetPrinter, q) \
1357 info_ctr.level = lvl1; \
1358 info_ctr.info.info ## lvl1 = (struct spoolss_SetPrinterInfo ## lvl1 *)&q.out.info->info ## lvl1; \
1359 info_ctr.info.info ## lvl1->field1 = value; \
1360 TESTSETCALL(SetPrinter, s) \
1361 info_ctr.info.info ## lvl1->field1 = 0; \
1362 TESTGETCALL(GetPrinter, q) \
1363 info_ctr.info.info ## lvl1 = (struct spoolss_SetPrinterInfo ## lvl1 *)&q.out.info->info ## lvl1; \
1364 INT_EQUAL(info_ctr.info.info ## lvl1->field1, exp_value, field1); \
1365 q.in.level = lvl2; \
1366 TESTGETCALL(GetPrinter, q) \
1367 info_ctr.info.info ## lvl2 = (struct spoolss_SetPrinterInfo ## lvl2 *)&q.out.info->info ## lvl2; \
1368 INT_EQUAL(info_ctr.info.info ## lvl2->field2, exp_value, field1); \
1369 } while (0)
1371 #define TEST_PRINTERINFO_INT(lvl1, field1, lvl2, field2, value) do { \
1372 TEST_PRINTERINFO_INT_EXP(lvl1, field1, lvl2, field2, value, value); \
1373 } while (0)
1375 q0.in.level = 0;
1376 do { TESTGETCALL(GetPrinter, q0) } while (0);
1378 TEST_PRINTERINFO_STRING(2, comment, 1, comment, "xx2-1 comment");
1379 TEST_PRINTERINFO_STRING(2, comment, 2, comment, "xx2-2 comment");
1381 /* level 0 printername does not stick */
1382 /* TEST_PRINTERINFO_STRING(2, printername, 0, printername, "xx2-0 printer"); */
1383 TEST_PRINTERINFO_STRING(2, printername, 1, name, "xx2-1 printer");
1384 TEST_PRINTERINFO_STRING(2, printername, 2, printername, "xx2-2 printer");
1385 TEST_PRINTERINFO_STRING(2, printername, 4, printername, "xx2-4 printer");
1386 TEST_PRINTERINFO_STRING(2, printername, 5, printername, "xx2-5 printer");
1387 /* TEST_PRINTERINFO_STRING(4, printername, 0, printername, "xx4-0 printer"); */
1388 TEST_PRINTERINFO_STRING(4, printername, 1, name, "xx4-1 printer");
1389 TEST_PRINTERINFO_STRING(4, printername, 2, printername, "xx4-2 printer");
1390 TEST_PRINTERINFO_STRING(4, printername, 4, printername, "xx4-4 printer");
1391 TEST_PRINTERINFO_STRING(4, printername, 5, printername, "xx4-5 printer");
1392 /* TEST_PRINTERINFO_STRING(5, printername, 0, printername, "xx5-0 printer"); */
1393 TEST_PRINTERINFO_STRING(5, printername, 1, name, "xx5-1 printer");
1394 TEST_PRINTERINFO_STRING(5, printername, 2, printername, "xx5-2 printer");
1395 TEST_PRINTERINFO_STRING(5, printername, 4, printername, "xx5-4 printer");
1396 TEST_PRINTERINFO_STRING(5, printername, 5, printername, "xx5-5 printer");
1398 /* servername can be set but does not stick
1399 TEST_PRINTERINFO_STRING(2, servername, 0, servername, "xx2-0 servername");
1400 TEST_PRINTERINFO_STRING(2, servername, 2, servername, "xx2-2 servername");
1401 TEST_PRINTERINFO_STRING(2, servername, 4, servername, "xx2-4 servername");
1404 /* passing an invalid port will result in WERR_UNKNOWN_PORT */
1405 TEST_PRINTERINFO_STRING_EXP_ERR(2, portname, 2, portname, "xx2-2 portname", WERR_UNKNOWN_PORT);
1406 TEST_PRINTERINFO_STRING_EXP_ERR(2, portname, 5, portname, "xx2-5 portname", WERR_UNKNOWN_PORT);
1407 TEST_PRINTERINFO_STRING_EXP_ERR(5, portname, 2, portname, "xx5-2 portname", WERR_UNKNOWN_PORT);
1408 TEST_PRINTERINFO_STRING_EXP_ERR(5, portname, 5, portname, "xx5-5 portname", WERR_UNKNOWN_PORT);
1410 TEST_PRINTERINFO_STRING(2, sharename, 2, sharename, "xx2-2 sharename");
1411 /* passing an invalid driver will result in WERR_UNKNOWN_PRINTER_DRIVER */
1412 TEST_PRINTERINFO_STRING_EXP_ERR(2, drivername, 2, drivername, "xx2-2 drivername", WERR_UNKNOWN_PRINTER_DRIVER);
1413 TEST_PRINTERINFO_STRING(2, location, 2, location, "xx2-2 location");
1414 /* passing an invalid sepfile will result in WERR_INVALID_SEPARATOR_FILE */
1415 TEST_PRINTERINFO_STRING_EXP_ERR(2, sepfile, 2, sepfile, "xx2-2 sepfile", WERR_INVALID_SEPARATOR_FILE);
1416 /* passing an invalid printprocessor will result in WERR_UNKNOWN_PRINTPROCESSOR */
1417 TEST_PRINTERINFO_STRING_EXP_ERR(2, printprocessor, 2, printprocessor, "xx2-2 printprocessor", WERR_UNKNOWN_PRINTPROCESSOR);
1418 TEST_PRINTERINFO_STRING(2, datatype, 2, datatype, "xx2-2 datatype");
1419 TEST_PRINTERINFO_STRING(2, parameters, 2, parameters, "xx2-2 parameters");
1421 for (i=0; i < ARRAY_SIZE(attribute_list); i++) {
1422 /* TEST_PRINTERINFO_INT_EXP(2, attributes, 1, flags,
1423 attribute_list[i],
1424 (attribute_list[i] | default_attribute)
1425 ); */
1426 TEST_PRINTERINFO_INT_EXP(2, attributes, 2, attributes,
1427 attribute_list[i],
1428 (attribute_list[i] | default_attribute)
1430 TEST_PRINTERINFO_INT_EXP(2, attributes, 4, attributes,
1431 attribute_list[i],
1432 (attribute_list[i] | default_attribute)
1434 TEST_PRINTERINFO_INT_EXP(2, attributes, 5, attributes,
1435 attribute_list[i],
1436 (attribute_list[i] | default_attribute)
1438 /* TEST_PRINTERINFO_INT_EXP(4, attributes, 1, flags,
1439 attribute_list[i],
1440 (attribute_list[i] | default_attribute)
1441 ); */
1442 TEST_PRINTERINFO_INT_EXP(4, attributes, 2, attributes,
1443 attribute_list[i],
1444 (attribute_list[i] | default_attribute)
1446 TEST_PRINTERINFO_INT_EXP(4, attributes, 4, attributes,
1447 attribute_list[i],
1448 (attribute_list[i] | default_attribute)
1450 TEST_PRINTERINFO_INT_EXP(4, attributes, 5, attributes,
1451 attribute_list[i],
1452 (attribute_list[i] | default_attribute)
1454 /* TEST_PRINTERINFO_INT_EXP(5, attributes, 1, flags,
1455 attribute_list[i],
1456 (attribute_list[i] | default_attribute)
1457 ); */
1458 TEST_PRINTERINFO_INT_EXP(5, attributes, 2, attributes,
1459 attribute_list[i],
1460 (attribute_list[i] | default_attribute)
1462 TEST_PRINTERINFO_INT_EXP(5, attributes, 4, attributes,
1463 attribute_list[i],
1464 (attribute_list[i] | default_attribute)
1466 TEST_PRINTERINFO_INT_EXP(5, attributes, 5, attributes,
1467 attribute_list[i],
1468 (attribute_list[i] | default_attribute)
1472 for (i=0; i < ARRAY_SIZE(status_list); i++) {
1473 /* level 2 sets do not stick
1474 TEST_PRINTERINFO_INT(2, status, 0, status, status_list[i]);
1475 TEST_PRINTERINFO_INT(2, status, 2, status, status_list[i]);
1476 TEST_PRINTERINFO_INT(2, status, 6, status, status_list[i]); */
1477 TEST_PRINTERINFO_INT(6, status, 0, status, status_list[i]);
1478 TEST_PRINTERINFO_INT(6, status, 2, status, status_list[i]);
1479 TEST_PRINTERINFO_INT(6, status, 6, status, status_list[i]);
1482 /* priorities need to be between 0 and 99
1483 passing an invalid priority will result in WERR_INVALID_PRIORITY */
1484 TEST_PRINTERINFO_INT(2, priority, 2, priority, 0);
1485 TEST_PRINTERINFO_INT(2, priority, 2, priority, 1);
1486 TEST_PRINTERINFO_INT(2, priority, 2, priority, 99);
1487 /* TEST_PRINTERINFO_INT(2, priority, 2, priority, 100); */
1488 TEST_PRINTERINFO_INT(2, defaultpriority,2, defaultpriority, 0);
1489 TEST_PRINTERINFO_INT(2, defaultpriority,2, defaultpriority, 1);
1490 TEST_PRINTERINFO_INT(2, defaultpriority,2, defaultpriority, 99);
1491 /* TEST_PRINTERINFO_INT(2, defaultpriority,2, defaultpriority, 100); */
1493 TEST_PRINTERINFO_INT(2, starttime, 2, starttime, __LINE__);
1494 TEST_PRINTERINFO_INT(2, untiltime, 2, untiltime, __LINE__);
1496 /* does not stick
1497 TEST_PRINTERINFO_INT(2, cjobs, 2, cjobs, __LINE__);
1498 TEST_PRINTERINFO_INT(2, averageppm, 2, averageppm, __LINE__); */
1500 /* does not stick
1501 TEST_PRINTERINFO_INT(5, device_not_selected_timeout, 5, device_not_selected_timeout, __LINE__);
1502 TEST_PRINTERINFO_INT(5, transmission_retry_timeout, 5, transmission_retry_timeout, __LINE__); */
1504 /* FIXME: gd also test devmode and secdesc behavior */
1507 /* verify composition of level 1 description field */
1508 const char *description;
1509 const char *tmp;
1511 q0.in.level = 1;
1512 do { TESTGETCALL(GetPrinter, q0) } while (0);
1514 description = talloc_strdup(tctx, q0.out.info->info1.description);
1516 q0.in.level = 2;
1517 do { TESTGETCALL(GetPrinter, q0) } while (0);
1519 tmp = talloc_asprintf(tctx, "%s,%s,%s",
1520 q0.out.info->info2.printername,
1521 q0.out.info->info2.drivername,
1522 q0.out.info->info2.location);
1524 do { STRING_EQUAL(description, tmp, "description")} while (0);
1527 return ret;
1530 #define torture_assert_sid_equal(torture_ctx,got,expected,cmt)\
1531 do { struct dom_sid *__got = (got), *__expected = (expected); \
1532 if (!dom_sid_equal(__got, __expected)) { \
1533 torture_result(torture_ctx, TORTURE_FAIL, \
1534 __location__": "#got" was %s, expected %s: %s", \
1535 dom_sid_string(torture_ctx, __got), dom_sid_string(torture_ctx, __expected), cmt); \
1536 return false; \
1538 } while(0)
1540 static bool test_security_descriptor_equal(struct torture_context *tctx,
1541 const struct security_descriptor *sd1,
1542 const struct security_descriptor *sd2)
1544 if (sd1 == sd2) {
1545 return true;
1548 if (!sd1 || !sd2) {
1549 torture_comment(tctx, "%s\n", __location__);
1550 return false;
1553 torture_assert_int_equal(tctx, sd1->revision, sd2->revision, "revision mismatch");
1554 torture_assert_int_equal(tctx, sd1->type, sd2->type, "type mismatch");
1556 torture_assert_sid_equal(tctx, sd1->owner_sid, sd2->owner_sid, "owner mismatch");
1557 torture_assert_sid_equal(tctx, sd1->group_sid, sd2->group_sid, "group mismatch");
1559 if (!security_acl_equal(sd1->sacl, sd2->sacl)) {
1560 torture_comment(tctx, "%s: sacl mismatch\n", __location__);
1561 NDR_PRINT_DEBUG(security_acl, sd1->sacl);
1562 NDR_PRINT_DEBUG(security_acl, sd2->sacl);
1563 return false;
1565 if (!security_acl_equal(sd1->dacl, sd2->dacl)) {
1566 torture_comment(tctx, "%s: dacl mismatch\n", __location__);
1567 NDR_PRINT_DEBUG(security_acl, sd1->dacl);
1568 NDR_PRINT_DEBUG(security_acl, sd2->dacl);
1569 return false;
1572 return true;
1575 static bool test_sd_set_level(struct torture_context *tctx,
1576 struct dcerpc_pipe *p,
1577 struct policy_handle *handle,
1578 uint32_t level,
1579 struct security_descriptor *sd)
1581 struct spoolss_SetPrinterInfoCtr info_ctr;
1582 struct spoolss_DevmodeContainer devmode_ctr;
1583 struct sec_desc_buf secdesc_ctr;
1585 ZERO_STRUCT(devmode_ctr);
1586 ZERO_STRUCT(secdesc_ctr);
1588 switch (level) {
1589 case 2: {
1590 union spoolss_PrinterInfo info;
1591 struct spoolss_SetPrinterInfo2 info2;
1592 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 2, &info), "");
1594 info2.servername = info.info2.servername;
1595 info2.printername = info.info2.printername;
1596 info2.sharename = info.info2.sharename;
1597 info2.portname = info.info2.portname;
1598 info2.drivername = info.info2.drivername;
1599 info2.comment = info.info2.comment;
1600 info2.location = info.info2.location;
1601 info2.devmode_ptr = 0;
1602 info2.sepfile = info.info2.sepfile;
1603 info2.printprocessor = info.info2.printprocessor;
1604 info2.datatype = info.info2.datatype;
1605 info2.parameters = info.info2.parameters;
1606 info2.secdesc_ptr = 0;
1607 info2.attributes = info.info2.attributes;
1608 info2.priority = info.info2.priority;
1609 info2.defaultpriority = info.info2.defaultpriority;
1610 info2.starttime = info.info2.starttime;
1611 info2.untiltime = info.info2.untiltime;
1612 info2.status = info.info2.status;
1613 info2.cjobs = info.info2.cjobs;
1614 info2.averageppm = info.info2.averageppm;
1616 info_ctr.level = 2;
1617 info_ctr.info.info2 = &info2;
1619 break;
1621 case 3: {
1622 struct spoolss_SetPrinterInfo3 info3;
1624 info3.sec_desc_ptr = 0;
1626 info_ctr.level = 3;
1627 info_ctr.info.info3 = &info3;
1629 break;
1631 default:
1632 return false;
1635 secdesc_ctr.sd = sd;
1637 torture_assert(tctx,
1638 test_SetPrinter(tctx, p, handle, &info_ctr, &devmode_ctr, &secdesc_ctr, 0), "");
1640 return true;
1643 static bool test_PrinterInfo_SDs(struct torture_context *tctx,
1644 struct dcerpc_pipe *p,
1645 struct policy_handle *handle)
1647 union spoolss_PrinterInfo info;
1648 struct security_descriptor *sd1, *sd2;
1649 int i;
1651 /* just compare level 2 and level 3 */
1653 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 2, &info), "");
1655 sd1 = info.info2.secdesc;
1657 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 3, &info), "");
1659 sd2 = info.info3.secdesc;
1661 torture_assert(tctx, test_security_descriptor_equal(tctx, sd1, sd2), "");
1664 /* query level 2, set level 2, query level 2 */
1666 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 2, &info), "");
1668 sd1 = info.info2.secdesc;
1670 torture_assert(tctx, test_sd_set_level(tctx, p, handle, 2, sd1), "");
1672 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 2, &info), "");
1674 sd2 = info.info2.secdesc;
1675 if (sd1->type & SEC_DESC_DACL_DEFAULTED) {
1676 torture_comment(tctx, "removing SEC_DESC_DACL_DEFAULTED\n");
1677 sd1->type &= ~SEC_DESC_DACL_DEFAULTED;
1680 torture_assert(tctx, test_security_descriptor_equal(tctx, sd1, sd2), "");
1683 /* query level 2, set level 3, query level 2 */
1685 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 2, &info), "");
1687 sd1 = info.info2.secdesc;
1689 torture_assert(tctx, test_sd_set_level(tctx, p, handle, 3, sd1), "");
1691 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 2, &info), "");
1693 sd2 = info.info2.secdesc;
1695 torture_assert(tctx, test_security_descriptor_equal(tctx, sd1, sd2), "");
1698 /* set modified sd level 3, query level 2 */
1700 for (i=0; i < 93; i++) {
1701 struct security_ace a;
1702 const char *sid_string = talloc_asprintf(tctx, "S-1-5-32-9999%i", i);
1703 a.type = SEC_ACE_TYPE_ACCESS_ALLOWED;
1704 a.flags = 0;
1705 a.size = 0; /* autogenerated */
1706 a.access_mask = 0;
1707 a.trustee = *dom_sid_parse_talloc(tctx, sid_string);
1708 torture_assert_ntstatus_ok(tctx, security_descriptor_dacl_add(sd1, &a), "");
1711 torture_assert(tctx, test_sd_set_level(tctx, p, handle, 3, sd1), "");
1713 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 2, &info), "");
1714 sd2 = info.info2.secdesc;
1716 if (sd1->type & SEC_DESC_DACL_DEFAULTED) {
1717 torture_comment(tctx, "removing SEC_DESC_DACL_DEFAULTED\n");
1718 sd1->type &= ~SEC_DESC_DACL_DEFAULTED;
1721 torture_assert(tctx, test_security_descriptor_equal(tctx, sd1, sd2), "");
1723 return true;
1727 * wrapper call that saves original sd, runs tests, and restores sd
1730 static bool test_PrinterInfo_SD(struct torture_context *tctx,
1731 struct dcerpc_pipe *p,
1732 struct policy_handle *handle)
1734 union spoolss_PrinterInfo info;
1735 struct spoolss_SetPrinterInfo3 info3;
1736 struct spoolss_SetPrinterInfoCtr info_ctr;
1737 struct spoolss_DevmodeContainer devmode_ctr;
1738 struct sec_desc_buf secdesc_ctr;
1739 struct security_descriptor *sd;
1740 bool ret = true;
1742 /* save original sd */
1744 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 2, &info), "");
1746 sd = security_descriptor_copy(tctx, info.info2.secdesc);
1748 /* run tests */
1750 ret = test_PrinterInfo_SDs(tctx, p, handle);
1752 /* restore original sd */
1754 ZERO_STRUCT(devmode_ctr);
1755 ZERO_STRUCT(secdesc_ctr);
1757 info3.sec_desc_ptr = 0;
1759 info_ctr.level = 3;
1760 info_ctr.info.info3 = &info3;
1762 secdesc_ctr.sd = sd;
1764 torture_assert(tctx,
1765 test_SetPrinter(tctx, p, handle, &info_ctr, &devmode_ctr, &secdesc_ctr, 0), "");
1767 return ret;
1770 static bool test_devmode_set_level(struct torture_context *tctx,
1771 struct dcerpc_pipe *p,
1772 struct policy_handle *handle,
1773 uint32_t level,
1774 struct spoolss_DeviceMode *devmode)
1776 struct spoolss_SetPrinterInfoCtr info_ctr;
1777 struct spoolss_DevmodeContainer devmode_ctr;
1778 struct sec_desc_buf secdesc_ctr;
1780 ZERO_STRUCT(devmode_ctr);
1781 ZERO_STRUCT(secdesc_ctr);
1783 switch (level) {
1784 case 2: {
1785 union spoolss_PrinterInfo info;
1786 struct spoolss_SetPrinterInfo2 info2;
1787 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 2, &info), "");
1789 info2.servername = info.info2.servername;
1790 info2.printername = info.info2.printername;
1791 info2.sharename = info.info2.sharename;
1792 info2.portname = info.info2.portname;
1793 info2.drivername = info.info2.drivername;
1794 info2.comment = info.info2.comment;
1795 info2.location = info.info2.location;
1796 info2.devmode_ptr = 0;
1797 info2.sepfile = info.info2.sepfile;
1798 info2.printprocessor = info.info2.printprocessor;
1799 info2.datatype = info.info2.datatype;
1800 info2.parameters = info.info2.parameters;
1801 info2.secdesc_ptr = 0;
1802 info2.attributes = info.info2.attributes;
1803 info2.priority = info.info2.priority;
1804 info2.defaultpriority = info.info2.defaultpriority;
1805 info2.starttime = info.info2.starttime;
1806 info2.untiltime = info.info2.untiltime;
1807 info2.status = info.info2.status;
1808 info2.cjobs = info.info2.cjobs;
1809 info2.averageppm = info.info2.averageppm;
1811 info_ctr.level = 2;
1812 info_ctr.info.info2 = &info2;
1814 break;
1816 case 8: {
1817 struct spoolss_SetPrinterInfo8 info8;
1819 info8.devmode_ptr = 0;
1821 info_ctr.level = 8;
1822 info_ctr.info.info8 = &info8;
1824 break;
1826 default:
1827 return false;
1830 devmode_ctr.devmode = devmode;
1832 torture_assert(tctx,
1833 test_SetPrinter(tctx, p, handle, &info_ctr, &devmode_ctr, &secdesc_ctr, 0), "");
1835 return true;
1839 static bool test_devicemode_equal(struct torture_context *tctx,
1840 const struct spoolss_DeviceMode *d1,
1841 const struct spoolss_DeviceMode *d2)
1843 if (d1 == d2) {
1844 return true;
1847 if (!d1 || !d2) {
1848 torture_comment(tctx, "%s\n", __location__);
1849 return false;
1851 torture_assert_str_equal(tctx, d1->devicename, d2->devicename, "devicename mismatch");
1852 torture_assert_int_equal(tctx, d1->specversion, d2->specversion, "specversion mismatch");
1853 torture_assert_int_equal(tctx, d1->driverversion, d2->driverversion, "driverversion mismatch");
1854 torture_assert_int_equal(tctx, d1->size, d2->size, "size mismatch");
1855 torture_assert_int_equal(tctx, d1->__driverextra_length, d2->__driverextra_length, "__driverextra_length mismatch");
1856 torture_assert_int_equal(tctx, d1->fields, d2->fields, "fields mismatch");
1857 torture_assert_int_equal(tctx, d1->orientation, d2->orientation, "orientation mismatch");
1858 torture_assert_int_equal(tctx, d1->papersize, d2->papersize, "papersize mismatch");
1859 torture_assert_int_equal(tctx, d1->paperlength, d2->paperlength, "paperlength mismatch");
1860 torture_assert_int_equal(tctx, d1->paperwidth, d2->paperwidth, "paperwidth mismatch");
1861 torture_assert_int_equal(tctx, d1->scale, d2->scale, "scale mismatch");
1862 torture_assert_int_equal(tctx, d1->copies, d2->copies, "copies mismatch");
1863 torture_assert_int_equal(tctx, d1->defaultsource, d2->defaultsource, "defaultsource mismatch");
1864 torture_assert_int_equal(tctx, d1->printquality, d2->printquality, "printquality mismatch");
1865 torture_assert_int_equal(tctx, d1->color, d2->color, "color mismatch");
1866 torture_assert_int_equal(tctx, d1->duplex, d2->duplex, "duplex mismatch");
1867 torture_assert_int_equal(tctx, d1->yresolution, d2->yresolution, "yresolution mismatch");
1868 torture_assert_int_equal(tctx, d1->ttoption, d2->ttoption, "ttoption mismatch");
1869 torture_assert_int_equal(tctx, d1->collate, d2->collate, "collate mismatch");
1870 torture_assert_str_equal(tctx, d1->formname, d2->formname, "formname mismatch");
1871 torture_assert_int_equal(tctx, d1->logpixels, d2->logpixels, "logpixels mismatch");
1872 torture_assert_int_equal(tctx, d1->bitsperpel, d2->bitsperpel, "bitsperpel mismatch");
1873 torture_assert_int_equal(tctx, d1->pelswidth, d2->pelswidth, "pelswidth mismatch");
1874 torture_assert_int_equal(tctx, d1->pelsheight, d2->pelsheight, "pelsheight mismatch");
1875 torture_assert_int_equal(tctx, d1->displayflags, d2->displayflags, "displayflags mismatch");
1876 torture_assert_int_equal(tctx, d1->displayfrequency, d2->displayfrequency, "displayfrequency mismatch");
1877 torture_assert_int_equal(tctx, d1->icmmethod, d2->icmmethod, "icmmethod mismatch");
1878 torture_assert_int_equal(tctx, d1->icmintent, d2->icmintent, "icmintent mismatch");
1879 torture_assert_int_equal(tctx, d1->mediatype, d2->mediatype, "mediatype mismatch");
1880 torture_assert_int_equal(tctx, d1->dithertype, d2->dithertype, "dithertype mismatch");
1881 torture_assert_int_equal(tctx, d1->reserved1, d2->reserved1, "reserved1 mismatch");
1882 torture_assert_int_equal(tctx, d1->reserved2, d2->reserved2, "reserved2 mismatch");
1883 torture_assert_int_equal(tctx, d1->panningwidth, d2->panningwidth, "panningwidth mismatch");
1884 torture_assert_int_equal(tctx, d1->panningheight, d2->panningheight, "panningheight mismatch");
1885 torture_assert_data_blob_equal(tctx, d1->driverextra_data, d2->driverextra_data, "driverextra_data mismatch");
1887 return true;
1890 static bool call_OpenPrinterEx(struct torture_context *tctx,
1891 struct dcerpc_pipe *p,
1892 const char *name,
1893 struct spoolss_DeviceMode *devmode,
1894 struct policy_handle *handle);
1896 static bool test_ClosePrinter(struct torture_context *tctx,
1897 struct dcerpc_pipe *p,
1898 struct policy_handle *handle);
1900 static bool test_PrinterInfo_DevModes(struct torture_context *tctx,
1901 struct dcerpc_pipe *p,
1902 struct policy_handle *handle,
1903 const char *name)
1905 union spoolss_PrinterInfo info;
1906 struct spoolss_DeviceMode *devmode;
1907 struct spoolss_DeviceMode *devmode2;
1908 struct policy_handle handle_devmode;
1910 /* simply compare level8 and level2 devmode */
1912 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 8, &info), "");
1914 devmode = info.info8.devmode;
1916 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 2, &info), "");
1918 devmode2 = info.info2.devmode;
1920 torture_assert(tctx, test_devicemode_equal(tctx, devmode, devmode2), "");
1923 /* change formname upon open and see if it persists in getprinter calls */
1925 devmode->formname = talloc_strdup(tctx, "A4");
1927 torture_assert(tctx, call_OpenPrinterEx(tctx, p, name, devmode, &handle_devmode),
1928 "failed to open printer handle");
1930 torture_assert(tctx, test_GetPrinter_level(tctx, p, &handle_devmode, 8, &info), "");
1932 devmode2 = info.info8.devmode;
1934 if (strequal(devmode->devicename, devmode2->devicename)) {
1935 torture_fail(tctx, "devicename is the same");
1938 if (strequal(devmode->formname, devmode2->formname)) {
1939 torture_fail(tctx, "formname is the same");
1942 torture_assert(tctx, test_GetPrinter_level(tctx, p, &handle_devmode, 2, &info), "");
1944 devmode2 = info.info2.devmode;
1946 if (strequal(devmode->devicename, devmode2->devicename)) {
1947 torture_fail(tctx, "devicename is the same");
1950 if (strequal(devmode->formname, devmode2->formname)) {
1951 torture_fail(tctx, "formname is the same");
1954 test_ClosePrinter(tctx, p, &handle_devmode);
1957 /* set devicemode level 8 and see if it persists */
1959 devmode->copies = 93;
1960 devmode->formname = talloc_strdup(tctx, "Legal");
1962 torture_assert(tctx, test_devmode_set_level(tctx, p, handle, 8, devmode), "");
1964 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 8, &info), "");
1966 devmode2 = info.info8.devmode;
1968 torture_assert(tctx, test_devicemode_equal(tctx, devmode, devmode2), "");
1970 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 2, &info), "");
1972 devmode2 = info.info2.devmode;
1974 torture_assert(tctx, test_devicemode_equal(tctx, devmode, devmode2), "");
1977 /* set devicemode level 2 and see if it persists */
1979 devmode->copies = 39;
1980 devmode->formname = talloc_strdup(tctx, "Letter");
1982 torture_assert(tctx, test_devmode_set_level(tctx, p, handle, 8, devmode), "");
1984 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 8, &info), "");
1986 devmode2 = info.info8.devmode;
1988 torture_assert(tctx, test_devicemode_equal(tctx, devmode, devmode2), "");
1990 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 2, &info), "");
1992 devmode2 = info.info2.devmode;
1994 torture_assert(tctx, test_devicemode_equal(tctx, devmode, devmode2), "");
1997 return true;
2001 * wrapper call that saves original devmode, runs tests, and restores devmode
2004 static bool test_PrinterInfo_DevMode(struct torture_context *tctx,
2005 struct dcerpc_pipe *p,
2006 struct policy_handle *handle,
2007 const char *name)
2009 union spoolss_PrinterInfo info;
2010 struct spoolss_SetPrinterInfo8 info8;
2011 struct spoolss_SetPrinterInfoCtr info_ctr;
2012 struct spoolss_DevmodeContainer devmode_ctr;
2013 struct sec_desc_buf secdesc_ctr;
2014 struct spoolss_DeviceMode *devmode;
2015 bool ret = true;
2017 /* save original devmode */
2019 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 8, &info), "");
2021 devmode = info.info8.devmode;
2023 /* run tests */
2025 ret = test_PrinterInfo_DevModes(tctx, p, handle, name);
2027 /* restore original devmode */
2029 ZERO_STRUCT(devmode_ctr);
2030 ZERO_STRUCT(secdesc_ctr);
2032 info8.devmode_ptr = 0;
2034 info_ctr.level = 8;
2035 info_ctr.info.info8 = &info8;
2037 devmode_ctr.devmode = devmode;
2039 torture_assert(tctx,
2040 test_SetPrinter(tctx, p, handle, &info_ctr, &devmode_ctr, &secdesc_ctr, 0), "");
2042 return ret;
2045 static bool test_ClosePrinter(struct torture_context *tctx,
2046 struct dcerpc_pipe *p,
2047 struct policy_handle *handle)
2049 NTSTATUS status;
2050 struct spoolss_ClosePrinter r;
2052 r.in.handle = handle;
2053 r.out.handle = handle;
2055 torture_comment(tctx, "Testing ClosePrinter\n");
2057 status = dcerpc_spoolss_ClosePrinter(p, tctx, &r);
2058 torture_assert_ntstatus_ok(tctx, status, "ClosePrinter failed");
2059 torture_assert_werr_ok(tctx, r.out.result, "ClosePrinter failed");
2061 return true;
2064 static bool test_GetForm(struct torture_context *tctx,
2065 struct dcerpc_pipe *p,
2066 struct policy_handle *handle,
2067 const char *form_name,
2068 uint32_t level)
2070 NTSTATUS status;
2071 struct spoolss_GetForm r;
2072 uint32_t needed;
2074 r.in.handle = handle;
2075 r.in.form_name = form_name;
2076 r.in.level = level;
2077 r.in.buffer = NULL;
2078 r.in.offered = 0;
2079 r.out.needed = &needed;
2081 torture_comment(tctx, "Testing GetForm level %d\n", r.in.level);
2083 status = dcerpc_spoolss_GetForm(p, tctx, &r);
2084 torture_assert_ntstatus_ok(tctx, status, "GetForm failed");
2086 if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
2087 DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed);
2088 data_blob_clear(&blob);
2089 r.in.buffer = &blob;
2090 r.in.offered = needed;
2091 status = dcerpc_spoolss_GetForm(p, tctx, &r);
2092 torture_assert_ntstatus_ok(tctx, status, "GetForm failed");
2094 torture_assert_werr_ok(tctx, r.out.result, "GetForm failed");
2096 torture_assert(tctx, r.out.info, "No form info returned");
2099 torture_assert_werr_ok(tctx, r.out.result, "GetForm failed");
2101 CHECK_NEEDED_SIZE_LEVEL(spoolss_FormInfo, r.out.info, r.in.level, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
2103 return true;
2106 static bool test_EnumForms(struct torture_context *tctx,
2107 struct dcerpc_pipe *p,
2108 struct policy_handle *handle, bool print_server)
2110 NTSTATUS status;
2111 struct spoolss_EnumForms r;
2112 bool ret = true;
2113 uint32_t needed;
2114 uint32_t count;
2115 uint32_t levels[] = { 1, 2 };
2116 int i;
2118 for (i=0; i<ARRAY_SIZE(levels); i++) {
2120 union spoolss_FormInfo *info;
2122 r.in.handle = handle;
2123 r.in.level = levels[i];
2124 r.in.buffer = NULL;
2125 r.in.offered = 0;
2126 r.out.needed = &needed;
2127 r.out.count = &count;
2128 r.out.info = &info;
2130 torture_comment(tctx, "Testing EnumForms level %d\n", levels[i]);
2132 status = dcerpc_spoolss_EnumForms(p, tctx, &r);
2133 torture_assert_ntstatus_ok(tctx, status, "EnumForms failed");
2135 if ((r.in.level == 2) && (W_ERROR_EQUAL(r.out.result, WERR_UNKNOWN_LEVEL))) {
2136 break;
2139 if (print_server && W_ERROR_EQUAL(r.out.result, WERR_BADFID))
2140 torture_fail(tctx, "EnumForms on the PrintServer isn't supported by test server (NT4)");
2142 if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
2143 int j;
2144 DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed);
2145 data_blob_clear(&blob);
2146 r.in.buffer = &blob;
2147 r.in.offered = needed;
2149 status = dcerpc_spoolss_EnumForms(p, tctx, &r);
2151 torture_assert(tctx, info, "No forms returned");
2153 for (j = 0; j < count; j++) {
2154 if (!print_server)
2155 ret &= test_GetForm(tctx, p, handle, info[j].info1.form_name, levels[i]);
2159 torture_assert_ntstatus_ok(tctx, status, "EnumForms failed");
2161 torture_assert_werr_ok(tctx, r.out.result, "EnumForms failed");
2163 CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumForms, info, r.in.level, count, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
2166 return true;
2169 static bool test_DeleteForm(struct torture_context *tctx,
2170 struct dcerpc_pipe *p,
2171 struct policy_handle *handle,
2172 const char *form_name)
2174 NTSTATUS status;
2175 struct spoolss_DeleteForm r;
2177 r.in.handle = handle;
2178 r.in.form_name = form_name;
2180 status = dcerpc_spoolss_DeleteForm(p, tctx, &r);
2182 torture_assert_ntstatus_ok(tctx, status, "DeleteForm failed");
2184 torture_assert_werr_ok(tctx, r.out.result, "DeleteForm failed");
2186 return true;
2189 static bool test_AddForm(struct torture_context *tctx,
2190 struct dcerpc_pipe *p,
2191 struct policy_handle *handle, bool print_server)
2193 struct spoolss_AddForm r;
2194 struct spoolss_AddFormInfo1 addform;
2195 const char *form_name = "testform3";
2196 NTSTATUS status;
2197 bool ret = true;
2199 r.in.handle = handle;
2200 r.in.level = 1;
2201 r.in.info.info1 = &addform;
2202 addform.flags = SPOOLSS_FORM_USER;
2203 addform.form_name = form_name;
2204 addform.size.width = 50;
2205 addform.size.height = 25;
2206 addform.area.left = 5;
2207 addform.area.top = 10;
2208 addform.area.right = 45;
2209 addform.area.bottom = 15;
2211 status = dcerpc_spoolss_AddForm(p, tctx, &r);
2213 torture_assert_ntstatus_ok(tctx, status, "AddForm failed");
2215 torture_assert_werr_ok(tctx, r.out.result, "AddForm failed");
2217 if (!print_server) ret &= test_GetForm(tctx, p, handle, form_name, 1);
2220 struct spoolss_SetForm sf;
2221 struct spoolss_AddFormInfo1 setform;
2223 sf.in.handle = handle;
2224 sf.in.form_name = form_name;
2225 sf.in.level = 1;
2226 sf.in.info.info1= &setform;
2227 setform.flags = addform.flags;
2228 setform.form_name = addform.form_name;
2229 setform.size = addform.size;
2230 setform.area = addform.area;
2232 setform.size.width = 1234;
2234 status = dcerpc_spoolss_SetForm(p, tctx, &sf);
2236 torture_assert_ntstatus_ok(tctx, status, "SetForm failed");
2238 torture_assert_werr_ok(tctx, r.out.result, "SetForm failed");
2241 if (!print_server) ret &= test_GetForm(tctx, p, handle, form_name, 1);
2244 struct spoolss_EnumForms e;
2245 union spoolss_FormInfo *info;
2246 uint32_t needed;
2247 uint32_t count;
2248 bool found = false;
2250 e.in.handle = handle;
2251 e.in.level = 1;
2252 e.in.buffer = NULL;
2253 e.in.offered = 0;
2254 e.out.needed = &needed;
2255 e.out.count = &count;
2256 e.out.info = &info;
2258 torture_comment(tctx, "Testing EnumForms level 1\n");
2260 status = dcerpc_spoolss_EnumForms(p, tctx, &e);
2261 torture_assert_ntstatus_ok(tctx, status, "EnumForms failed");
2263 if (print_server && W_ERROR_EQUAL(e.out.result, WERR_BADFID))
2264 torture_fail(tctx, "EnumForms on the PrintServer isn't supported by test server (NT4)");
2266 if (W_ERROR_EQUAL(e.out.result, WERR_INSUFFICIENT_BUFFER)) {
2267 int j;
2268 DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed);
2269 data_blob_clear(&blob);
2270 e.in.buffer = &blob;
2271 e.in.offered = needed;
2273 status = dcerpc_spoolss_EnumForms(p, tctx, &e);
2275 torture_assert(tctx, info, "No forms returned");
2277 for (j = 0; j < count; j++) {
2278 if (strequal(form_name, info[j].info1.form_name)) {
2279 found = true;
2280 break;
2284 torture_assert(tctx, found, "Newly added form not found in enum call");
2287 if (!test_DeleteForm(tctx, p, handle, form_name)) {
2288 ret = false;
2291 return ret;
2294 static bool test_EnumPorts_old(struct torture_context *tctx,
2295 struct dcerpc_pipe *p)
2297 NTSTATUS status;
2298 struct spoolss_EnumPorts r;
2299 uint32_t needed;
2300 uint32_t count;
2301 union spoolss_PortInfo *info;
2303 r.in.servername = talloc_asprintf(tctx, "\\\\%s",
2304 dcerpc_server_name(p));
2305 r.in.level = 2;
2306 r.in.buffer = NULL;
2307 r.in.offered = 0;
2308 r.out.needed = &needed;
2309 r.out.count = &count;
2310 r.out.info = &info;
2312 torture_comment(tctx, "Testing EnumPorts\n");
2314 status = dcerpc_spoolss_EnumPorts(p, tctx, &r);
2316 torture_assert_ntstatus_ok(tctx, status, "EnumPorts failed");
2318 if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
2319 DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed);
2320 data_blob_clear(&blob);
2321 r.in.buffer = &blob;
2322 r.in.offered = needed;
2324 status = dcerpc_spoolss_EnumPorts(p, tctx, &r);
2325 torture_assert_ntstatus_ok(tctx, status, "EnumPorts failed");
2326 torture_assert_werr_ok(tctx, r.out.result, "EnumPorts failed");
2328 torture_assert(tctx, info, "No ports returned");
2331 torture_assert_werr_ok(tctx, r.out.result, "EnumPorts failed");
2333 CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumPorts, info, 2, count, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
2335 return true;
2338 static bool test_AddPort(struct torture_context *tctx,
2339 struct dcerpc_pipe *p)
2341 NTSTATUS status;
2342 struct spoolss_AddPort r;
2344 r.in.server_name = talloc_asprintf(tctx, "\\\\%s",
2345 dcerpc_server_name(p));
2346 r.in.unknown = 0;
2347 r.in.monitor_name = "foo";
2349 torture_comment(tctx, "Testing AddPort\n");
2351 status = dcerpc_spoolss_AddPort(p, tctx, &r);
2353 torture_assert_ntstatus_ok(tctx, status, "AddPort failed");
2355 /* win2k3 returns WERR_NOT_SUPPORTED */
2357 #if 0
2359 if (!W_ERROR_IS_OK(r.out.result)) {
2360 printf("AddPort failed - %s\n", win_errstr(r.out.result));
2361 return false;
2364 #endif
2366 return true;
2369 static bool test_GetJob(struct torture_context *tctx,
2370 struct dcerpc_pipe *p,
2371 struct policy_handle *handle, uint32_t job_id)
2373 NTSTATUS status;
2374 struct spoolss_GetJob r;
2375 union spoolss_JobInfo info;
2376 uint32_t needed;
2377 uint32_t levels[] = {1, 2 /* 3, 4 */};
2378 uint32_t i;
2380 r.in.handle = handle;
2381 r.in.job_id = job_id;
2382 r.in.level = 0;
2383 r.in.buffer = NULL;
2384 r.in.offered = 0;
2385 r.out.needed = &needed;
2386 r.out.info = &info;
2388 torture_comment(tctx, "Testing GetJob level %d\n", r.in.level);
2390 status = dcerpc_spoolss_GetJob(p, tctx, &r);
2391 torture_assert_werr_equal(tctx, r.out.result, WERR_UNKNOWN_LEVEL, "Unexpected return code");
2393 for (i = 0; i < ARRAY_SIZE(levels); i++) {
2395 torture_comment(tctx, "Testing GetJob level %d\n", r.in.level);
2397 needed = 0;
2399 r.in.level = levels[i];
2400 r.in.offered = 0;
2401 r.in.buffer = NULL;
2403 status = dcerpc_spoolss_GetJob(p, tctx, &r);
2404 torture_assert_ntstatus_ok(tctx, status, "GetJob failed");
2406 if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
2407 DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed);
2408 data_blob_clear(&blob);
2409 r.in.buffer = &blob;
2410 r.in.offered = needed;
2412 status = dcerpc_spoolss_GetJob(p, tctx, &r);
2413 torture_assert_ntstatus_ok(tctx, status, "GetJob failed");
2416 torture_assert(tctx, r.out.info, "No job info returned");
2417 torture_assert_werr_ok(tctx, r.out.result, "GetJob failed");
2419 CHECK_NEEDED_SIZE_LEVEL(spoolss_JobInfo, r.out.info, r.in.level, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
2422 return true;
2425 static bool test_SetJob(struct torture_context *tctx,
2426 struct dcerpc_pipe *p,
2427 struct policy_handle *handle, uint32_t job_id,
2428 enum spoolss_JobControl command)
2430 NTSTATUS status;
2431 struct spoolss_SetJob r;
2433 r.in.handle = handle;
2434 r.in.job_id = job_id;
2435 r.in.ctr = NULL;
2436 r.in.command = command;
2438 switch (command) {
2439 case SPOOLSS_JOB_CONTROL_PAUSE:
2440 torture_comment(tctx, "Testing SetJob: SPOOLSS_JOB_CONTROL_PAUSE\n");
2441 break;
2442 case SPOOLSS_JOB_CONTROL_RESUME:
2443 torture_comment(tctx, "Testing SetJob: SPOOLSS_JOB_CONTROL_RESUME\n");
2444 break;
2445 case SPOOLSS_JOB_CONTROL_CANCEL:
2446 torture_comment(tctx, "Testing SetJob: SPOOLSS_JOB_CONTROL_CANCEL\n");
2447 break;
2448 case SPOOLSS_JOB_CONTROL_RESTART:
2449 torture_comment(tctx, "Testing SetJob: SPOOLSS_JOB_CONTROL_RESTART\n");
2450 break;
2451 case SPOOLSS_JOB_CONTROL_DELETE:
2452 torture_comment(tctx, "Testing SetJob: SPOOLSS_JOB_CONTROL_DELETE\n");
2453 break;
2454 case SPOOLSS_JOB_CONTROL_SEND_TO_PRINTER:
2455 torture_comment(tctx, "Testing SetJob: SPOOLSS_JOB_CONTROL_SEND_TO_PRINTER\n");
2456 break;
2457 case SPOOLSS_JOB_CONTROL_LAST_PAGE_EJECTED:
2458 torture_comment(tctx, "Testing SetJob: SPOOLSS_JOB_CONTROL_LAST_PAGE_EJECTED\n");
2459 break;
2460 case SPOOLSS_JOB_CONTROL_RETAIN:
2461 torture_comment(tctx, "Testing SetJob: SPOOLSS_JOB_CONTROL_RETAIN\n");
2462 break;
2463 case SPOOLSS_JOB_CONTROL_RELEASE:
2464 torture_comment(tctx, "Testing SetJob: SPOOLSS_JOB_CONTROL_RELEASE\n");
2465 break;
2466 default:
2467 torture_comment(tctx, "Testing SetJob\n");
2468 break;
2471 status = dcerpc_spoolss_SetJob(p, tctx, &r);
2472 torture_assert_ntstatus_ok(tctx, status, "SetJob failed");
2473 torture_assert_werr_ok(tctx, r.out.result, "SetJob failed");
2475 return true;
2478 static bool test_AddJob(struct torture_context *tctx,
2479 struct dcerpc_pipe *p,
2480 struct policy_handle *handle)
2482 NTSTATUS status;
2483 struct spoolss_AddJob r;
2484 uint32_t needed;
2486 r.in.level = 0;
2487 r.in.handle = handle;
2488 r.in.offered = 0;
2489 r.out.needed = &needed;
2490 r.in.buffer = r.out.buffer = NULL;
2492 torture_comment(tctx, "Testing AddJob\n");
2494 status = dcerpc_spoolss_AddJob(p, tctx, &r);
2495 torture_assert_werr_equal(tctx, r.out.result, WERR_UNKNOWN_LEVEL, "AddJob failed");
2497 r.in.level = 1;
2499 status = dcerpc_spoolss_AddJob(p, tctx, &r);
2500 torture_assert_werr_equal(tctx, r.out.result, WERR_INVALID_PARAM, "AddJob failed");
2502 return true;
2506 static bool test_EnumJobs(struct torture_context *tctx,
2507 struct dcerpc_pipe *p,
2508 struct policy_handle *handle)
2510 NTSTATUS status;
2511 struct spoolss_EnumJobs r;
2512 uint32_t needed;
2513 uint32_t count;
2514 union spoolss_JobInfo *info;
2516 r.in.handle = handle;
2517 r.in.firstjob = 0;
2518 r.in.numjobs = 0xffffffff;
2519 r.in.level = 1;
2520 r.in.buffer = NULL;
2521 r.in.offered = 0;
2522 r.out.needed = &needed;
2523 r.out.count = &count;
2524 r.out.info = &info;
2526 torture_comment(tctx, "Testing EnumJobs\n");
2528 status = dcerpc_spoolss_EnumJobs(p, tctx, &r);
2530 torture_assert_ntstatus_ok(tctx, status, "EnumJobs failed");
2532 if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
2533 int j;
2534 DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed);
2535 data_blob_clear(&blob);
2536 r.in.buffer = &blob;
2537 r.in.offered = needed;
2539 status = dcerpc_spoolss_EnumJobs(p, tctx, &r);
2541 torture_assert_ntstatus_ok(tctx, status, "EnumJobs failed");
2542 torture_assert_werr_ok(tctx, r.out.result, "EnumJobs failed");
2543 torture_assert(tctx, info, "No jobs returned");
2545 CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumJobs, *r.out.info, r.in.level, count, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
2547 for (j = 0; j < count; j++) {
2549 torture_assert(tctx, test_GetJob(tctx, p, handle, info[j].info1.job_id),
2550 "failed to call test_GetJob");
2552 /* FIXME - gd */
2553 if (!torture_setting_bool(tctx, "samba3", false)) {
2554 test_SetJob(tctx, p, handle, info[j].info1.job_id, SPOOLSS_JOB_CONTROL_PAUSE);
2555 test_SetJob(tctx, p, handle, info[j].info1.job_id, SPOOLSS_JOB_CONTROL_RESUME);
2559 } else {
2560 torture_assert_werr_ok(tctx, r.out.result, "EnumJobs failed");
2563 return true;
2566 static bool test_DoPrintTest(struct torture_context *tctx,
2567 struct dcerpc_pipe *p,
2568 struct policy_handle *handle)
2570 bool ret = true;
2571 NTSTATUS status;
2572 struct spoolss_StartDocPrinter s;
2573 struct spoolss_DocumentInfo1 info1;
2574 struct spoolss_StartPagePrinter sp;
2575 struct spoolss_WritePrinter w;
2576 struct spoolss_EndPagePrinter ep;
2577 struct spoolss_EndDocPrinter e;
2578 int i;
2579 uint32_t job_id;
2580 uint32_t num_written;
2582 torture_comment(tctx, "Testing StartDocPrinter\n");
2584 s.in.handle = handle;
2585 s.in.level = 1;
2586 s.in.info.info1 = &info1;
2587 s.out.job_id = &job_id;
2588 info1.document_name = "TorturePrintJob";
2589 info1.output_file = NULL;
2590 info1.datatype = "RAW";
2592 status = dcerpc_spoolss_StartDocPrinter(p, tctx, &s);
2593 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_StartDocPrinter failed");
2594 torture_assert_werr_ok(tctx, s.out.result, "StartDocPrinter failed");
2596 for (i=1; i < 4; i++) {
2597 torture_comment(tctx, "Testing StartPagePrinter: Page[%d]\n", i);
2599 sp.in.handle = handle;
2601 status = dcerpc_spoolss_StartPagePrinter(p, tctx, &sp);
2602 torture_assert_ntstatus_ok(tctx, status,
2603 "dcerpc_spoolss_StartPagePrinter failed");
2604 torture_assert_werr_ok(tctx, sp.out.result, "StartPagePrinter failed");
2606 torture_comment(tctx, "Testing WritePrinter: Page[%d]\n", i);
2608 w.in.handle = handle;
2609 w.in.data = data_blob_string_const(talloc_asprintf(tctx,"TortureTestPage: %d\nData\n",i));
2610 w.out.num_written = &num_written;
2612 status = dcerpc_spoolss_WritePrinter(p, tctx, &w);
2613 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_WritePrinter failed");
2614 torture_assert_werr_ok(tctx, w.out.result, "WritePrinter failed");
2616 torture_comment(tctx, "Testing EndPagePrinter: Page[%d]\n", i);
2618 ep.in.handle = handle;
2620 status = dcerpc_spoolss_EndPagePrinter(p, tctx, &ep);
2621 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EndPagePrinter failed");
2622 torture_assert_werr_ok(tctx, ep.out.result, "EndPagePrinter failed");
2625 torture_comment(tctx, "Testing EndDocPrinter\n");
2627 e.in.handle = handle;
2629 status = dcerpc_spoolss_EndDocPrinter(p, tctx, &e);
2630 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EndDocPrinter failed");
2631 torture_assert_werr_ok(tctx, e.out.result, "EndDocPrinter failed");
2633 ret &= test_AddJob(tctx, p, handle);
2634 ret &= test_EnumJobs(tctx, p, handle);
2636 ret &= test_SetJob(tctx, p, handle, job_id, SPOOLSS_JOB_CONTROL_DELETE);
2638 return ret;
2641 static bool test_PausePrinter(struct torture_context *tctx,
2642 struct dcerpc_pipe *p,
2643 struct policy_handle *handle)
2645 NTSTATUS status;
2646 struct spoolss_SetPrinter r;
2647 struct spoolss_SetPrinterInfoCtr info_ctr;
2648 struct spoolss_DevmodeContainer devmode_ctr;
2649 struct sec_desc_buf secdesc_ctr;
2651 info_ctr.level = 0;
2652 info_ctr.info.info0 = NULL;
2654 ZERO_STRUCT(devmode_ctr);
2655 ZERO_STRUCT(secdesc_ctr);
2657 r.in.handle = handle;
2658 r.in.info_ctr = &info_ctr;
2659 r.in.devmode_ctr = &devmode_ctr;
2660 r.in.secdesc_ctr = &secdesc_ctr;
2661 r.in.command = SPOOLSS_PRINTER_CONTROL_PAUSE;
2663 torture_comment(tctx, "Testing SetPrinter: SPOOLSS_PRINTER_CONTROL_PAUSE\n");
2665 status = dcerpc_spoolss_SetPrinter(p, tctx, &r);
2667 torture_assert_ntstatus_ok(tctx, status, "SetPrinter failed");
2669 torture_assert_werr_ok(tctx, r.out.result, "SetPrinter failed");
2671 return true;
2674 static bool test_ResumePrinter(struct torture_context *tctx,
2675 struct dcerpc_pipe *p,
2676 struct policy_handle *handle)
2678 NTSTATUS status;
2679 struct spoolss_SetPrinter r;
2680 struct spoolss_SetPrinterInfoCtr info_ctr;
2681 struct spoolss_DevmodeContainer devmode_ctr;
2682 struct sec_desc_buf secdesc_ctr;
2684 info_ctr.level = 0;
2685 info_ctr.info.info0 = NULL;
2687 ZERO_STRUCT(devmode_ctr);
2688 ZERO_STRUCT(secdesc_ctr);
2690 r.in.handle = handle;
2691 r.in.info_ctr = &info_ctr;
2692 r.in.devmode_ctr = &devmode_ctr;
2693 r.in.secdesc_ctr = &secdesc_ctr;
2694 r.in.command = SPOOLSS_PRINTER_CONTROL_RESUME;
2696 torture_comment(tctx, "Testing SetPrinter: SPOOLSS_PRINTER_CONTROL_RESUME\n");
2698 status = dcerpc_spoolss_SetPrinter(p, tctx, &r);
2700 torture_assert_ntstatus_ok(tctx, status, "SetPrinter failed");
2702 torture_assert_werr_ok(tctx, r.out.result, "SetPrinter failed");
2704 return true;
2707 static bool test_GetPrinterData(struct torture_context *tctx,
2708 struct dcerpc_pipe *p,
2709 struct policy_handle *handle,
2710 const char *value_name,
2711 enum winreg_Type *type_p,
2712 union spoolss_PrinterData *data_p)
2714 NTSTATUS status;
2715 struct spoolss_GetPrinterData r;
2716 uint32_t needed;
2717 enum winreg_Type type;
2718 union spoolss_PrinterData data;
2720 r.in.handle = handle;
2721 r.in.value_name = value_name;
2722 r.in.offered = 0;
2723 r.out.needed = &needed;
2724 r.out.type = &type;
2725 r.out.data = &data;
2727 torture_comment(tctx, "Testing GetPrinterData(%s)\n", r.in.value_name);
2729 status = dcerpc_spoolss_GetPrinterData(p, tctx, &r);
2730 torture_assert_ntstatus_ok(tctx, status, "GetPrinterData failed");
2732 if (W_ERROR_EQUAL(r.out.result, WERR_MORE_DATA)) {
2733 r.in.offered = needed;
2735 status = dcerpc_spoolss_GetPrinterData(p, tctx, &r);
2736 torture_assert_ntstatus_ok(tctx, status, "GetPrinterData failed");
2739 torture_assert_werr_ok(tctx, r.out.result,
2740 talloc_asprintf(tctx, "GetPrinterData(%s) failed", r.in.value_name));
2742 CHECK_NEEDED_SIZE_LEVEL(spoolss_PrinterData, &data, type, lp_iconv_convenience(tctx->lp_ctx), needed, 1);
2744 if (type_p) {
2745 *type_p = type;
2748 if (data_p) {
2749 *data_p = data;
2752 return true;
2755 static bool test_GetPrinterDataEx(struct torture_context *tctx,
2756 struct dcerpc_pipe *p,
2757 struct policy_handle *handle,
2758 const char *key_name,
2759 const char *value_name,
2760 enum winreg_Type *type_p,
2761 union spoolss_PrinterData *data_p)
2763 NTSTATUS status;
2764 struct spoolss_GetPrinterDataEx r;
2765 enum winreg_Type type;
2766 uint32_t needed;
2767 union spoolss_PrinterData data;
2769 r.in.handle = handle;
2770 r.in.key_name = key_name;
2771 r.in.value_name = value_name;
2772 r.in.offered = 0;
2773 r.out.type = &type;
2774 r.out.needed = &needed;
2775 r.out.data = &data;
2777 torture_comment(tctx, "Testing GetPrinterDataEx(%s - %s)\n",
2778 r.in.key_name, r.in.value_name);
2780 status = dcerpc_spoolss_GetPrinterDataEx(p, tctx, &r);
2781 if (!NT_STATUS_IS_OK(status)) {
2782 if (NT_STATUS_EQUAL(status,NT_STATUS_NET_WRITE_FAULT) &&
2783 p->last_fault_code == DCERPC_FAULT_OP_RNG_ERROR) {
2784 torture_skip(tctx, "GetPrinterDataEx not supported by server\n");
2786 torture_assert_ntstatus_ok(tctx, status, "GetPrinterDataEx failed");
2789 if (W_ERROR_EQUAL(r.out.result, WERR_MORE_DATA)) {
2790 r.in.offered = needed;
2791 status = dcerpc_spoolss_GetPrinterDataEx(p, tctx, &r);
2792 torture_assert_ntstatus_ok(tctx, status, "GetPrinterDataEx failed");
2795 torture_assert_werr_ok(tctx, r.out.result,
2796 talloc_asprintf(tctx, "GetPrinterDataEx(%s - %s) failed", r.in.key_name, r.in.value_name));
2798 CHECK_NEEDED_SIZE_LEVEL(spoolss_PrinterData, &data, type, lp_iconv_convenience(tctx->lp_ctx), needed, 1);
2800 if (type_p) {
2801 *type_p = type;
2804 if (data_p) {
2805 *data_p = data;
2808 return true;
2811 static bool test_GetPrinterData_list(struct torture_context *tctx,
2812 struct dcerpc_pipe *p,
2813 struct policy_handle *handle)
2815 const char *list[] = {
2816 "W3SvcInstalled",
2817 "BeepEnabled",
2818 "EventLog",
2819 /* "NetPopup", not on w2k8 */
2820 /* "NetPopupToComputer", not on w2k8 */
2821 "MajorVersion",
2822 "MinorVersion",
2823 "DefaultSpoolDirectory",
2824 "Architecture",
2825 "DsPresent",
2826 "OSVersion",
2827 /* "OSVersionEx", not on s3 */
2828 "DNSMachineName"
2830 int i;
2832 for (i=0; i < ARRAY_SIZE(list); i++) {
2833 enum winreg_Type type, type_ex;
2834 union spoolss_PrinterData data, data_ex;
2836 torture_assert(tctx, test_GetPrinterData(tctx, p, handle, list[i], &type, &data),
2837 talloc_asprintf(tctx, "GetPrinterData failed on %s\n", list[i]));
2838 torture_assert(tctx, test_GetPrinterDataEx(tctx, p, handle, "random_string", list[i], &type_ex, &data_ex),
2839 talloc_asprintf(tctx, "GetPrinterDataEx failed on %s\n", list[i]));
2840 torture_assert_int_equal(tctx, type, type_ex, "type mismatch");
2841 switch (type) {
2842 case REG_SZ:
2843 torture_assert_str_equal(tctx, data.string, data_ex.string, "REG_SZ mismatch");
2844 break;
2845 case REG_DWORD:
2846 torture_assert_int_equal(tctx, data.value, data_ex.value, "REG_DWORD mismatch");
2847 break;
2848 case REG_BINARY:
2849 torture_assert_data_blob_equal(tctx, data.binary, data_ex.binary, "REG_BINARY mismatch");
2850 break;
2851 default:
2852 break;
2856 return true;
2859 static bool test_EnumPrinterData(struct torture_context *tctx, struct dcerpc_pipe *p,
2860 struct policy_handle *handle)
2862 NTSTATUS status;
2863 struct spoolss_EnumPrinterData r;
2865 ZERO_STRUCT(r);
2866 r.in.handle = handle;
2867 r.in.enum_index = 0;
2869 do {
2870 uint32_t value_size = 0;
2871 uint32_t data_size = 0;
2872 enum winreg_Type type = 0;
2874 r.in.value_offered = value_size;
2875 r.out.value_needed = &value_size;
2876 r.in.data_offered = data_size;
2877 r.out.data_needed = &data_size;
2879 r.out.type = &type;
2880 r.out.data = talloc_zero_array(tctx, uint8_t, 0);
2882 torture_comment(tctx, "Testing EnumPrinterData\n");
2884 status = dcerpc_spoolss_EnumPrinterData(p, tctx, &r);
2886 torture_assert_ntstatus_ok(tctx, status, "EnumPrinterData failed");
2887 if (W_ERROR_EQUAL(r.out.result, WERR_NO_MORE_ITEMS)) {
2888 break;
2890 torture_assert_werr_ok(tctx, r.out.result, "EnumPrinterData");
2892 r.in.value_offered = value_size;
2893 r.out.value_name = talloc_zero_array(tctx, const char, value_size);
2894 r.in.data_offered = data_size;
2895 r.out.data = talloc_zero_array(tctx, uint8_t, data_size);
2897 status = dcerpc_spoolss_EnumPrinterData(p, tctx, &r);
2899 torture_assert_ntstatus_ok(tctx, status, "EnumPrinterData failed");
2900 if (W_ERROR_EQUAL(r.out.result, WERR_NO_MORE_ITEMS)) {
2901 break;
2904 torture_assert_werr_ok(tctx, r.out.result, "EnumPrinterData failed");
2906 torture_assert(tctx, test_GetPrinterData(tctx, p, handle, r.out.value_name, NULL, NULL),
2907 talloc_asprintf(tctx, "failed to call GetPrinterData for %s\n", r.out.value_name));
2909 torture_assert(tctx, test_GetPrinterDataEx(tctx, p, handle, "PrinterDriverData", r.out.value_name, NULL, NULL),
2910 talloc_asprintf(tctx, "failed to call GetPrinterDataEx on PrinterDriverData for %s\n", r.out.value_name));
2912 r.in.enum_index++;
2914 } while (W_ERROR_IS_OK(r.out.result));
2916 return true;
2919 static bool test_EnumPrinterDataEx(struct torture_context *tctx,
2920 struct dcerpc_pipe *p,
2921 struct policy_handle *handle,
2922 const char *key_name)
2924 struct spoolss_EnumPrinterDataEx r;
2925 struct spoolss_PrinterEnumValues *info;
2926 uint32_t needed;
2927 uint32_t count;
2929 r.in.handle = handle;
2930 r.in.key_name = key_name;
2931 r.in.offered = 0;
2932 r.out.needed = &needed;
2933 r.out.count = &count;
2934 r.out.info = &info;
2936 torture_comment(tctx, "Testing EnumPrinterDataEx(%s)\n", key_name);
2938 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_EnumPrinterDataEx(p, tctx, &r),
2939 "EnumPrinterDataEx failed");
2940 if (W_ERROR_EQUAL(r.out.result, WERR_MORE_DATA)) {
2941 r.in.offered = needed;
2942 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_EnumPrinterDataEx(p, tctx, &r),
2943 "EnumPrinterDataEx failed");
2946 torture_assert_werr_ok(tctx, r.out.result, "EnumPrinterDataEx failed");
2948 CHECK_NEEDED_SIZE_ENUM(spoolss_EnumPrinterDataEx, info, count, lp_iconv_convenience(tctx->lp_ctx), needed, 1);
2950 return true;
2954 static bool test_DeletePrinterData(struct torture_context *tctx,
2955 struct dcerpc_pipe *p,
2956 struct policy_handle *handle,
2957 const char *value_name)
2959 NTSTATUS status;
2960 struct spoolss_DeletePrinterData r;
2962 r.in.handle = handle;
2963 r.in.value_name = value_name;
2965 torture_comment(tctx, "Testing DeletePrinterData(%s)\n",
2966 r.in.value_name);
2968 status = dcerpc_spoolss_DeletePrinterData(p, tctx, &r);
2970 torture_assert_ntstatus_ok(tctx, status, "DeletePrinterData failed");
2971 torture_assert_werr_ok(tctx, r.out.result, "DeletePrinterData failed");
2973 return true;
2976 static bool test_DeletePrinterDataEx(struct torture_context *tctx,
2977 struct dcerpc_pipe *p,
2978 struct policy_handle *handle,
2979 const char *key_name,
2980 const char *value_name)
2982 struct spoolss_DeletePrinterDataEx r;
2984 r.in.handle = handle;
2985 r.in.key_name = key_name;
2986 r.in.value_name = value_name;
2988 torture_comment(tctx, "Testing DeletePrinterDataEx(%s - %s)\n",
2989 r.in.key_name, r.in.value_name);
2991 torture_assert_ntstatus_ok(tctx,
2992 dcerpc_spoolss_DeletePrinterDataEx(p, tctx, &r),
2993 "DeletePrinterDataEx failed");
2994 torture_assert_werr_ok(tctx, r.out.result,
2995 "DeletePrinterDataEx failed");
2997 return true;
3000 static bool test_DeletePrinterKey(struct torture_context *tctx,
3001 struct dcerpc_pipe *p,
3002 struct policy_handle *handle,
3003 const char *key_name)
3005 struct spoolss_DeletePrinterKey r;
3007 r.in.handle = handle;
3008 r.in.key_name = key_name;
3010 torture_comment(tctx, "Testing DeletePrinterKey(%s)\n", r.in.key_name);
3012 if (strequal(key_name, "") && !torture_setting_bool(tctx, "dangerous", false)) {
3013 torture_skip(tctx, "not wiping out printer registry - enable dangerous tests to use\n");
3014 return true;
3017 torture_assert_ntstatus_ok(tctx,
3018 dcerpc_spoolss_DeletePrinterKey(p, tctx, &r),
3019 "DeletePrinterKey failed");
3020 torture_assert_werr_ok(tctx, r.out.result,
3021 "DeletePrinterKey failed");
3023 return true;
3026 static bool test_SetPrinterData(struct torture_context *tctx,
3027 struct dcerpc_pipe *p,
3028 struct policy_handle *handle)
3030 NTSTATUS status;
3031 struct spoolss_SetPrinterData r;
3032 const char *values[] = {
3033 "spootyfoot",
3034 "spooty\\foot",
3035 #if 0
3036 /* FIXME: not working with s3 atm. */
3037 "spooty,foot",
3038 "spooty,fo,ot",
3039 #endif
3040 "spooty foot",
3041 #if 0
3042 /* FIXME: not working with s3 atm. */
3043 "spooty\\fo,ot",
3044 "spooty,fo\\ot"
3045 #endif
3047 int i;
3049 for (i=0; i < ARRAY_SIZE(values); i++) {
3051 enum winreg_Type type;
3052 union spoolss_PrinterData data;
3054 r.in.handle = handle;
3055 r.in.value_name = values[i];
3056 r.in.type = REG_SZ;
3057 r.in.data.string = "dog";
3059 torture_comment(tctx, "Testing SetPrinterData(%s)\n",
3060 r.in.value_name);
3062 status = dcerpc_spoolss_SetPrinterData(p, tctx, &r);
3064 torture_assert_ntstatus_ok(tctx, status, "SetPrinterData failed");
3065 torture_assert_werr_ok(tctx, r.out.result, "SetPrinterData failed");
3067 if (!test_GetPrinterData(tctx, p, handle, r.in.value_name, &type, &data)) {
3068 return false;
3071 torture_assert_int_equal(tctx, r.in.type, type, "type mismatch");
3072 torture_assert_str_equal(tctx, r.in.data.string, data.string, "data mismatch");
3074 if (!test_DeletePrinterData(tctx, p, handle, r.in.value_name)) {
3075 return false;
3079 return true;
3082 static bool test_EnumPrinterKey(struct torture_context *tctx,
3083 struct dcerpc_pipe *p,
3084 struct policy_handle *handle,
3085 const char *key_name,
3086 const char ***array);
3088 static bool test_SetPrinterDataEx(struct torture_context *tctx,
3089 struct dcerpc_pipe *p,
3090 struct policy_handle *handle)
3092 NTSTATUS status;
3093 struct spoolss_SetPrinterDataEx r;
3094 const char *value_name = "dog";
3095 const char *keys[] = {
3096 "torturedataex",
3097 "torture data ex",
3098 #if 0
3099 /* FIXME: not working with s3 atm. */
3100 "torturedataex_with_subkey\\subkey",
3101 "torturedataex_with_subkey\\subkey:0",
3102 "torturedataex_with_subkey\\subkey:1",
3103 "torturedataex_with_subkey\\subkey\\subsubkey",
3104 "torturedataex_with_subkey\\subkey\\subsubkey:0",
3105 "torturedataex_with_subkey\\subkey\\subsubkey:1",
3106 #endif
3107 "torture,data",
3108 #if 0
3109 /* FIXME: not working with s3 atm. */
3111 "torture,data,ex",
3112 "torture,data\\ex",
3113 "torture\\data,ex"
3114 #endif
3116 int i;
3117 DATA_BLOB blob = data_blob_string_const("catfoobar");
3120 for (i=0; i < ARRAY_SIZE(keys); i++) {
3122 char *c;
3123 const char *key;
3124 enum winreg_Type type;
3125 const char **subkeys;
3126 union spoolss_PrinterData data;
3128 r.in.handle = handle;
3129 r.in.key_name = keys[i];
3130 r.in.value_name = value_name;
3131 r.in.type = REG_BINARY;
3132 r.in.data.binary = blob;
3134 torture_comment(tctx, "Testing SetPrinterDataEx(%s - %s)\n", r.in.key_name, value_name);
3136 status = dcerpc_spoolss_SetPrinterDataEx(p, tctx, &r);
3138 torture_assert_ntstatus_ok(tctx, status, "SetPrinterDataEx failed");
3139 torture_assert_werr_ok(tctx, r.out.result, "SetPrinterDataEx failed");
3141 key = talloc_strdup(tctx, r.in.key_name);
3143 if (!test_GetPrinterDataEx(tctx, p, handle, r.in.key_name, value_name, &type, &data)) {
3144 return false;
3147 torture_assert_int_equal(tctx, r.in.type, type, "type mismatch");
3148 torture_assert_data_blob_equal(tctx, blob, data.binary, "data mismatch");
3150 if (!test_EnumPrinterDataEx(tctx, p, handle, r.in.key_name)) {
3151 return false;
3154 if (!test_DeletePrinterDataEx(tctx, p, handle, r.in.key_name, value_name)) {
3155 return false;
3158 c = strchr(key, '\\');
3159 if (c) {
3160 int i;
3162 /* we have subkeys */
3164 *c = 0;
3166 if (!test_EnumPrinterKey(tctx, p, handle, key, &subkeys)) {
3167 return false;
3170 for (i=0; subkeys && subkeys[i]; i++) {
3172 const char *current_key = talloc_asprintf(tctx, "%s\\%s", key, subkeys[i]);
3174 if (!test_DeletePrinterKey(tctx, p, handle, current_key)) {
3175 return false;
3179 if (!test_DeletePrinterKey(tctx, p, handle, key)) {
3180 return false;
3183 } else {
3184 if (!test_DeletePrinterKey(tctx, p, handle, key)) {
3185 return false;
3190 return true;
3193 static bool test_GetChangeID_PrinterData(struct torture_context *tctx,
3194 struct dcerpc_pipe *p,
3195 struct policy_handle *handle,
3196 uint32_t *change_id)
3198 enum winreg_Type type;
3199 union spoolss_PrinterData data;
3201 torture_assert(tctx,
3202 test_GetPrinterData(tctx, p, handle, "ChangeID", &type, &data),
3203 "failed to call GetPrinterData");
3205 torture_assert(tctx, type == REG_DWORD, "unexpected type");
3207 *change_id = data.value;
3209 return true;
3212 static bool test_GetChangeID_PrinterDataEx(struct torture_context *tctx,
3213 struct dcerpc_pipe *p,
3214 struct policy_handle *handle,
3215 uint32_t *change_id)
3217 enum winreg_Type type;
3218 union spoolss_PrinterData data;
3220 torture_assert(tctx,
3221 test_GetPrinterDataEx(tctx, p, handle, "PrinterDriverData", "ChangeID", &type, &data),
3222 "failed to call GetPrinterData");
3224 torture_assert(tctx, type == REG_DWORD, "unexpected type");
3226 *change_id = data.value;
3228 return true;
3231 static bool test_GetChangeID_PrinterInfo(struct torture_context *tctx,
3232 struct dcerpc_pipe *p,
3233 struct policy_handle *handle,
3234 uint32_t *change_id)
3236 union spoolss_PrinterInfo info;
3238 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 0, &info),
3239 "failed to query Printer level 0");
3241 *change_id = info.info0.change_id;
3243 return true;
3246 static bool test_ChangeID(struct torture_context *tctx,
3247 struct dcerpc_pipe *p,
3248 struct policy_handle *handle)
3250 uint32_t change_id, change_id_ex, change_id_info;
3251 uint32_t change_id2, change_id_ex2, change_id_info2;
3252 union spoolss_PrinterInfo info;
3253 const char *comment;
3256 torture_comment(tctx, "Testing ChangeID: id change test #1\n");
3258 torture_assert(tctx, test_GetChangeID_PrinterData(tctx, p, handle, &change_id),
3259 "failed to query for ChangeID");
3260 torture_assert(tctx, test_GetChangeID_PrinterDataEx(tctx, p, handle, &change_id_ex),
3261 "failed to query for ChangeID");
3262 torture_assert(tctx, test_GetChangeID_PrinterInfo(tctx, p, handle, &change_id_info),
3263 "failed to query for ChangeID");
3265 torture_assert_int_equal(tctx, change_id, change_id_ex,
3266 "change_ids should all be equal");
3267 torture_assert_int_equal(tctx, change_id_ex, change_id_info,
3268 "change_ids should all be equal");
3271 torture_comment(tctx, "Testing ChangeID: id change test #2\n");
3273 torture_assert(tctx, test_GetChangeID_PrinterData(tctx, p, handle, &change_id),
3274 "failed to query for ChangeID");
3275 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 2, &info),
3276 "failed to query Printer level 2");
3277 torture_assert(tctx, test_GetChangeID_PrinterDataEx(tctx, p, handle, &change_id_ex),
3278 "failed to query for ChangeID");
3279 torture_assert(tctx, test_GetChangeID_PrinterInfo(tctx, p, handle, &change_id_info),
3280 "failed to query for ChangeID");
3281 torture_assert_int_equal(tctx, change_id, change_id_ex,
3282 "change_id should not have changed");
3283 torture_assert_int_equal(tctx, change_id_ex, change_id_info,
3284 "change_id should not have changed");
3287 torture_comment(tctx, "Testing ChangeID: id change test #3\n");
3289 torture_assert(tctx, test_GetChangeID_PrinterData(tctx, p, handle, &change_id),
3290 "failed to query for ChangeID");
3291 torture_assert(tctx, test_GetChangeID_PrinterDataEx(tctx, p, handle, &change_id_ex),
3292 "failed to query for ChangeID");
3293 torture_assert(tctx, test_GetChangeID_PrinterInfo(tctx, p, handle, &change_id_info),
3294 "failed to query for ChangeID");
3295 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 2, &info),
3296 "failed to query Printer level 2");
3297 comment = talloc_strdup(tctx, info.info2.comment);
3300 struct spoolss_SetPrinterInfoCtr info_ctr;
3301 struct spoolss_DevmodeContainer devmode_ctr;
3302 struct sec_desc_buf secdesc_ctr;
3303 struct spoolss_SetPrinterInfo2 info2;
3305 ZERO_STRUCT(info_ctr);
3306 ZERO_STRUCT(devmode_ctr);
3307 ZERO_STRUCT(secdesc_ctr);
3309 info2.servername = info.info2.servername;
3310 info2.printername = info.info2.printername;
3311 info2.sharename = info.info2.sharename;
3312 info2.portname = info.info2.portname;
3313 info2.drivername = info.info2.drivername;
3314 info2.comment = "torture_comment";
3315 info2.location = info.info2.location;
3316 info2.devmode_ptr = 0;
3317 info2.sepfile = info.info2.sepfile;
3318 info2.printprocessor = info.info2.printprocessor;
3319 info2.datatype = info.info2.datatype;
3320 info2.parameters = info.info2.parameters;
3321 info2.secdesc_ptr = 0;
3322 info2.attributes = info.info2.attributes;
3323 info2.priority = info.info2.priority;
3324 info2.defaultpriority = info.info2.defaultpriority;
3325 info2.starttime = info.info2.starttime;
3326 info2.untiltime = info.info2.untiltime;
3327 info2.status = info.info2.status;
3328 info2.cjobs = info.info2.cjobs;
3329 info2.averageppm = info.info2.averageppm;
3331 info_ctr.level = 2;
3332 info_ctr.info.info2 = &info2;
3334 torture_assert(tctx, test_SetPrinter(tctx, p, handle, &info_ctr, &devmode_ctr, &secdesc_ctr, 0),
3335 "failed to call SetPrinter");
3337 info2.comment = comment;
3339 torture_assert(tctx, test_SetPrinter(tctx, p, handle, &info_ctr, &devmode_ctr, &secdesc_ctr, 0),
3340 "failed to call SetPrinter");
3344 torture_assert(tctx, test_GetChangeID_PrinterData(tctx, p, handle, &change_id2),
3345 "failed to query for ChangeID");
3346 torture_assert(tctx, test_GetChangeID_PrinterDataEx(tctx, p, handle, &change_id_ex2),
3347 "failed to query for ChangeID");
3348 torture_assert(tctx, test_GetChangeID_PrinterInfo(tctx, p, handle, &change_id_info2),
3349 "failed to query for ChangeID");
3351 torture_assert_int_equal(tctx, change_id2, change_id_ex2,
3352 "change_ids should all be equal");
3353 torture_assert_int_equal(tctx, change_id_ex2, change_id_info2,
3354 "change_ids should all be equal");
3356 torture_assert(tctx, (change_id < change_id2),
3357 talloc_asprintf(tctx, "change_id %d needs to be larger than change_id %d",
3358 change_id2, change_id));
3359 torture_assert(tctx, (change_id_ex < change_id_ex2),
3360 talloc_asprintf(tctx, "change_id %d needs to be larger than change_id %d",
3361 change_id_ex2, change_id_ex));
3362 torture_assert(tctx, (change_id_info < change_id_info2),
3363 talloc_asprintf(tctx, "change_id %d needs to be larger than change_id %d",
3364 change_id_info2, change_id_info));
3366 return true;
3369 static bool test_SecondaryClosePrinter(struct torture_context *tctx,
3370 struct dcerpc_pipe *p,
3371 struct policy_handle *handle)
3373 NTSTATUS status;
3374 struct dcerpc_binding *b;
3375 struct dcerpc_pipe *p2;
3376 struct spoolss_ClosePrinter cp;
3378 /* only makes sense on SMB */
3379 if (p->conn->transport.transport != NCACN_NP) {
3380 return true;
3383 torture_comment(tctx, "testing close on secondary pipe\n");
3385 status = dcerpc_parse_binding(tctx, p->conn->binding_string, &b);
3386 torture_assert_ntstatus_ok(tctx, status, "Failed to parse dcerpc binding");
3388 status = dcerpc_secondary_connection(p, &p2, b);
3389 torture_assert_ntstatus_ok(tctx, status, "Failed to create secondary connection");
3391 status = dcerpc_bind_auth_none(p2, &ndr_table_spoolss);
3392 torture_assert_ntstatus_ok(tctx, status, "Failed to create bind on secondary connection");
3394 cp.in.handle = handle;
3395 cp.out.handle = handle;
3397 status = dcerpc_spoolss_ClosePrinter(p2, tctx, &cp);
3398 torture_assert_ntstatus_equal(tctx, status, NT_STATUS_NET_WRITE_FAULT,
3399 "ERROR: Allowed close on secondary connection");
3401 torture_assert_int_equal(tctx, p2->last_fault_code, DCERPC_FAULT_CONTEXT_MISMATCH,
3402 "Unexpected fault code");
3404 talloc_free(p2);
3406 return true;
3409 static bool test_OpenPrinter_badname(struct torture_context *tctx,
3410 struct dcerpc_pipe *p, const char *name)
3412 NTSTATUS status;
3413 struct spoolss_OpenPrinter op;
3414 struct spoolss_OpenPrinterEx opEx;
3415 struct policy_handle handle;
3416 bool ret = true;
3418 op.in.printername = name;
3419 op.in.datatype = NULL;
3420 op.in.devmode_ctr.devmode= NULL;
3421 op.in.access_mask = 0;
3422 op.out.handle = &handle;
3424 torture_comment(tctx, "\nTesting OpenPrinter(%s) with bad name\n", op.in.printername);
3426 status = dcerpc_spoolss_OpenPrinter(p, tctx, &op);
3427 torture_assert_ntstatus_ok(tctx, status, "OpenPrinter failed");
3428 if (!W_ERROR_EQUAL(WERR_INVALID_PRINTER_NAME,op.out.result)) {
3429 torture_comment(tctx, "OpenPrinter(%s) unexpected result[%s] should be WERR_INVALID_PRINTER_NAME\n",
3430 name, win_errstr(op.out.result));
3433 if (W_ERROR_IS_OK(op.out.result)) {
3434 ret &=test_ClosePrinter(tctx, p, &handle);
3437 opEx.in.printername = name;
3438 opEx.in.datatype = NULL;
3439 opEx.in.devmode_ctr.devmode = NULL;
3440 opEx.in.access_mask = 0;
3441 opEx.in.level = 1;
3442 opEx.in.userlevel.level1 = NULL;
3443 opEx.out.handle = &handle;
3445 torture_comment(tctx, "Testing OpenPrinterEx(%s) with bad name\n", opEx.in.printername);
3447 status = dcerpc_spoolss_OpenPrinterEx(p, tctx, &opEx);
3448 torture_assert_ntstatus_ok(tctx, status, "OpenPrinterEx failed");
3449 if (!W_ERROR_EQUAL(WERR_INVALID_PARAM,opEx.out.result)) {
3450 torture_comment(tctx, "OpenPrinterEx(%s) unexpected result[%s] should be WERR_INVALID_PARAM\n",
3451 name, win_errstr(opEx.out.result));
3454 if (W_ERROR_IS_OK(opEx.out.result)) {
3455 ret &=test_ClosePrinter(tctx, p, &handle);
3458 return ret;
3461 static bool test_OpenPrinter(struct torture_context *tctx,
3462 struct dcerpc_pipe *p,
3463 const char *name)
3465 NTSTATUS status;
3466 struct spoolss_OpenPrinter r;
3467 struct policy_handle handle;
3468 bool ret = true;
3470 r.in.printername = talloc_asprintf(tctx, "\\\\%s\\%s", dcerpc_server_name(p), name);
3471 r.in.datatype = NULL;
3472 r.in.devmode_ctr.devmode= NULL;
3473 r.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
3474 r.out.handle = &handle;
3476 torture_comment(tctx, "Testing OpenPrinter(%s)\n", r.in.printername);
3478 status = dcerpc_spoolss_OpenPrinter(p, tctx, &r);
3480 torture_assert_ntstatus_ok(tctx, status, "OpenPrinter failed");
3482 torture_assert_werr_ok(tctx, r.out.result, "OpenPrinter failed");
3484 if (!test_GetPrinter(tctx, p, &handle)) {
3485 ret = false;
3488 if (!torture_setting_bool(tctx, "samba3", false)) {
3489 if (!test_SecondaryClosePrinter(tctx, p, &handle)) {
3490 ret = false;
3494 if (!test_ClosePrinter(tctx, p, &handle)) {
3495 ret = false;
3498 return ret;
3501 static bool call_OpenPrinterEx(struct torture_context *tctx,
3502 struct dcerpc_pipe *p,
3503 const char *name,
3504 struct spoolss_DeviceMode *devmode,
3505 struct policy_handle *handle)
3507 struct spoolss_OpenPrinterEx r;
3508 struct spoolss_UserLevel1 userlevel1;
3509 NTSTATUS status;
3511 if (name && name[0]) {
3512 r.in.printername = talloc_asprintf(tctx, "\\\\%s\\%s",
3513 dcerpc_server_name(p), name);
3514 } else {
3515 r.in.printername = talloc_asprintf(tctx, "\\\\%s",
3516 dcerpc_server_name(p));
3519 r.in.datatype = NULL;
3520 r.in.devmode_ctr.devmode= devmode;
3521 r.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
3522 r.in.level = 1;
3523 r.in.userlevel.level1 = &userlevel1;
3524 r.out.handle = handle;
3526 userlevel1.size = 1234;
3527 userlevel1.client = "hello";
3528 userlevel1.user = "spottyfoot!";
3529 userlevel1.build = 1;
3530 userlevel1.major = 2;
3531 userlevel1.minor = 3;
3532 userlevel1.processor = 4;
3534 torture_comment(tctx, "Testing OpenPrinterEx(%s)\n", r.in.printername);
3536 status = dcerpc_spoolss_OpenPrinterEx(p, tctx, &r);
3538 torture_assert_ntstatus_ok(tctx, status, "OpenPrinterEx failed");
3540 torture_assert_werr_ok(tctx, r.out.result, "OpenPrinterEx failed");
3542 return true;
3545 static bool test_OpenPrinterEx(struct torture_context *tctx,
3546 struct dcerpc_pipe *p,
3547 const char *name)
3549 struct policy_handle handle;
3550 bool ret = true;
3552 if (!call_OpenPrinterEx(tctx, p, name, NULL, &handle)) {
3553 return false;
3556 if (!test_PrinterInfo_SD(tctx, p, &handle)) {
3557 ret = false;
3560 if (!test_GetPrinter(tctx, p, &handle)) {
3561 ret = false;
3564 if (!test_EnumForms(tctx, p, &handle, false)) {
3565 ret = false;
3568 if (!test_AddForm(tctx, p, &handle, false)) {
3569 ret = false;
3572 if (!test_EnumPrinterData(tctx, p, &handle)) {
3573 ret = false;
3576 if (!test_EnumPrinterDataEx(tctx, p, &handle, "PrinterDriverData")) {
3577 ret = false;
3580 if (!test_printer_keys(tctx, p, &handle)) {
3581 ret = false;
3584 if (!test_PausePrinter(tctx, p, &handle)) {
3585 ret = false;
3588 if (!test_DoPrintTest(tctx, p, &handle)) {
3589 ret = false;
3592 if (!test_ResumePrinter(tctx, p, &handle)) {
3593 ret = false;
3596 if (!test_SetPrinterData(tctx, p, &handle)) {
3597 ret = false;
3600 if (!test_SetPrinterDataEx(tctx, p, &handle)) {
3601 ret = false;
3604 if (!test_ChangeID(tctx, p, &handle)) {
3605 ret = false;
3608 if (!torture_setting_bool(tctx, "samba3", false)) {
3609 if (!test_SecondaryClosePrinter(tctx, p, &handle)) {
3610 ret = false;
3614 if (!test_ClosePrinter(tctx, p, &handle)) {
3615 ret = false;
3618 return ret;
3621 static bool test_EnumPrinters_old(struct torture_context *tctx, struct dcerpc_pipe *p)
3623 struct spoolss_EnumPrinters r;
3624 NTSTATUS status;
3625 uint16_t levels[] = {1, 2, 4, 5};
3626 int i;
3627 bool ret = true;
3629 for (i=0;i<ARRAY_SIZE(levels);i++) {
3630 union spoolss_PrinterInfo *info;
3631 int j;
3632 uint32_t needed;
3633 uint32_t count;
3635 r.in.flags = PRINTER_ENUM_LOCAL;
3636 r.in.server = "";
3637 r.in.level = levels[i];
3638 r.in.buffer = NULL;
3639 r.in.offered = 0;
3640 r.out.needed = &needed;
3641 r.out.count = &count;
3642 r.out.info = &info;
3644 torture_comment(tctx, "Testing EnumPrinters level %u\n", r.in.level);
3646 status = dcerpc_spoolss_EnumPrinters(p, tctx, &r);
3647 torture_assert_ntstatus_ok(tctx, status, "EnumPrinters failed");
3649 if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
3650 DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed);
3651 data_blob_clear(&blob);
3652 r.in.buffer = &blob;
3653 r.in.offered = needed;
3654 status = dcerpc_spoolss_EnumPrinters(p, tctx, &r);
3657 torture_assert_ntstatus_ok(tctx, status, "EnumPrinters failed");
3659 torture_assert_werr_ok(tctx, r.out.result, "EnumPrinters failed");
3661 CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumPrinters, info, r.in.level, count, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
3663 if (!info) {
3664 torture_comment(tctx, "No printers returned\n");
3665 return true;
3668 for (j=0;j<count;j++) {
3669 if (r.in.level == 1) {
3670 char *unc = talloc_strdup(tctx, info[j].info1.name);
3671 char *slash, *name;
3672 name = unc;
3673 if (unc[0] == '\\' && unc[1] == '\\') {
3674 unc +=2;
3676 slash = strchr(unc, '\\');
3677 if (slash) {
3678 slash++;
3679 name = slash;
3681 if (!test_OpenPrinter(tctx, p, name)) {
3682 ret = false;
3684 if (!test_OpenPrinterEx(tctx, p, name)) {
3685 ret = false;
3691 return ret;
3694 static bool test_GetPrinterDriver(struct torture_context *tctx,
3695 struct dcerpc_pipe *p,
3696 struct policy_handle *handle,
3697 const char *driver_name)
3699 struct spoolss_GetPrinterDriver r;
3700 uint32_t needed;
3702 r.in.handle = handle;
3703 r.in.architecture = "W32X86";
3704 r.in.level = 1;
3705 r.in.buffer = NULL;
3706 r.in.offered = 0;
3707 r.out.needed = &needed;
3709 torture_comment(tctx, "Testing GetPrinterDriver level %d\n", r.in.level);
3711 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_GetPrinterDriver(p, tctx, &r),
3712 "failed to call GetPrinterDriver");
3713 if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
3714 DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed);
3715 data_blob_clear(&blob);
3716 r.in.buffer = &blob;
3717 r.in.offered = needed;
3718 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_GetPrinterDriver(p, tctx, &r),
3719 "failed to call GetPrinterDriver");
3722 torture_assert_werr_ok(tctx, r.out.result,
3723 "failed to call GetPrinterDriver");
3725 CHECK_NEEDED_SIZE_LEVEL(spoolss_DriverInfo, r.out.info, r.in.level, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
3727 return true;
3730 static bool test_GetPrinterDriver2(struct torture_context *tctx,
3731 struct dcerpc_pipe *p,
3732 struct policy_handle *handle,
3733 const char *driver_name)
3735 struct spoolss_GetPrinterDriver2 r;
3736 uint16_t levels[] = {1, 2, 3, 4, 5, 6, 8, 101 };
3737 uint32_t needed;
3738 uint32_t server_major_version;
3739 uint32_t server_minor_version;
3740 int i;
3742 r.in.handle = handle;
3743 r.in.architecture = SPOOLSS_ARCHITECTURE_NT_X86;
3744 r.in.client_major_version = 3;
3745 r.in.client_minor_version = 0;
3746 r.out.needed = &needed;
3747 r.out.server_major_version = &server_major_version;
3748 r.out.server_minor_version = &server_minor_version;
3750 for (i=0;i<ARRAY_SIZE(levels);i++) {
3752 r.in.buffer = NULL;
3753 r.in.offered = 0;
3754 r.in.level = levels[i];
3756 torture_comment(tctx, "Testing GetPrinterDriver2(%s) level %d\n",
3757 driver_name, r.in.level);
3759 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_GetPrinterDriver2(p, tctx, &r),
3760 "failed to call GetPrinterDriver2");
3761 if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
3762 DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed);
3763 data_blob_clear(&blob);
3764 r.in.buffer = &blob;
3765 r.in.offered = needed;
3766 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_GetPrinterDriver2(p, tctx, &r),
3767 "failed to call GetPrinterDriver2");
3770 if (W_ERROR_EQUAL(r.out.result, WERR_INVALID_LEVEL)) {
3771 switch (r.in.level) {
3772 case 101:
3773 case 8:
3774 continue;
3775 default:
3776 break;
3780 torture_assert_werr_ok(tctx, r.out.result,
3781 "failed to call GetPrinterDriver2");
3783 CHECK_NEEDED_SIZE_LEVEL(spoolss_DriverInfo, r.out.info, r.in.level, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
3786 return true;
3789 static bool test_EnumPrinterDrivers_old(struct torture_context *tctx,
3790 struct dcerpc_pipe *p)
3792 struct spoolss_EnumPrinterDrivers r;
3793 NTSTATUS status;
3794 uint16_t levels[] = {1, 2, 3, 4, 5, 6};
3795 int i;
3797 for (i=0;i<ARRAY_SIZE(levels);i++) {
3799 uint32_t needed;
3800 uint32_t count;
3801 union spoolss_DriverInfo *info;
3803 r.in.server = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
3804 r.in.environment = SPOOLSS_ARCHITECTURE_NT_X86;
3805 r.in.level = levels[i];
3806 r.in.buffer = NULL;
3807 r.in.offered = 0;
3808 r.out.needed = &needed;
3809 r.out.count = &count;
3810 r.out.info = &info;
3812 torture_comment(tctx, "Testing EnumPrinterDrivers level %u\n", r.in.level);
3814 status = dcerpc_spoolss_EnumPrinterDrivers(p, tctx, &r);
3816 torture_assert_ntstatus_ok(tctx, status, "EnumPrinterDrivers failed");
3818 if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
3819 DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed);
3820 data_blob_clear(&blob);
3821 r.in.buffer = &blob;
3822 r.in.offered = needed;
3823 status = dcerpc_spoolss_EnumPrinterDrivers(p, tctx, &r);
3826 torture_assert_ntstatus_ok(tctx, status, "EnumPrinterDrivers failed");
3828 torture_assert_werr_ok(tctx, r.out.result, "EnumPrinterDrivers failed");
3830 if (!info) {
3831 torture_comment(tctx, "No printer drivers returned\n");
3832 break;
3835 CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumPrinterDrivers, info, r.in.level, count, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
3838 return true;
3841 static bool test_DeletePrinter(struct torture_context *tctx,
3842 struct dcerpc_pipe *p,
3843 struct policy_handle *handle)
3845 struct spoolss_DeletePrinter r;
3847 torture_comment(tctx, "Testing DeletePrinter\n");
3849 r.in.handle = handle;
3851 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_DeletePrinter(p, tctx, &r),
3852 "failed to delete printer");
3853 torture_assert_werr_ok(tctx, r.out.result,
3854 "failed to delete printer");
3856 return true;
3859 static bool test_EnumPrinters_findname(struct torture_context *tctx,
3860 struct dcerpc_pipe *p,
3861 uint32_t flags,
3862 uint32_t level,
3863 const char *name,
3864 bool *found)
3866 struct spoolss_EnumPrinters e;
3867 uint32_t count;
3868 union spoolss_PrinterInfo *info;
3869 uint32_t needed;
3870 int i;
3872 *found = false;
3874 e.in.flags = flags;
3875 e.in.server = NULL;
3876 e.in.level = level;
3877 e.in.buffer = NULL;
3878 e.in.offered = 0;
3879 e.out.count = &count;
3880 e.out.info = &info;
3881 e.out.needed = &needed;
3883 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_EnumPrinters(p, tctx, &e),
3884 "failed to enum printers");
3886 if (W_ERROR_EQUAL(e.out.result, WERR_INSUFFICIENT_BUFFER)) {
3887 DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed);
3888 data_blob_clear(&blob);
3889 e.in.buffer = &blob;
3890 e.in.offered = needed;
3892 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_EnumPrinters(p, tctx, &e),
3893 "failed to enum printers");
3896 torture_assert_werr_ok(tctx, e.out.result,
3897 "failed to enum printers");
3899 for (i=0; i < count; i++) {
3901 const char *current = NULL;
3903 switch (level) {
3904 case 1:
3905 current = info[i].info1.name;
3906 break;
3909 if (strequal(current, name)) {
3910 *found = true;
3911 break;
3915 return true;
3918 static bool test_AddPrinter_wellknown(struct torture_context *tctx,
3919 struct dcerpc_pipe *p,
3920 const char *printername,
3921 bool ex)
3923 WERROR result;
3924 struct spoolss_AddPrinter r;
3925 struct spoolss_AddPrinterEx rex;
3926 struct spoolss_SetPrinterInfoCtr info_ctr;
3927 struct spoolss_SetPrinterInfo1 info1;
3928 struct spoolss_DevmodeContainer devmode_ctr;
3929 struct sec_desc_buf secdesc_ctr;
3930 struct spoolss_UserLevelCtr userlevel_ctr;
3931 struct policy_handle handle;
3932 bool found = false;
3934 ZERO_STRUCT(devmode_ctr);
3935 ZERO_STRUCT(secdesc_ctr);
3936 ZERO_STRUCT(userlevel_ctr);
3937 ZERO_STRUCT(info1);
3939 torture_comment(tctx, "Testing AddPrinter%s level 1\n", ex ? "Ex":"");
3941 /* try to add printer to wellknown printer list (level 1) */
3943 userlevel_ctr.level = 1;
3945 info_ctr.info.info1 = &info1;
3946 info_ctr.level = 1;
3948 rex.in.server = NULL;
3949 rex.in.info_ctr = &info_ctr;
3950 rex.in.devmode_ctr = &devmode_ctr;
3951 rex.in.secdesc_ctr = &secdesc_ctr;
3952 rex.in.userlevel_ctr = &userlevel_ctr;
3953 rex.out.handle = &handle;
3955 r.in.server = NULL;
3956 r.in.info_ctr = &info_ctr;
3957 r.in.devmode_ctr = &devmode_ctr;
3958 r.in.secdesc_ctr = &secdesc_ctr;
3959 r.out.handle = &handle;
3961 torture_assert_ntstatus_ok(tctx, ex ? dcerpc_spoolss_AddPrinterEx(p, tctx, &rex) :
3962 dcerpc_spoolss_AddPrinter(p, tctx, &r),
3963 "failed to add printer");
3964 result = ex ? rex.out.result : r.out.result;
3965 torture_assert_werr_equal(tctx, result, WERR_INVALID_PRINTER_NAME,
3966 "unexpected result code");
3968 info1.name = printername;
3969 info1.flags = PRINTER_ATTRIBUTE_SHARED;
3971 torture_assert_ntstatus_ok(tctx, ex ? dcerpc_spoolss_AddPrinterEx(p, tctx, &rex) :
3972 dcerpc_spoolss_AddPrinter(p, tctx, &r),
3973 "failed to add printer");
3974 result = ex ? rex.out.result : r.out.result;
3975 torture_assert_werr_equal(tctx, result, WERR_PRINTER_ALREADY_EXISTS,
3976 "unexpected result code");
3978 /* bizarre protocol, WERR_PRINTER_ALREADY_EXISTS means success here,
3979 better do a real check to see the printer is really there */
3981 torture_assert(tctx, test_EnumPrinters_findname(tctx, p,
3982 PRINTER_ENUM_NETWORK, 1,
3983 printername,
3984 &found),
3985 "failed to enum printers");
3987 torture_assert(tctx, found, "failed to find newly added printer");
3989 info1.flags = 0;
3991 torture_assert_ntstatus_ok(tctx, ex ? dcerpc_spoolss_AddPrinterEx(p, tctx, &rex) :
3992 dcerpc_spoolss_AddPrinter(p, tctx, &r),
3993 "failed to add printer");
3994 result = ex ? rex.out.result : r.out.result;
3995 torture_assert_werr_equal(tctx, result, WERR_PRINTER_ALREADY_EXISTS,
3996 "unexpected result code");
3998 /* bizarre protocol, WERR_PRINTER_ALREADY_EXISTS means success here,
3999 better do a real check to see the printer has really been removed
4000 from the well known printer list */
4002 found = false;
4004 torture_assert(tctx, test_EnumPrinters_findname(tctx, p,
4005 PRINTER_ENUM_NETWORK, 1,
4006 printername,
4007 &found),
4008 "failed to enum printers");
4009 #if 0
4010 torture_assert(tctx, !found, "printer still in well known printer list");
4011 #endif
4012 return true;
4015 static bool test_AddPrinter_normal(struct torture_context *tctx,
4016 struct dcerpc_pipe *p,
4017 struct policy_handle *handle_p,
4018 const char *printername,
4019 const char *drivername,
4020 const char *portname,
4021 bool ex)
4023 WERROR result;
4024 struct spoolss_AddPrinter r;
4025 struct spoolss_AddPrinterEx rex;
4026 struct spoolss_SetPrinterInfoCtr info_ctr;
4027 struct spoolss_SetPrinterInfo2 info2;
4028 struct spoolss_DevmodeContainer devmode_ctr;
4029 struct sec_desc_buf secdesc_ctr;
4030 struct spoolss_UserLevelCtr userlevel_ctr;
4031 struct policy_handle handle;
4032 bool found = false;
4033 bool existing_printer_deleted = false;
4035 ZERO_STRUCT(devmode_ctr);
4036 ZERO_STRUCT(secdesc_ctr);
4037 ZERO_STRUCT(userlevel_ctr);
4039 torture_comment(tctx, "Testing AddPrinter%s level 2\n", ex ? "Ex":"");
4041 userlevel_ctr.level = 1;
4043 rex.in.server = NULL;
4044 rex.in.info_ctr = &info_ctr;
4045 rex.in.devmode_ctr = &devmode_ctr;
4046 rex.in.secdesc_ctr = &secdesc_ctr;
4047 rex.in.userlevel_ctr = &userlevel_ctr;
4048 rex.out.handle = &handle;
4050 r.in.server = NULL;
4051 r.in.info_ctr = &info_ctr;
4052 r.in.devmode_ctr = &devmode_ctr;
4053 r.in.secdesc_ctr = &secdesc_ctr;
4054 r.out.handle = &handle;
4056 again:
4058 /* try to add printer to printer list (level 2) */
4060 ZERO_STRUCT(info2);
4062 info_ctr.info.info2 = &info2;
4063 info_ctr.level = 2;
4065 torture_assert_ntstatus_ok(tctx, ex ? dcerpc_spoolss_AddPrinterEx(p, tctx, &rex) :
4066 dcerpc_spoolss_AddPrinter(p, tctx, &r),
4067 "failed to add printer");
4068 result = ex ? rex.out.result : r.out.result;
4069 torture_assert_werr_equal(tctx, result, WERR_INVALID_PRINTER_NAME,
4070 "unexpected result code");
4072 info2.printername = printername;
4074 torture_assert_ntstatus_ok(tctx, ex ? dcerpc_spoolss_AddPrinterEx(p, tctx, &rex) :
4075 dcerpc_spoolss_AddPrinter(p, tctx, &r),
4076 "failed to add printer");
4077 result = ex ? rex.out.result : r.out.result;
4079 if (W_ERROR_EQUAL(result, WERR_PRINTER_ALREADY_EXISTS)) {
4080 struct policy_handle printer_handle;
4082 if (existing_printer_deleted) {
4083 torture_fail(tctx, "already deleted printer still existing?");
4086 torture_assert(tctx, call_OpenPrinterEx(tctx, p, printername, NULL, &printer_handle),
4087 "failed to open printer handle");
4089 torture_assert(tctx, test_DeletePrinter(tctx, p, &printer_handle),
4090 "failed to delete printer");
4092 torture_assert(tctx, test_ClosePrinter(tctx, p, &printer_handle),
4093 "failed to close server handle");
4095 existing_printer_deleted = true;
4097 goto again;
4100 torture_assert_werr_equal(tctx, result, WERR_UNKNOWN_PORT,
4101 "unexpected result code");
4103 info2.portname = portname;
4105 torture_assert_ntstatus_ok(tctx, ex ? dcerpc_spoolss_AddPrinterEx(p, tctx, &rex) :
4106 dcerpc_spoolss_AddPrinter(p, tctx, &r),
4107 "failed to add printer");
4108 result = ex ? rex.out.result : r.out.result;
4109 torture_assert_werr_equal(tctx, result, WERR_UNKNOWN_PRINTER_DRIVER,
4110 "unexpected result code");
4112 info2.drivername = drivername;
4114 torture_assert_ntstatus_ok(tctx, ex ? dcerpc_spoolss_AddPrinterEx(p, tctx, &rex) :
4115 dcerpc_spoolss_AddPrinter(p, tctx, &r),
4116 "failed to add printer");
4117 result = ex ? rex.out.result : r.out.result;
4119 /* w2k8r2 allows to add printer w/o defining printprocessor */
4121 if (!W_ERROR_IS_OK(result)) {
4122 torture_assert_werr_equal(tctx, result, WERR_UNKNOWN_PRINTPROCESSOR,
4123 "unexpected result code");
4125 info2.printprocessor = "winprint";
4127 torture_assert_ntstatus_ok(tctx, ex ? dcerpc_spoolss_AddPrinterEx(p, tctx, &rex) :
4128 dcerpc_spoolss_AddPrinter(p, tctx, &r),
4129 "failed to add printer");
4130 result = ex ? rex.out.result : r.out.result;
4131 torture_assert_werr_ok(tctx, result,
4132 "failed to add printer");
4135 *handle_p = handle;
4137 /* we are paranoid, really check if the printer is there now */
4139 torture_assert(tctx, test_EnumPrinters_findname(tctx, p,
4140 PRINTER_ENUM_LOCAL, 1,
4141 printername,
4142 &found),
4143 "failed to enum printers");
4144 torture_assert(tctx, found, "failed to find newly added printer");
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_PRINTER_ALREADY_EXISTS,
4151 "unexpected result code");
4153 return true;
4156 static bool test_AddPrinterEx(struct torture_context *tctx,
4157 struct dcerpc_pipe *p,
4158 struct policy_handle *handle_p,
4159 const char *printername,
4160 const char *drivername,
4161 const char *portname)
4163 bool ret = true;
4165 if (!torture_setting_bool(tctx, "samba3", false)) {
4166 if (!test_AddPrinter_wellknown(tctx, p, TORTURE_WELLKNOWN_PRINTER_EX, true)) {
4167 torture_comment(tctx, "failed to add printer to well known list\n");
4168 ret = false;
4172 if (!test_AddPrinter_normal(tctx, p, handle_p,
4173 printername, drivername, portname,
4174 true)) {
4175 torture_comment(tctx, "failed to add printer to printer list\n");
4176 ret = false;
4179 return ret;
4182 static bool test_AddPrinter(struct torture_context *tctx,
4183 struct dcerpc_pipe *p,
4184 struct policy_handle *handle_p,
4185 const char *printername,
4186 const char *drivername,
4187 const char *portname)
4189 bool ret = true;
4191 if (!torture_setting_bool(tctx, "samba3", false)) {
4192 if (!test_AddPrinter_wellknown(tctx, p, TORTURE_WELLKNOWN_PRINTER, false)) {
4193 torture_comment(tctx, "failed to add printer to well known list\n");
4194 ret = false;
4198 if (!test_AddPrinter_normal(tctx, p, handle_p,
4199 printername, drivername, portname,
4200 false)) {
4201 torture_comment(tctx, "failed to add printer to printer list\n");
4202 ret = false;
4205 return ret;
4208 static bool test_printer_info(struct torture_context *tctx,
4209 struct dcerpc_pipe *p,
4210 struct policy_handle *handle)
4212 bool ret = true;
4214 if (!test_PrinterInfo(tctx, p, handle)) {
4215 ret = false;
4218 if (!test_SetPrinter_errors(tctx, p, handle)) {
4219 ret = false;
4222 return ret;
4225 static bool test_EnumPrinterKey(struct torture_context *tctx,
4226 struct dcerpc_pipe *p,
4227 struct policy_handle *handle,
4228 const char *key_name,
4229 const char ***array)
4231 struct spoolss_EnumPrinterKey r;
4232 uint32_t needed = 0;
4233 union spoolss_KeyNames key_buffer;
4234 int32_t offered[] = { 0, 1, 2, 3, 4, 5, -1, -2, -3, -4, -5, 256, 512, 1024, 2048 };
4235 uint32_t _ndr_size;
4236 int i;
4238 r.in.handle = handle;
4239 r.in.key_name = key_name;
4240 r.out.key_buffer = &key_buffer;
4241 r.out.needed = &needed;
4242 r.out._ndr_size = &_ndr_size;
4244 for (i=0; i < ARRAY_SIZE(offered); i++) {
4246 if (offered[i] < 0 && needed) {
4247 if (needed <= 4) {
4248 continue;
4250 r.in.offered = needed + offered[i];
4251 } else {
4252 r.in.offered = offered[i];
4255 ZERO_STRUCT(key_buffer);
4257 torture_comment(tctx, "Testing EnumPrinterKey(%s) with %d offered\n", r.in.key_name, r.in.offered);
4259 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_EnumPrinterKey(p, tctx, &r),
4260 "failed to call EnumPrinterKey");
4261 if (W_ERROR_EQUAL(r.out.result, WERR_MORE_DATA)) {
4263 torture_assert(tctx, (_ndr_size == r.in.offered/2),
4264 talloc_asprintf(tctx, "EnumPrinterKey size mismatch, _ndr_size %d (expected %d)",
4265 _ndr_size, r.in.offered/2));
4267 r.in.offered = needed;
4268 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_EnumPrinterKey(p, tctx, &r),
4269 "failed to call EnumPrinterKey");
4272 if (offered[i] > 0) {
4273 torture_assert_werr_ok(tctx, r.out.result,
4274 "failed to call EnumPrinterKey");
4277 torture_assert(tctx, (_ndr_size == r.in.offered/2),
4278 talloc_asprintf(tctx, "EnumPrinterKey size mismatch, _ndr_size %d (expected %d)",
4279 _ndr_size, r.in.offered/2));
4281 torture_assert(tctx, (*r.out.needed <= r.in.offered),
4282 talloc_asprintf(tctx, "EnumPrinterKey size mismatch: needed %d is not <= offered %d", *r.out.needed, r.in.offered));
4284 torture_assert(tctx, (*r.out.needed <= _ndr_size * 2),
4285 talloc_asprintf(tctx, "EnumPrinterKey size mismatch: needed %d is not <= _ndr_size %d * 2", *r.out.needed, _ndr_size));
4287 if (key_buffer.string_array) {
4288 uint32_t calc_needed = 0;
4289 int s;
4290 for (s=0; key_buffer.string_array[s]; s++) {
4291 calc_needed += strlen_m_term(key_buffer.string_array[s])*2;
4293 if (!key_buffer.string_array[0]) {
4294 calc_needed += 2;
4296 calc_needed += 2;
4298 torture_assert_int_equal(tctx, *r.out.needed, calc_needed,
4299 "EnumPrinterKey unexpected size");
4303 if (array) {
4304 *array = key_buffer.string_array;
4307 return true;
4310 bool test_printer_keys(struct torture_context *tctx,
4311 struct dcerpc_pipe *p,
4312 struct policy_handle *handle)
4314 const char **key_array = NULL;
4315 int i;
4317 torture_assert(tctx, test_EnumPrinterKey(tctx, p, handle, "", &key_array),
4318 "failed to call test_EnumPrinterKey");
4320 for (i=0; key_array && key_array[i]; i++) {
4321 torture_assert(tctx, test_EnumPrinterKey(tctx, p, handle, key_array[i], NULL),
4322 "failed to call test_EnumPrinterKey");
4324 for (i=0; key_array && key_array[i]; i++) {
4325 torture_assert(tctx, test_EnumPrinterDataEx(tctx, p, handle, key_array[i]),
4326 "failed to call test_EnumPrinterDataEx");
4329 return true;
4332 static bool test_one_printer(struct torture_context *tctx,
4333 struct dcerpc_pipe *p,
4334 struct policy_handle *handle,
4335 const char *name)
4337 bool ret = true;
4339 if (!test_printer_info(tctx, p, handle)) {
4340 ret = false;
4343 if (!test_PrinterInfo_SD(tctx, p, handle)) {
4344 ret = false;
4347 if (!test_PrinterInfo_DevMode(tctx, p, handle, name)) {
4348 ret = false;
4351 if (!test_printer_keys(tctx, p, handle)) {
4352 ret = false;
4355 return ret;
4358 static bool test_printer(struct torture_context *tctx,
4359 struct dcerpc_pipe *p)
4361 bool ret = true;
4362 struct policy_handle handle[2];
4363 bool found = false;
4364 const char *drivername = "Microsoft XPS Document Writer";
4365 const char *portname = "LPT1:";
4367 /* test printer created via AddPrinter */
4369 if (!test_AddPrinter(tctx, p, &handle[0], TORTURE_PRINTER, drivername, portname)) {
4370 return false;
4373 if (!test_one_printer(tctx, p, &handle[0], TORTURE_PRINTER)) {
4374 ret = false;
4377 if (!test_DeletePrinter(tctx, p, &handle[0])) {
4378 ret = false;
4381 if (!test_EnumPrinters_findname(tctx, p, PRINTER_ENUM_LOCAL, 1,
4382 TORTURE_PRINTER, &found)) {
4383 ret = false;
4386 torture_assert(tctx, !found, "deleted printer still there");
4388 /* test printer created via AddPrinterEx */
4390 if (!test_AddPrinterEx(tctx, p, &handle[1], TORTURE_PRINTER_EX, drivername, portname)) {
4391 return false;
4394 if (!test_one_printer(tctx, p, &handle[1], TORTURE_PRINTER_EX)) {
4395 ret = false;
4398 if (!test_DeletePrinter(tctx, p, &handle[1])) {
4399 ret = false;
4402 if (!test_EnumPrinters_findname(tctx, p, PRINTER_ENUM_LOCAL, 1,
4403 TORTURE_PRINTER_EX, &found)) {
4404 ret = false;
4407 torture_assert(tctx, !found, "deleted printer still there");
4409 return ret;
4412 bool torture_rpc_spoolss(struct torture_context *torture)
4414 NTSTATUS status;
4415 struct dcerpc_pipe *p;
4416 bool ret = true;
4417 struct test_spoolss_context *ctx;
4419 status = torture_rpc_connection(torture, &p, &ndr_table_spoolss);
4420 if (!NT_STATUS_IS_OK(status)) {
4421 return false;
4424 ctx = talloc_zero(torture, struct test_spoolss_context);
4426 ret &= test_OpenPrinter_server(torture, p, &ctx->server_handle);
4427 ret &= test_GetPrinterData_list(torture, p, &ctx->server_handle);
4428 ret &= test_EnumForms(torture, p, &ctx->server_handle, true);
4429 ret &= test_AddForm(torture, p, &ctx->server_handle, true);
4430 ret &= test_EnumPorts(torture, p, ctx);
4431 ret &= test_GetPrinterDriverDirectory(torture, p, ctx);
4432 ret &= test_GetPrintProcessorDirectory(torture, p, ctx);
4433 ret &= test_EnumPrinterDrivers(torture, p, ctx, SPOOLSS_ARCHITECTURE_NT_X86);
4434 ret &= test_EnumPrinterDrivers(torture, p, ctx, SPOOLSS_ARCHITECTURE_ALL);
4435 ret &= test_EnumMonitors(torture, p, ctx);
4436 ret &= test_EnumPrintProcessors(torture, p, ctx);
4437 ret &= test_EnumPrintProcDataTypes(torture, p, ctx);
4438 ret &= test_EnumPrinters(torture, p, ctx);
4439 ret &= test_OpenPrinter_badname(torture, p, "__INVALID_PRINTER__");
4440 ret &= test_OpenPrinter_badname(torture, p, "\\\\__INVALID_HOST__");
4441 ret &= test_OpenPrinter_badname(torture, p, "");
4442 ret &= test_OpenPrinter_badname(torture, p, "\\\\\\");
4443 ret &= test_OpenPrinter_badname(torture, p, "\\\\\\__INVALID_PRINTER__");
4444 ret &= test_OpenPrinter_badname(torture, p, talloc_asprintf(torture, "\\\\%s\\", dcerpc_server_name(p)));
4445 ret &= test_OpenPrinter_badname(torture, p,
4446 talloc_asprintf(torture, "\\\\%s\\__INVALID_PRINTER__", dcerpc_server_name(p)));
4449 ret &= test_AddPort(torture, p);
4450 ret &= test_EnumPorts_old(torture, p);
4451 ret &= test_EnumPrinters_old(torture, p);
4452 ret &= test_EnumPrinterDrivers_old(torture, p);
4454 return ret;
4457 struct torture_suite *torture_rpc_spoolss_printer(TALLOC_CTX *mem_ctx)
4459 struct torture_suite *suite = torture_suite_create(mem_ctx, "SPOOLSS-PRINTER");
4461 struct torture_rpc_tcase *tcase = torture_suite_add_rpc_iface_tcase(suite,
4462 "printer", &ndr_table_spoolss);
4464 torture_rpc_tcase_add_test(tcase, "printer", test_printer);
4466 return suite;