s4-smbtorture: use test_SetPrinter call in spoolss security descriptor tests.
[Samba/cd1.git] / source4 / torture / rpc / spoolss.c
blob242b3053937ad04288efb2df580fb3ecdb8ba355
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 union spoolss_PrinterInfo info_2;
1649 struct security_descriptor *sd1, *sd2;
1650 int i;
1652 /* level 2 */
1654 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 2, &info), "");
1656 sd1 = security_descriptor_copy(tctx, info.info2.secdesc);
1658 torture_assert(tctx, test_sd_set_level(tctx, p, handle, 2, sd1), "");
1660 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 2, &info_2), "");
1662 sd2 = security_descriptor_copy(tctx, info_2.info2.secdesc);
1664 if (sd1->type & SEC_DESC_DACL_DEFAULTED) {
1665 torture_comment(tctx, "removing SEC_DESC_DACL_DEFAULTED from 1st for comparison\n");
1666 sd1->type &= ~SEC_DESC_DACL_DEFAULTED;
1669 torture_assert(tctx, test_security_descriptor_equal(tctx, sd1, sd2), "");
1671 /* level 3 */
1673 sd1 = sd2;
1675 for (i=0; i < 93; i++) {
1676 struct security_ace a;
1677 const char *sid_string = talloc_asprintf(tctx, "S-1-5-32-9999%i", i);
1678 a.type = SEC_ACE_TYPE_ACCESS_ALLOWED;
1679 a.flags = 0;
1680 a.size = 0; /* autogenerated */
1681 a.access_mask = 0;
1682 a.trustee = *dom_sid_parse_talloc(tctx, sid_string);
1683 torture_assert_ntstatus_ok(tctx, security_descriptor_dacl_add(sd1, &a), "");
1686 torture_assert(tctx, test_sd_set_level(tctx, p, handle, 3, sd1), "");
1688 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 2, &info_2), "");
1689 sd2 = security_descriptor_copy(tctx, info_2.info2.secdesc);
1691 torture_assert(tctx, test_security_descriptor_equal(tctx, sd1, sd2), "");
1693 return true;
1697 * wrapper call that saves original sd, runs tests, and restores sd
1700 static bool test_PrinterInfo_SD(struct torture_context *tctx,
1701 struct dcerpc_pipe *p,
1702 struct policy_handle *handle)
1704 union spoolss_PrinterInfo info;
1705 struct spoolss_SetPrinterInfo3 info3;
1706 struct spoolss_SetPrinterInfoCtr info_ctr;
1707 struct spoolss_DevmodeContainer devmode_ctr;
1708 struct sec_desc_buf secdesc_ctr;
1709 struct security_descriptor *sd;
1710 bool ret = true;
1712 /* save original sd */
1714 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 2, &info), "");
1716 sd = security_descriptor_copy(tctx, info.info2.secdesc);
1718 /* run tests */
1720 ret = test_PrinterInfo_SDs(tctx, p, handle);
1722 /* restore original sd */
1724 ZERO_STRUCT(devmode_ctr);
1725 ZERO_STRUCT(secdesc_ctr);
1727 info3.sec_desc_ptr = 0;
1729 info_ctr.level = 3;
1730 info_ctr.info.info3 = &info3;
1732 secdesc_ctr.sd = sd;
1734 torture_assert(tctx,
1735 test_SetPrinter(tctx, p, handle, &info_ctr, &devmode_ctr, &secdesc_ctr, 0), "");
1737 return ret;
1740 static bool test_ClosePrinter(struct torture_context *tctx,
1741 struct dcerpc_pipe *p,
1742 struct policy_handle *handle)
1744 NTSTATUS status;
1745 struct spoolss_ClosePrinter r;
1747 r.in.handle = handle;
1748 r.out.handle = handle;
1750 torture_comment(tctx, "Testing ClosePrinter\n");
1752 status = dcerpc_spoolss_ClosePrinter(p, tctx, &r);
1753 torture_assert_ntstatus_ok(tctx, status, "ClosePrinter failed");
1754 torture_assert_werr_ok(tctx, r.out.result, "ClosePrinter failed");
1756 return true;
1759 static bool test_GetForm(struct torture_context *tctx,
1760 struct dcerpc_pipe *p,
1761 struct policy_handle *handle,
1762 const char *form_name,
1763 uint32_t level)
1765 NTSTATUS status;
1766 struct spoolss_GetForm r;
1767 uint32_t needed;
1769 r.in.handle = handle;
1770 r.in.form_name = form_name;
1771 r.in.level = level;
1772 r.in.buffer = NULL;
1773 r.in.offered = 0;
1774 r.out.needed = &needed;
1776 torture_comment(tctx, "Testing GetForm level %d\n", r.in.level);
1778 status = dcerpc_spoolss_GetForm(p, tctx, &r);
1779 torture_assert_ntstatus_ok(tctx, status, "GetForm failed");
1781 if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
1782 DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed);
1783 data_blob_clear(&blob);
1784 r.in.buffer = &blob;
1785 r.in.offered = needed;
1786 status = dcerpc_spoolss_GetForm(p, tctx, &r);
1787 torture_assert_ntstatus_ok(tctx, status, "GetForm failed");
1789 torture_assert_werr_ok(tctx, r.out.result, "GetForm failed");
1791 torture_assert(tctx, r.out.info, "No form info returned");
1794 torture_assert_werr_ok(tctx, r.out.result, "GetForm failed");
1796 CHECK_NEEDED_SIZE_LEVEL(spoolss_FormInfo, r.out.info, r.in.level, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
1798 return true;
1801 static bool test_EnumForms(struct torture_context *tctx,
1802 struct dcerpc_pipe *p,
1803 struct policy_handle *handle, bool print_server)
1805 NTSTATUS status;
1806 struct spoolss_EnumForms r;
1807 bool ret = true;
1808 uint32_t needed;
1809 uint32_t count;
1810 uint32_t levels[] = { 1, 2 };
1811 int i;
1813 for (i=0; i<ARRAY_SIZE(levels); i++) {
1815 union spoolss_FormInfo *info;
1817 r.in.handle = handle;
1818 r.in.level = levels[i];
1819 r.in.buffer = NULL;
1820 r.in.offered = 0;
1821 r.out.needed = &needed;
1822 r.out.count = &count;
1823 r.out.info = &info;
1825 torture_comment(tctx, "Testing EnumForms level %d\n", levels[i]);
1827 status = dcerpc_spoolss_EnumForms(p, tctx, &r);
1828 torture_assert_ntstatus_ok(tctx, status, "EnumForms failed");
1830 if ((r.in.level == 2) && (W_ERROR_EQUAL(r.out.result, WERR_UNKNOWN_LEVEL))) {
1831 break;
1834 if (print_server && W_ERROR_EQUAL(r.out.result, WERR_BADFID))
1835 torture_fail(tctx, "EnumForms on the PrintServer isn't supported by test server (NT4)");
1837 if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
1838 int j;
1839 DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed);
1840 data_blob_clear(&blob);
1841 r.in.buffer = &blob;
1842 r.in.offered = needed;
1844 status = dcerpc_spoolss_EnumForms(p, tctx, &r);
1846 torture_assert(tctx, info, "No forms returned");
1848 for (j = 0; j < count; j++) {
1849 if (!print_server)
1850 ret &= test_GetForm(tctx, p, handle, info[j].info1.form_name, levels[i]);
1854 torture_assert_ntstatus_ok(tctx, status, "EnumForms failed");
1856 torture_assert_werr_ok(tctx, r.out.result, "EnumForms failed");
1858 CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumForms, info, r.in.level, count, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
1861 return true;
1864 static bool test_DeleteForm(struct torture_context *tctx,
1865 struct dcerpc_pipe *p,
1866 struct policy_handle *handle,
1867 const char *form_name)
1869 NTSTATUS status;
1870 struct spoolss_DeleteForm r;
1872 r.in.handle = handle;
1873 r.in.form_name = form_name;
1875 status = dcerpc_spoolss_DeleteForm(p, tctx, &r);
1877 torture_assert_ntstatus_ok(tctx, status, "DeleteForm failed");
1879 torture_assert_werr_ok(tctx, r.out.result, "DeleteForm failed");
1881 return true;
1884 static bool test_AddForm(struct torture_context *tctx,
1885 struct dcerpc_pipe *p,
1886 struct policy_handle *handle, bool print_server)
1888 struct spoolss_AddForm r;
1889 struct spoolss_AddFormInfo1 addform;
1890 const char *form_name = "testform3";
1891 NTSTATUS status;
1892 bool ret = true;
1894 r.in.handle = handle;
1895 r.in.level = 1;
1896 r.in.info.info1 = &addform;
1897 addform.flags = SPOOLSS_FORM_USER;
1898 addform.form_name = form_name;
1899 addform.size.width = 50;
1900 addform.size.height = 25;
1901 addform.area.left = 5;
1902 addform.area.top = 10;
1903 addform.area.right = 45;
1904 addform.area.bottom = 15;
1906 status = dcerpc_spoolss_AddForm(p, tctx, &r);
1908 torture_assert_ntstatus_ok(tctx, status, "AddForm failed");
1910 torture_assert_werr_ok(tctx, r.out.result, "AddForm failed");
1912 if (!print_server) ret &= test_GetForm(tctx, p, handle, form_name, 1);
1915 struct spoolss_SetForm sf;
1916 struct spoolss_AddFormInfo1 setform;
1918 sf.in.handle = handle;
1919 sf.in.form_name = form_name;
1920 sf.in.level = 1;
1921 sf.in.info.info1= &setform;
1922 setform.flags = addform.flags;
1923 setform.form_name = addform.form_name;
1924 setform.size = addform.size;
1925 setform.area = addform.area;
1927 setform.size.width = 1234;
1929 status = dcerpc_spoolss_SetForm(p, tctx, &sf);
1931 torture_assert_ntstatus_ok(tctx, status, "SetForm failed");
1933 torture_assert_werr_ok(tctx, r.out.result, "SetForm failed");
1936 if (!print_server) ret &= test_GetForm(tctx, p, handle, form_name, 1);
1939 struct spoolss_EnumForms e;
1940 union spoolss_FormInfo *info;
1941 uint32_t needed;
1942 uint32_t count;
1943 bool found = false;
1945 e.in.handle = handle;
1946 e.in.level = 1;
1947 e.in.buffer = NULL;
1948 e.in.offered = 0;
1949 e.out.needed = &needed;
1950 e.out.count = &count;
1951 e.out.info = &info;
1953 torture_comment(tctx, "Testing EnumForms level 1\n");
1955 status = dcerpc_spoolss_EnumForms(p, tctx, &e);
1956 torture_assert_ntstatus_ok(tctx, status, "EnumForms failed");
1958 if (print_server && W_ERROR_EQUAL(e.out.result, WERR_BADFID))
1959 torture_fail(tctx, "EnumForms on the PrintServer isn't supported by test server (NT4)");
1961 if (W_ERROR_EQUAL(e.out.result, WERR_INSUFFICIENT_BUFFER)) {
1962 int j;
1963 DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed);
1964 data_blob_clear(&blob);
1965 e.in.buffer = &blob;
1966 e.in.offered = needed;
1968 status = dcerpc_spoolss_EnumForms(p, tctx, &e);
1970 torture_assert(tctx, info, "No forms returned");
1972 for (j = 0; j < count; j++) {
1973 if (strequal(form_name, info[j].info1.form_name)) {
1974 found = true;
1975 break;
1979 torture_assert(tctx, found, "Newly added form not found in enum call");
1982 if (!test_DeleteForm(tctx, p, handle, form_name)) {
1983 ret = false;
1986 return ret;
1989 static bool test_EnumPorts_old(struct torture_context *tctx,
1990 struct dcerpc_pipe *p)
1992 NTSTATUS status;
1993 struct spoolss_EnumPorts r;
1994 uint32_t needed;
1995 uint32_t count;
1996 union spoolss_PortInfo *info;
1998 r.in.servername = talloc_asprintf(tctx, "\\\\%s",
1999 dcerpc_server_name(p));
2000 r.in.level = 2;
2001 r.in.buffer = NULL;
2002 r.in.offered = 0;
2003 r.out.needed = &needed;
2004 r.out.count = &count;
2005 r.out.info = &info;
2007 torture_comment(tctx, "Testing EnumPorts\n");
2009 status = dcerpc_spoolss_EnumPorts(p, tctx, &r);
2011 torture_assert_ntstatus_ok(tctx, status, "EnumPorts failed");
2013 if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
2014 DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed);
2015 data_blob_clear(&blob);
2016 r.in.buffer = &blob;
2017 r.in.offered = needed;
2019 status = dcerpc_spoolss_EnumPorts(p, tctx, &r);
2020 torture_assert_ntstatus_ok(tctx, status, "EnumPorts failed");
2021 torture_assert_werr_ok(tctx, r.out.result, "EnumPorts failed");
2023 torture_assert(tctx, info, "No ports returned");
2026 torture_assert_werr_ok(tctx, r.out.result, "EnumPorts failed");
2028 CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumPorts, info, 2, count, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
2030 return true;
2033 static bool test_AddPort(struct torture_context *tctx,
2034 struct dcerpc_pipe *p)
2036 NTSTATUS status;
2037 struct spoolss_AddPort r;
2039 r.in.server_name = talloc_asprintf(tctx, "\\\\%s",
2040 dcerpc_server_name(p));
2041 r.in.unknown = 0;
2042 r.in.monitor_name = "foo";
2044 torture_comment(tctx, "Testing AddPort\n");
2046 status = dcerpc_spoolss_AddPort(p, tctx, &r);
2048 torture_assert_ntstatus_ok(tctx, status, "AddPort failed");
2050 /* win2k3 returns WERR_NOT_SUPPORTED */
2052 #if 0
2054 if (!W_ERROR_IS_OK(r.out.result)) {
2055 printf("AddPort failed - %s\n", win_errstr(r.out.result));
2056 return false;
2059 #endif
2061 return true;
2064 static bool test_GetJob(struct torture_context *tctx,
2065 struct dcerpc_pipe *p,
2066 struct policy_handle *handle, uint32_t job_id)
2068 NTSTATUS status;
2069 struct spoolss_GetJob r;
2070 union spoolss_JobInfo info;
2071 uint32_t needed;
2072 uint32_t levels[] = {1, 2 /* 3, 4 */};
2073 uint32_t i;
2075 r.in.handle = handle;
2076 r.in.job_id = job_id;
2077 r.in.level = 0;
2078 r.in.buffer = NULL;
2079 r.in.offered = 0;
2080 r.out.needed = &needed;
2081 r.out.info = &info;
2083 torture_comment(tctx, "Testing GetJob level %d\n", r.in.level);
2085 status = dcerpc_spoolss_GetJob(p, tctx, &r);
2086 torture_assert_werr_equal(tctx, r.out.result, WERR_UNKNOWN_LEVEL, "Unexpected return code");
2088 for (i = 0; i < ARRAY_SIZE(levels); i++) {
2090 torture_comment(tctx, "Testing GetJob level %d\n", r.in.level);
2092 needed = 0;
2094 r.in.level = levels[i];
2095 r.in.offered = 0;
2096 r.in.buffer = NULL;
2098 status = dcerpc_spoolss_GetJob(p, tctx, &r);
2099 torture_assert_ntstatus_ok(tctx, status, "GetJob failed");
2101 if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
2102 DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed);
2103 data_blob_clear(&blob);
2104 r.in.buffer = &blob;
2105 r.in.offered = needed;
2107 status = dcerpc_spoolss_GetJob(p, tctx, &r);
2108 torture_assert_ntstatus_ok(tctx, status, "GetJob failed");
2111 torture_assert(tctx, r.out.info, "No job info returned");
2112 torture_assert_werr_ok(tctx, r.out.result, "GetJob failed");
2114 CHECK_NEEDED_SIZE_LEVEL(spoolss_JobInfo, r.out.info, r.in.level, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
2117 return true;
2120 static bool test_SetJob(struct torture_context *tctx,
2121 struct dcerpc_pipe *p,
2122 struct policy_handle *handle, uint32_t job_id,
2123 enum spoolss_JobControl command)
2125 NTSTATUS status;
2126 struct spoolss_SetJob r;
2128 r.in.handle = handle;
2129 r.in.job_id = job_id;
2130 r.in.ctr = NULL;
2131 r.in.command = command;
2133 switch (command) {
2134 case SPOOLSS_JOB_CONTROL_PAUSE:
2135 torture_comment(tctx, "Testing SetJob: SPOOLSS_JOB_CONTROL_PAUSE\n");
2136 break;
2137 case SPOOLSS_JOB_CONTROL_RESUME:
2138 torture_comment(tctx, "Testing SetJob: SPOOLSS_JOB_CONTROL_RESUME\n");
2139 break;
2140 case SPOOLSS_JOB_CONTROL_CANCEL:
2141 torture_comment(tctx, "Testing SetJob: SPOOLSS_JOB_CONTROL_CANCEL\n");
2142 break;
2143 case SPOOLSS_JOB_CONTROL_RESTART:
2144 torture_comment(tctx, "Testing SetJob: SPOOLSS_JOB_CONTROL_RESTART\n");
2145 break;
2146 case SPOOLSS_JOB_CONTROL_DELETE:
2147 torture_comment(tctx, "Testing SetJob: SPOOLSS_JOB_CONTROL_DELETE\n");
2148 break;
2149 case SPOOLSS_JOB_CONTROL_SEND_TO_PRINTER:
2150 torture_comment(tctx, "Testing SetJob: SPOOLSS_JOB_CONTROL_SEND_TO_PRINTER\n");
2151 break;
2152 case SPOOLSS_JOB_CONTROL_LAST_PAGE_EJECTED:
2153 torture_comment(tctx, "Testing SetJob: SPOOLSS_JOB_CONTROL_LAST_PAGE_EJECTED\n");
2154 break;
2155 case SPOOLSS_JOB_CONTROL_RETAIN:
2156 torture_comment(tctx, "Testing SetJob: SPOOLSS_JOB_CONTROL_RETAIN\n");
2157 break;
2158 case SPOOLSS_JOB_CONTROL_RELEASE:
2159 torture_comment(tctx, "Testing SetJob: SPOOLSS_JOB_CONTROL_RELEASE\n");
2160 break;
2161 default:
2162 torture_comment(tctx, "Testing SetJob\n");
2163 break;
2166 status = dcerpc_spoolss_SetJob(p, tctx, &r);
2167 torture_assert_ntstatus_ok(tctx, status, "SetJob failed");
2168 torture_assert_werr_ok(tctx, r.out.result, "SetJob failed");
2170 return true;
2173 static bool test_AddJob(struct torture_context *tctx,
2174 struct dcerpc_pipe *p,
2175 struct policy_handle *handle)
2177 NTSTATUS status;
2178 struct spoolss_AddJob r;
2179 uint32_t needed;
2181 r.in.level = 0;
2182 r.in.handle = handle;
2183 r.in.offered = 0;
2184 r.out.needed = &needed;
2185 r.in.buffer = r.out.buffer = NULL;
2187 torture_comment(tctx, "Testing AddJob\n");
2189 status = dcerpc_spoolss_AddJob(p, tctx, &r);
2190 torture_assert_werr_equal(tctx, r.out.result, WERR_UNKNOWN_LEVEL, "AddJob failed");
2192 r.in.level = 1;
2194 status = dcerpc_spoolss_AddJob(p, tctx, &r);
2195 torture_assert_werr_equal(tctx, r.out.result, WERR_INVALID_PARAM, "AddJob failed");
2197 return true;
2201 static bool test_EnumJobs(struct torture_context *tctx,
2202 struct dcerpc_pipe *p,
2203 struct policy_handle *handle)
2205 NTSTATUS status;
2206 struct spoolss_EnumJobs r;
2207 uint32_t needed;
2208 uint32_t count;
2209 union spoolss_JobInfo *info;
2211 r.in.handle = handle;
2212 r.in.firstjob = 0;
2213 r.in.numjobs = 0xffffffff;
2214 r.in.level = 1;
2215 r.in.buffer = NULL;
2216 r.in.offered = 0;
2217 r.out.needed = &needed;
2218 r.out.count = &count;
2219 r.out.info = &info;
2221 torture_comment(tctx, "Testing EnumJobs\n");
2223 status = dcerpc_spoolss_EnumJobs(p, tctx, &r);
2225 torture_assert_ntstatus_ok(tctx, status, "EnumJobs failed");
2227 if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
2228 int j;
2229 DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed);
2230 data_blob_clear(&blob);
2231 r.in.buffer = &blob;
2232 r.in.offered = needed;
2234 status = dcerpc_spoolss_EnumJobs(p, tctx, &r);
2236 torture_assert_ntstatus_ok(tctx, status, "EnumJobs failed");
2237 torture_assert_werr_ok(tctx, r.out.result, "EnumJobs failed");
2238 torture_assert(tctx, info, "No jobs returned");
2240 CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumJobs, *r.out.info, r.in.level, count, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
2242 for (j = 0; j < count; j++) {
2244 torture_assert(tctx, test_GetJob(tctx, p, handle, info[j].info1.job_id),
2245 "failed to call test_GetJob");
2247 /* FIXME - gd */
2248 if (!torture_setting_bool(tctx, "samba3", false)) {
2249 test_SetJob(tctx, p, handle, info[j].info1.job_id, SPOOLSS_JOB_CONTROL_PAUSE);
2250 test_SetJob(tctx, p, handle, info[j].info1.job_id, SPOOLSS_JOB_CONTROL_RESUME);
2254 } else {
2255 torture_assert_werr_ok(tctx, r.out.result, "EnumJobs failed");
2258 return true;
2261 static bool test_DoPrintTest(struct torture_context *tctx,
2262 struct dcerpc_pipe *p,
2263 struct policy_handle *handle)
2265 bool ret = true;
2266 NTSTATUS status;
2267 struct spoolss_StartDocPrinter s;
2268 struct spoolss_DocumentInfo1 info1;
2269 struct spoolss_StartPagePrinter sp;
2270 struct spoolss_WritePrinter w;
2271 struct spoolss_EndPagePrinter ep;
2272 struct spoolss_EndDocPrinter e;
2273 int i;
2274 uint32_t job_id;
2275 uint32_t num_written;
2277 torture_comment(tctx, "Testing StartDocPrinter\n");
2279 s.in.handle = handle;
2280 s.in.level = 1;
2281 s.in.info.info1 = &info1;
2282 s.out.job_id = &job_id;
2283 info1.document_name = "TorturePrintJob";
2284 info1.output_file = NULL;
2285 info1.datatype = "RAW";
2287 status = dcerpc_spoolss_StartDocPrinter(p, tctx, &s);
2288 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_StartDocPrinter failed");
2289 torture_assert_werr_ok(tctx, s.out.result, "StartDocPrinter failed");
2291 for (i=1; i < 4; i++) {
2292 torture_comment(tctx, "Testing StartPagePrinter: Page[%d]\n", i);
2294 sp.in.handle = handle;
2296 status = dcerpc_spoolss_StartPagePrinter(p, tctx, &sp);
2297 torture_assert_ntstatus_ok(tctx, status,
2298 "dcerpc_spoolss_StartPagePrinter failed");
2299 torture_assert_werr_ok(tctx, sp.out.result, "StartPagePrinter failed");
2301 torture_comment(tctx, "Testing WritePrinter: Page[%d]\n", i);
2303 w.in.handle = handle;
2304 w.in.data = data_blob_string_const(talloc_asprintf(tctx,"TortureTestPage: %d\nData\n",i));
2305 w.out.num_written = &num_written;
2307 status = dcerpc_spoolss_WritePrinter(p, tctx, &w);
2308 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_WritePrinter failed");
2309 torture_assert_werr_ok(tctx, w.out.result, "WritePrinter failed");
2311 torture_comment(tctx, "Testing EndPagePrinter: Page[%d]\n", i);
2313 ep.in.handle = handle;
2315 status = dcerpc_spoolss_EndPagePrinter(p, tctx, &ep);
2316 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EndPagePrinter failed");
2317 torture_assert_werr_ok(tctx, ep.out.result, "EndPagePrinter failed");
2320 torture_comment(tctx, "Testing EndDocPrinter\n");
2322 e.in.handle = handle;
2324 status = dcerpc_spoolss_EndDocPrinter(p, tctx, &e);
2325 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EndDocPrinter failed");
2326 torture_assert_werr_ok(tctx, e.out.result, "EndDocPrinter failed");
2328 ret &= test_AddJob(tctx, p, handle);
2329 ret &= test_EnumJobs(tctx, p, handle);
2331 ret &= test_SetJob(tctx, p, handle, job_id, SPOOLSS_JOB_CONTROL_DELETE);
2333 return ret;
2336 static bool test_PausePrinter(struct torture_context *tctx,
2337 struct dcerpc_pipe *p,
2338 struct policy_handle *handle)
2340 NTSTATUS status;
2341 struct spoolss_SetPrinter r;
2342 struct spoolss_SetPrinterInfoCtr info_ctr;
2343 struct spoolss_DevmodeContainer devmode_ctr;
2344 struct sec_desc_buf secdesc_ctr;
2346 info_ctr.level = 0;
2347 info_ctr.info.info0 = NULL;
2349 ZERO_STRUCT(devmode_ctr);
2350 ZERO_STRUCT(secdesc_ctr);
2352 r.in.handle = handle;
2353 r.in.info_ctr = &info_ctr;
2354 r.in.devmode_ctr = &devmode_ctr;
2355 r.in.secdesc_ctr = &secdesc_ctr;
2356 r.in.command = SPOOLSS_PRINTER_CONTROL_PAUSE;
2358 torture_comment(tctx, "Testing SetPrinter: SPOOLSS_PRINTER_CONTROL_PAUSE\n");
2360 status = dcerpc_spoolss_SetPrinter(p, tctx, &r);
2362 torture_assert_ntstatus_ok(tctx, status, "SetPrinter failed");
2364 torture_assert_werr_ok(tctx, r.out.result, "SetPrinter failed");
2366 return true;
2369 static bool test_ResumePrinter(struct torture_context *tctx,
2370 struct dcerpc_pipe *p,
2371 struct policy_handle *handle)
2373 NTSTATUS status;
2374 struct spoolss_SetPrinter r;
2375 struct spoolss_SetPrinterInfoCtr info_ctr;
2376 struct spoolss_DevmodeContainer devmode_ctr;
2377 struct sec_desc_buf secdesc_ctr;
2379 info_ctr.level = 0;
2380 info_ctr.info.info0 = NULL;
2382 ZERO_STRUCT(devmode_ctr);
2383 ZERO_STRUCT(secdesc_ctr);
2385 r.in.handle = handle;
2386 r.in.info_ctr = &info_ctr;
2387 r.in.devmode_ctr = &devmode_ctr;
2388 r.in.secdesc_ctr = &secdesc_ctr;
2389 r.in.command = SPOOLSS_PRINTER_CONTROL_RESUME;
2391 torture_comment(tctx, "Testing SetPrinter: SPOOLSS_PRINTER_CONTROL_RESUME\n");
2393 status = dcerpc_spoolss_SetPrinter(p, tctx, &r);
2395 torture_assert_ntstatus_ok(tctx, status, "SetPrinter failed");
2397 torture_assert_werr_ok(tctx, r.out.result, "SetPrinter failed");
2399 return true;
2402 static bool test_GetPrinterData(struct torture_context *tctx,
2403 struct dcerpc_pipe *p,
2404 struct policy_handle *handle,
2405 const char *value_name,
2406 enum winreg_Type *type_p,
2407 union spoolss_PrinterData *data_p)
2409 NTSTATUS status;
2410 struct spoolss_GetPrinterData r;
2411 uint32_t needed;
2412 enum winreg_Type type;
2413 union spoolss_PrinterData data;
2415 r.in.handle = handle;
2416 r.in.value_name = value_name;
2417 r.in.offered = 0;
2418 r.out.needed = &needed;
2419 r.out.type = &type;
2420 r.out.data = &data;
2422 torture_comment(tctx, "Testing GetPrinterData(%s)\n", r.in.value_name);
2424 status = dcerpc_spoolss_GetPrinterData(p, tctx, &r);
2425 torture_assert_ntstatus_ok(tctx, status, "GetPrinterData failed");
2427 if (W_ERROR_EQUAL(r.out.result, WERR_MORE_DATA)) {
2428 r.in.offered = needed;
2430 status = dcerpc_spoolss_GetPrinterData(p, tctx, &r);
2431 torture_assert_ntstatus_ok(tctx, status, "GetPrinterData failed");
2434 torture_assert_werr_ok(tctx, r.out.result,
2435 talloc_asprintf(tctx, "GetPrinterData(%s) failed", r.in.value_name));
2437 CHECK_NEEDED_SIZE_LEVEL(spoolss_PrinterData, &data, type, lp_iconv_convenience(tctx->lp_ctx), needed, 1);
2439 if (type_p) {
2440 *type_p = type;
2443 if (data_p) {
2444 *data_p = data;
2447 return true;
2450 static bool test_GetPrinterDataEx(struct torture_context *tctx,
2451 struct dcerpc_pipe *p,
2452 struct policy_handle *handle,
2453 const char *key_name,
2454 const char *value_name,
2455 enum winreg_Type *type_p,
2456 union spoolss_PrinterData *data_p)
2458 NTSTATUS status;
2459 struct spoolss_GetPrinterDataEx r;
2460 enum winreg_Type type;
2461 uint32_t needed;
2462 union spoolss_PrinterData data;
2464 r.in.handle = handle;
2465 r.in.key_name = key_name;
2466 r.in.value_name = value_name;
2467 r.in.offered = 0;
2468 r.out.type = &type;
2469 r.out.needed = &needed;
2470 r.out.data = &data;
2472 torture_comment(tctx, "Testing GetPrinterDataEx(%s - %s)\n",
2473 r.in.key_name, r.in.value_name);
2475 status = dcerpc_spoolss_GetPrinterDataEx(p, tctx, &r);
2476 if (!NT_STATUS_IS_OK(status)) {
2477 if (NT_STATUS_EQUAL(status,NT_STATUS_NET_WRITE_FAULT) &&
2478 p->last_fault_code == DCERPC_FAULT_OP_RNG_ERROR) {
2479 torture_skip(tctx, "GetPrinterDataEx not supported by server\n");
2481 torture_assert_ntstatus_ok(tctx, status, "GetPrinterDataEx failed");
2484 if (W_ERROR_EQUAL(r.out.result, WERR_MORE_DATA)) {
2485 r.in.offered = needed;
2486 status = dcerpc_spoolss_GetPrinterDataEx(p, tctx, &r);
2487 torture_assert_ntstatus_ok(tctx, status, "GetPrinterDataEx failed");
2490 torture_assert_werr_ok(tctx, r.out.result,
2491 talloc_asprintf(tctx, "GetPrinterDataEx(%s - %s) failed", r.in.key_name, r.in.value_name));
2493 CHECK_NEEDED_SIZE_LEVEL(spoolss_PrinterData, &data, type, lp_iconv_convenience(tctx->lp_ctx), needed, 1);
2495 if (type_p) {
2496 *type_p = type;
2499 if (data_p) {
2500 *data_p = data;
2503 return true;
2506 static bool test_GetPrinterData_list(struct torture_context *tctx,
2507 struct dcerpc_pipe *p,
2508 struct policy_handle *handle)
2510 const char *list[] = {
2511 "W3SvcInstalled",
2512 "BeepEnabled",
2513 "EventLog",
2514 /* "NetPopup", not on w2k8 */
2515 /* "NetPopupToComputer", not on w2k8 */
2516 "MajorVersion",
2517 "MinorVersion",
2518 "DefaultSpoolDirectory",
2519 "Architecture",
2520 "DsPresent",
2521 "OSVersion",
2522 /* "OSVersionEx", not on s3 */
2523 "DNSMachineName"
2525 int i;
2527 for (i=0; i < ARRAY_SIZE(list); i++) {
2528 enum winreg_Type type, type_ex;
2529 union spoolss_PrinterData data, data_ex;
2531 torture_assert(tctx, test_GetPrinterData(tctx, p, handle, list[i], &type, &data),
2532 talloc_asprintf(tctx, "GetPrinterData failed on %s\n", list[i]));
2533 torture_assert(tctx, test_GetPrinterDataEx(tctx, p, handle, "random_string", list[i], &type_ex, &data_ex),
2534 talloc_asprintf(tctx, "GetPrinterDataEx failed on %s\n", list[i]));
2535 torture_assert_int_equal(tctx, type, type_ex, "type mismatch");
2536 switch (type) {
2537 case REG_SZ:
2538 torture_assert_str_equal(tctx, data.string, data_ex.string, "REG_SZ mismatch");
2539 break;
2540 case REG_DWORD:
2541 torture_assert_int_equal(tctx, data.value, data_ex.value, "REG_DWORD mismatch");
2542 break;
2543 case REG_BINARY:
2544 torture_assert_data_blob_equal(tctx, data.binary, data_ex.binary, "REG_BINARY mismatch");
2545 break;
2546 default:
2547 break;
2551 return true;
2554 static bool test_EnumPrinterData(struct torture_context *tctx, struct dcerpc_pipe *p,
2555 struct policy_handle *handle)
2557 NTSTATUS status;
2558 struct spoolss_EnumPrinterData r;
2560 ZERO_STRUCT(r);
2561 r.in.handle = handle;
2562 r.in.enum_index = 0;
2564 do {
2565 uint32_t value_size = 0;
2566 uint32_t data_size = 0;
2567 enum winreg_Type type = 0;
2569 r.in.value_offered = value_size;
2570 r.out.value_needed = &value_size;
2571 r.in.data_offered = data_size;
2572 r.out.data_needed = &data_size;
2574 r.out.type = &type;
2575 r.out.data = talloc_zero_array(tctx, uint8_t, 0);
2577 torture_comment(tctx, "Testing EnumPrinterData\n");
2579 status = dcerpc_spoolss_EnumPrinterData(p, tctx, &r);
2581 torture_assert_ntstatus_ok(tctx, status, "EnumPrinterData failed");
2582 if (W_ERROR_EQUAL(r.out.result, WERR_NO_MORE_ITEMS)) {
2583 break;
2585 torture_assert_werr_ok(tctx, r.out.result, "EnumPrinterData");
2587 r.in.value_offered = value_size;
2588 r.out.value_name = talloc_zero_array(tctx, const char, value_size);
2589 r.in.data_offered = data_size;
2590 r.out.data = talloc_zero_array(tctx, uint8_t, data_size);
2592 status = dcerpc_spoolss_EnumPrinterData(p, tctx, &r);
2594 torture_assert_ntstatus_ok(tctx, status, "EnumPrinterData failed");
2595 if (W_ERROR_EQUAL(r.out.result, WERR_NO_MORE_ITEMS)) {
2596 break;
2599 torture_assert_werr_ok(tctx, r.out.result, "EnumPrinterData failed");
2601 torture_assert(tctx, test_GetPrinterData(tctx, p, handle, r.out.value_name, NULL, NULL),
2602 talloc_asprintf(tctx, "failed to call GetPrinterData for %s\n", r.out.value_name));
2604 torture_assert(tctx, test_GetPrinterDataEx(tctx, p, handle, "PrinterDriverData", r.out.value_name, NULL, NULL),
2605 talloc_asprintf(tctx, "failed to call GetPrinterDataEx on PrinterDriverData for %s\n", r.out.value_name));
2607 r.in.enum_index++;
2609 } while (W_ERROR_IS_OK(r.out.result));
2611 return true;
2614 static bool test_EnumPrinterDataEx(struct torture_context *tctx,
2615 struct dcerpc_pipe *p,
2616 struct policy_handle *handle,
2617 const char *key_name)
2619 struct spoolss_EnumPrinterDataEx r;
2620 struct spoolss_PrinterEnumValues *info;
2621 uint32_t needed;
2622 uint32_t count;
2624 r.in.handle = handle;
2625 r.in.key_name = key_name;
2626 r.in.offered = 0;
2627 r.out.needed = &needed;
2628 r.out.count = &count;
2629 r.out.info = &info;
2631 torture_comment(tctx, "Testing EnumPrinterDataEx(%s)\n", key_name);
2633 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_EnumPrinterDataEx(p, tctx, &r),
2634 "EnumPrinterDataEx failed");
2635 if (W_ERROR_EQUAL(r.out.result, WERR_MORE_DATA)) {
2636 r.in.offered = needed;
2637 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_EnumPrinterDataEx(p, tctx, &r),
2638 "EnumPrinterDataEx failed");
2641 torture_assert_werr_ok(tctx, r.out.result, "EnumPrinterDataEx failed");
2643 CHECK_NEEDED_SIZE_ENUM(spoolss_EnumPrinterDataEx, info, count, lp_iconv_convenience(tctx->lp_ctx), needed, 1);
2645 return true;
2649 static bool test_DeletePrinterData(struct torture_context *tctx,
2650 struct dcerpc_pipe *p,
2651 struct policy_handle *handle,
2652 const char *value_name)
2654 NTSTATUS status;
2655 struct spoolss_DeletePrinterData r;
2657 r.in.handle = handle;
2658 r.in.value_name = value_name;
2660 torture_comment(tctx, "Testing DeletePrinterData(%s)\n",
2661 r.in.value_name);
2663 status = dcerpc_spoolss_DeletePrinterData(p, tctx, &r);
2665 torture_assert_ntstatus_ok(tctx, status, "DeletePrinterData failed");
2666 torture_assert_werr_ok(tctx, r.out.result, "DeletePrinterData failed");
2668 return true;
2671 static bool test_DeletePrinterDataEx(struct torture_context *tctx,
2672 struct dcerpc_pipe *p,
2673 struct policy_handle *handle,
2674 const char *key_name,
2675 const char *value_name)
2677 struct spoolss_DeletePrinterDataEx r;
2679 r.in.handle = handle;
2680 r.in.key_name = key_name;
2681 r.in.value_name = value_name;
2683 torture_comment(tctx, "Testing DeletePrinterDataEx(%s - %s)\n",
2684 r.in.key_name, r.in.value_name);
2686 torture_assert_ntstatus_ok(tctx,
2687 dcerpc_spoolss_DeletePrinterDataEx(p, tctx, &r),
2688 "DeletePrinterDataEx failed");
2689 torture_assert_werr_ok(tctx, r.out.result,
2690 "DeletePrinterDataEx failed");
2692 return true;
2695 static bool test_DeletePrinterKey(struct torture_context *tctx,
2696 struct dcerpc_pipe *p,
2697 struct policy_handle *handle,
2698 const char *key_name)
2700 struct spoolss_DeletePrinterKey r;
2702 r.in.handle = handle;
2703 r.in.key_name = key_name;
2705 torture_comment(tctx, "Testing DeletePrinterKey(%s)\n", r.in.key_name);
2707 if (strequal(key_name, "") && !torture_setting_bool(tctx, "dangerous", false)) {
2708 torture_skip(tctx, "not wiping out printer registry - enable dangerous tests to use\n");
2709 return true;
2712 torture_assert_ntstatus_ok(tctx,
2713 dcerpc_spoolss_DeletePrinterKey(p, tctx, &r),
2714 "DeletePrinterKey failed");
2715 torture_assert_werr_ok(tctx, r.out.result,
2716 "DeletePrinterKey failed");
2718 return true;
2721 static bool test_SetPrinterData(struct torture_context *tctx,
2722 struct dcerpc_pipe *p,
2723 struct policy_handle *handle)
2725 NTSTATUS status;
2726 struct spoolss_SetPrinterData r;
2727 const char *values[] = {
2728 "spootyfoot",
2729 "spooty\\foot",
2730 #if 0
2731 /* FIXME: not working with s3 atm. */
2732 "spooty,foot",
2733 "spooty,fo,ot",
2734 #endif
2735 "spooty foot",
2736 #if 0
2737 /* FIXME: not working with s3 atm. */
2738 "spooty\\fo,ot",
2739 "spooty,fo\\ot"
2740 #endif
2742 int i;
2744 for (i=0; i < ARRAY_SIZE(values); i++) {
2746 enum winreg_Type type;
2747 union spoolss_PrinterData data;
2749 r.in.handle = handle;
2750 r.in.value_name = values[i];
2751 r.in.type = REG_SZ;
2752 r.in.data.string = "dog";
2754 torture_comment(tctx, "Testing SetPrinterData(%s)\n",
2755 r.in.value_name);
2757 status = dcerpc_spoolss_SetPrinterData(p, tctx, &r);
2759 torture_assert_ntstatus_ok(tctx, status, "SetPrinterData failed");
2760 torture_assert_werr_ok(tctx, r.out.result, "SetPrinterData failed");
2762 if (!test_GetPrinterData(tctx, p, handle, r.in.value_name, &type, &data)) {
2763 return false;
2766 torture_assert_int_equal(tctx, r.in.type, type, "type mismatch");
2767 torture_assert_str_equal(tctx, r.in.data.string, data.string, "data mismatch");
2769 if (!test_DeletePrinterData(tctx, p, handle, r.in.value_name)) {
2770 return false;
2774 return true;
2777 static bool test_EnumPrinterKey(struct torture_context *tctx,
2778 struct dcerpc_pipe *p,
2779 struct policy_handle *handle,
2780 const char *key_name,
2781 const char ***array);
2783 static bool test_SetPrinterDataEx(struct torture_context *tctx,
2784 struct dcerpc_pipe *p,
2785 struct policy_handle *handle)
2787 NTSTATUS status;
2788 struct spoolss_SetPrinterDataEx r;
2789 const char *value_name = "dog";
2790 const char *keys[] = {
2791 "torturedataex",
2792 "torture data ex",
2793 #if 0
2794 /* FIXME: not working with s3 atm. */
2795 "torturedataex_with_subkey\\subkey",
2796 "torturedataex_with_subkey\\subkey:0",
2797 "torturedataex_with_subkey\\subkey:1",
2798 "torturedataex_with_subkey\\subkey\\subsubkey",
2799 "torturedataex_with_subkey\\subkey\\subsubkey:0",
2800 "torturedataex_with_subkey\\subkey\\subsubkey:1",
2801 #endif
2802 "torture,data",
2803 #if 0
2804 /* FIXME: not working with s3 atm. */
2806 "torture,data,ex",
2807 "torture,data\\ex",
2808 "torture\\data,ex"
2809 #endif
2811 int i;
2812 DATA_BLOB blob = data_blob_string_const("catfoobar");
2815 for (i=0; i < ARRAY_SIZE(keys); i++) {
2817 char *c;
2818 const char *key;
2819 enum winreg_Type type;
2820 const char **subkeys;
2821 union spoolss_PrinterData data;
2823 r.in.handle = handle;
2824 r.in.key_name = keys[i];
2825 r.in.value_name = value_name;
2826 r.in.type = REG_BINARY;
2827 r.in.data.binary = blob;
2829 torture_comment(tctx, "Testing SetPrinterDataEx(%s - %s)\n", r.in.key_name, value_name);
2831 status = dcerpc_spoolss_SetPrinterDataEx(p, tctx, &r);
2833 torture_assert_ntstatus_ok(tctx, status, "SetPrinterDataEx failed");
2834 torture_assert_werr_ok(tctx, r.out.result, "SetPrinterDataEx failed");
2836 key = talloc_strdup(tctx, r.in.key_name);
2838 if (!test_GetPrinterDataEx(tctx, p, handle, r.in.key_name, value_name, &type, &data)) {
2839 return false;
2842 torture_assert_int_equal(tctx, r.in.type, type, "type mismatch");
2843 torture_assert_data_blob_equal(tctx, blob, data.binary, "data mismatch");
2845 if (!test_EnumPrinterDataEx(tctx, p, handle, r.in.key_name)) {
2846 return false;
2849 if (!test_DeletePrinterDataEx(tctx, p, handle, r.in.key_name, value_name)) {
2850 return false;
2853 c = strchr(key, '\\');
2854 if (c) {
2855 int i;
2857 /* we have subkeys */
2859 *c = 0;
2861 if (!test_EnumPrinterKey(tctx, p, handle, key, &subkeys)) {
2862 return false;
2865 for (i=0; subkeys && subkeys[i]; i++) {
2867 const char *current_key = talloc_asprintf(tctx, "%s\\%s", key, subkeys[i]);
2869 if (!test_DeletePrinterKey(tctx, p, handle, current_key)) {
2870 return false;
2874 if (!test_DeletePrinterKey(tctx, p, handle, key)) {
2875 return false;
2878 } else {
2879 if (!test_DeletePrinterKey(tctx, p, handle, key)) {
2880 return false;
2885 return true;
2888 static bool test_GetChangeID_PrinterData(struct torture_context *tctx,
2889 struct dcerpc_pipe *p,
2890 struct policy_handle *handle,
2891 uint32_t *change_id)
2893 enum winreg_Type type;
2894 union spoolss_PrinterData data;
2896 torture_assert(tctx,
2897 test_GetPrinterData(tctx, p, handle, "ChangeID", &type, &data),
2898 "failed to call GetPrinterData");
2900 torture_assert(tctx, type == REG_DWORD, "unexpected type");
2902 *change_id = data.value;
2904 return true;
2907 static bool test_GetChangeID_PrinterDataEx(struct torture_context *tctx,
2908 struct dcerpc_pipe *p,
2909 struct policy_handle *handle,
2910 uint32_t *change_id)
2912 enum winreg_Type type;
2913 union spoolss_PrinterData data;
2915 torture_assert(tctx,
2916 test_GetPrinterDataEx(tctx, p, handle, "PrinterDriverData", "ChangeID", &type, &data),
2917 "failed to call GetPrinterData");
2919 torture_assert(tctx, type == REG_DWORD, "unexpected type");
2921 *change_id = data.value;
2923 return true;
2926 static bool test_GetChangeID_PrinterInfo(struct torture_context *tctx,
2927 struct dcerpc_pipe *p,
2928 struct policy_handle *handle,
2929 uint32_t *change_id)
2931 union spoolss_PrinterInfo info;
2933 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 0, &info),
2934 "failed to query Printer level 0");
2936 *change_id = info.info0.change_id;
2938 return true;
2941 static bool test_ChangeID(struct torture_context *tctx,
2942 struct dcerpc_pipe *p,
2943 struct policy_handle *handle)
2945 uint32_t change_id, change_id_ex, change_id_info;
2946 uint32_t change_id2, change_id_ex2, change_id_info2;
2947 union spoolss_PrinterInfo info;
2948 const char *comment;
2951 torture_comment(tctx, "Testing ChangeID: id change test #1\n");
2953 torture_assert(tctx, test_GetChangeID_PrinterData(tctx, p, handle, &change_id),
2954 "failed to query for ChangeID");
2955 torture_assert(tctx, test_GetChangeID_PrinterDataEx(tctx, p, handle, &change_id_ex),
2956 "failed to query for ChangeID");
2957 torture_assert(tctx, test_GetChangeID_PrinterInfo(tctx, p, handle, &change_id_info),
2958 "failed to query for ChangeID");
2960 torture_assert_int_equal(tctx, change_id, change_id_ex,
2961 "change_ids should all be equal");
2962 torture_assert_int_equal(tctx, change_id_ex, change_id_info,
2963 "change_ids should all be equal");
2966 torture_comment(tctx, "Testing ChangeID: id change test #2\n");
2968 torture_assert(tctx, test_GetChangeID_PrinterData(tctx, p, handle, &change_id),
2969 "failed to query for ChangeID");
2970 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 2, &info),
2971 "failed to query Printer level 2");
2972 torture_assert(tctx, test_GetChangeID_PrinterDataEx(tctx, p, handle, &change_id_ex),
2973 "failed to query for ChangeID");
2974 torture_assert(tctx, test_GetChangeID_PrinterInfo(tctx, p, handle, &change_id_info),
2975 "failed to query for ChangeID");
2976 torture_assert_int_equal(tctx, change_id, change_id_ex,
2977 "change_id should not have changed");
2978 torture_assert_int_equal(tctx, change_id_ex, change_id_info,
2979 "change_id should not have changed");
2982 torture_comment(tctx, "Testing ChangeID: id change test #3\n");
2984 torture_assert(tctx, test_GetChangeID_PrinterData(tctx, p, handle, &change_id),
2985 "failed to query for ChangeID");
2986 torture_assert(tctx, test_GetChangeID_PrinterDataEx(tctx, p, handle, &change_id_ex),
2987 "failed to query for ChangeID");
2988 torture_assert(tctx, test_GetChangeID_PrinterInfo(tctx, p, handle, &change_id_info),
2989 "failed to query for ChangeID");
2990 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 2, &info),
2991 "failed to query Printer level 2");
2992 comment = talloc_strdup(tctx, info.info2.comment);
2995 struct spoolss_SetPrinterInfoCtr info_ctr;
2996 struct spoolss_DevmodeContainer devmode_ctr;
2997 struct sec_desc_buf secdesc_ctr;
2998 struct spoolss_SetPrinterInfo2 info2;
3000 ZERO_STRUCT(info_ctr);
3001 ZERO_STRUCT(devmode_ctr);
3002 ZERO_STRUCT(secdesc_ctr);
3004 info2.servername = info.info2.servername;
3005 info2.printername = info.info2.printername;
3006 info2.sharename = info.info2.sharename;
3007 info2.portname = info.info2.portname;
3008 info2.drivername = info.info2.drivername;
3009 info2.comment = "torture_comment";
3010 info2.location = info.info2.location;
3011 info2.devmode_ptr = 0;
3012 info2.sepfile = info.info2.sepfile;
3013 info2.printprocessor = info.info2.printprocessor;
3014 info2.datatype = info.info2.datatype;
3015 info2.parameters = info.info2.parameters;
3016 info2.secdesc_ptr = 0;
3017 info2.attributes = info.info2.attributes;
3018 info2.priority = info.info2.priority;
3019 info2.defaultpriority = info.info2.defaultpriority;
3020 info2.starttime = info.info2.starttime;
3021 info2.untiltime = info.info2.untiltime;
3022 info2.status = info.info2.status;
3023 info2.cjobs = info.info2.cjobs;
3024 info2.averageppm = info.info2.averageppm;
3026 info_ctr.level = 2;
3027 info_ctr.info.info2 = &info2;
3029 torture_assert(tctx, test_SetPrinter(tctx, p, handle, &info_ctr, &devmode_ctr, &secdesc_ctr, 0),
3030 "failed to call SetPrinter");
3032 info2.comment = comment;
3034 torture_assert(tctx, test_SetPrinter(tctx, p, handle, &info_ctr, &devmode_ctr, &secdesc_ctr, 0),
3035 "failed to call SetPrinter");
3039 torture_assert(tctx, test_GetChangeID_PrinterData(tctx, p, handle, &change_id2),
3040 "failed to query for ChangeID");
3041 torture_assert(tctx, test_GetChangeID_PrinterDataEx(tctx, p, handle, &change_id_ex2),
3042 "failed to query for ChangeID");
3043 torture_assert(tctx, test_GetChangeID_PrinterInfo(tctx, p, handle, &change_id_info2),
3044 "failed to query for ChangeID");
3046 torture_assert_int_equal(tctx, change_id2, change_id_ex2,
3047 "change_ids should all be equal");
3048 torture_assert_int_equal(tctx, change_id_ex2, change_id_info2,
3049 "change_ids should all be equal");
3051 torture_assert(tctx, (change_id < change_id2),
3052 talloc_asprintf(tctx, "change_id %d needs to be larger than change_id %d",
3053 change_id2, change_id));
3054 torture_assert(tctx, (change_id_ex < change_id_ex2),
3055 talloc_asprintf(tctx, "change_id %d needs to be larger than change_id %d",
3056 change_id_ex2, change_id_ex));
3057 torture_assert(tctx, (change_id_info < change_id_info2),
3058 talloc_asprintf(tctx, "change_id %d needs to be larger than change_id %d",
3059 change_id_info2, change_id_info));
3061 return true;
3064 static bool test_SecondaryClosePrinter(struct torture_context *tctx,
3065 struct dcerpc_pipe *p,
3066 struct policy_handle *handle)
3068 NTSTATUS status;
3069 struct dcerpc_binding *b;
3070 struct dcerpc_pipe *p2;
3071 struct spoolss_ClosePrinter cp;
3073 /* only makes sense on SMB */
3074 if (p->conn->transport.transport != NCACN_NP) {
3075 return true;
3078 torture_comment(tctx, "testing close on secondary pipe\n");
3080 status = dcerpc_parse_binding(tctx, p->conn->binding_string, &b);
3081 torture_assert_ntstatus_ok(tctx, status, "Failed to parse dcerpc binding");
3083 status = dcerpc_secondary_connection(p, &p2, b);
3084 torture_assert_ntstatus_ok(tctx, status, "Failed to create secondary connection");
3086 status = dcerpc_bind_auth_none(p2, &ndr_table_spoolss);
3087 torture_assert_ntstatus_ok(tctx, status, "Failed to create bind on secondary connection");
3089 cp.in.handle = handle;
3090 cp.out.handle = handle;
3092 status = dcerpc_spoolss_ClosePrinter(p2, tctx, &cp);
3093 torture_assert_ntstatus_equal(tctx, status, NT_STATUS_NET_WRITE_FAULT,
3094 "ERROR: Allowed close on secondary connection");
3096 torture_assert_int_equal(tctx, p2->last_fault_code, DCERPC_FAULT_CONTEXT_MISMATCH,
3097 "Unexpected fault code");
3099 talloc_free(p2);
3101 return true;
3104 static bool test_OpenPrinter_badname(struct torture_context *tctx,
3105 struct dcerpc_pipe *p, const char *name)
3107 NTSTATUS status;
3108 struct spoolss_OpenPrinter op;
3109 struct spoolss_OpenPrinterEx opEx;
3110 struct policy_handle handle;
3111 bool ret = true;
3113 op.in.printername = name;
3114 op.in.datatype = NULL;
3115 op.in.devmode_ctr.devmode= NULL;
3116 op.in.access_mask = 0;
3117 op.out.handle = &handle;
3119 torture_comment(tctx, "\nTesting OpenPrinter(%s) with bad name\n", op.in.printername);
3121 status = dcerpc_spoolss_OpenPrinter(p, tctx, &op);
3122 torture_assert_ntstatus_ok(tctx, status, "OpenPrinter failed");
3123 if (!W_ERROR_EQUAL(WERR_INVALID_PRINTER_NAME,op.out.result)) {
3124 torture_comment(tctx, "OpenPrinter(%s) unexpected result[%s] should be WERR_INVALID_PRINTER_NAME\n",
3125 name, win_errstr(op.out.result));
3128 if (W_ERROR_IS_OK(op.out.result)) {
3129 ret &=test_ClosePrinter(tctx, p, &handle);
3132 opEx.in.printername = name;
3133 opEx.in.datatype = NULL;
3134 opEx.in.devmode_ctr.devmode = NULL;
3135 opEx.in.access_mask = 0;
3136 opEx.in.level = 1;
3137 opEx.in.userlevel.level1 = NULL;
3138 opEx.out.handle = &handle;
3140 torture_comment(tctx, "Testing OpenPrinterEx(%s) with bad name\n", opEx.in.printername);
3142 status = dcerpc_spoolss_OpenPrinterEx(p, tctx, &opEx);
3143 torture_assert_ntstatus_ok(tctx, status, "OpenPrinterEx failed");
3144 if (!W_ERROR_EQUAL(WERR_INVALID_PARAM,opEx.out.result)) {
3145 torture_comment(tctx, "OpenPrinterEx(%s) unexpected result[%s] should be WERR_INVALID_PARAM\n",
3146 name, win_errstr(opEx.out.result));
3149 if (W_ERROR_IS_OK(opEx.out.result)) {
3150 ret &=test_ClosePrinter(tctx, p, &handle);
3153 return ret;
3156 static bool test_OpenPrinter(struct torture_context *tctx,
3157 struct dcerpc_pipe *p,
3158 const char *name)
3160 NTSTATUS status;
3161 struct spoolss_OpenPrinter r;
3162 struct policy_handle handle;
3163 bool ret = true;
3165 r.in.printername = talloc_asprintf(tctx, "\\\\%s\\%s", dcerpc_server_name(p), name);
3166 r.in.datatype = NULL;
3167 r.in.devmode_ctr.devmode= NULL;
3168 r.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
3169 r.out.handle = &handle;
3171 torture_comment(tctx, "Testing OpenPrinter(%s)\n", r.in.printername);
3173 status = dcerpc_spoolss_OpenPrinter(p, tctx, &r);
3175 torture_assert_ntstatus_ok(tctx, status, "OpenPrinter failed");
3177 torture_assert_werr_ok(tctx, r.out.result, "OpenPrinter failed");
3179 if (!test_GetPrinter(tctx, p, &handle)) {
3180 ret = false;
3183 if (!torture_setting_bool(tctx, "samba3", false)) {
3184 if (!test_SecondaryClosePrinter(tctx, p, &handle)) {
3185 ret = false;
3189 if (!test_ClosePrinter(tctx, p, &handle)) {
3190 ret = false;
3193 return ret;
3196 static bool call_OpenPrinterEx(struct torture_context *tctx,
3197 struct dcerpc_pipe *p,
3198 const char *name, struct policy_handle *handle)
3200 struct spoolss_OpenPrinterEx r;
3201 struct spoolss_UserLevel1 userlevel1;
3202 NTSTATUS status;
3204 if (name && name[0]) {
3205 r.in.printername = talloc_asprintf(tctx, "\\\\%s\\%s",
3206 dcerpc_server_name(p), name);
3207 } else {
3208 r.in.printername = talloc_asprintf(tctx, "\\\\%s",
3209 dcerpc_server_name(p));
3212 r.in.datatype = NULL;
3213 r.in.devmode_ctr.devmode= NULL;
3214 r.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
3215 r.in.level = 1;
3216 r.in.userlevel.level1 = &userlevel1;
3217 r.out.handle = handle;
3219 userlevel1.size = 1234;
3220 userlevel1.client = "hello";
3221 userlevel1.user = "spottyfoot!";
3222 userlevel1.build = 1;
3223 userlevel1.major = 2;
3224 userlevel1.minor = 3;
3225 userlevel1.processor = 4;
3227 torture_comment(tctx, "Testing OpenPrinterEx(%s)\n", r.in.printername);
3229 status = dcerpc_spoolss_OpenPrinterEx(p, tctx, &r);
3231 torture_assert_ntstatus_ok(tctx, status, "OpenPrinterEx failed");
3233 torture_assert_werr_ok(tctx, r.out.result, "OpenPrinterEx failed");
3235 return true;
3238 static bool test_OpenPrinterEx(struct torture_context *tctx,
3239 struct dcerpc_pipe *p,
3240 const char *name)
3242 struct policy_handle handle;
3243 bool ret = true;
3245 if (!call_OpenPrinterEx(tctx, p, name, &handle)) {
3246 return false;
3249 if (!test_PrinterInfo_SD(tctx, p, &handle)) {
3250 ret = false;
3253 if (!test_GetPrinter(tctx, p, &handle)) {
3254 ret = false;
3257 if (!test_EnumForms(tctx, p, &handle, false)) {
3258 ret = false;
3261 if (!test_AddForm(tctx, p, &handle, false)) {
3262 ret = false;
3265 if (!test_EnumPrinterData(tctx, p, &handle)) {
3266 ret = false;
3269 if (!test_EnumPrinterDataEx(tctx, p, &handle, "PrinterDriverData")) {
3270 ret = false;
3273 if (!test_printer_keys(tctx, p, &handle)) {
3274 ret = false;
3277 if (!test_PausePrinter(tctx, p, &handle)) {
3278 ret = false;
3281 if (!test_DoPrintTest(tctx, p, &handle)) {
3282 ret = false;
3285 if (!test_ResumePrinter(tctx, p, &handle)) {
3286 ret = false;
3289 if (!test_SetPrinterData(tctx, p, &handle)) {
3290 ret = false;
3293 if (!test_SetPrinterDataEx(tctx, p, &handle)) {
3294 ret = false;
3297 if (!test_ChangeID(tctx, p, &handle)) {
3298 ret = false;
3301 if (!torture_setting_bool(tctx, "samba3", false)) {
3302 if (!test_SecondaryClosePrinter(tctx, p, &handle)) {
3303 ret = false;
3307 if (!test_ClosePrinter(tctx, p, &handle)) {
3308 ret = false;
3311 return ret;
3314 static bool test_EnumPrinters_old(struct torture_context *tctx, struct dcerpc_pipe *p)
3316 struct spoolss_EnumPrinters r;
3317 NTSTATUS status;
3318 uint16_t levels[] = {1, 2, 4, 5};
3319 int i;
3320 bool ret = true;
3322 for (i=0;i<ARRAY_SIZE(levels);i++) {
3323 union spoolss_PrinterInfo *info;
3324 int j;
3325 uint32_t needed;
3326 uint32_t count;
3328 r.in.flags = PRINTER_ENUM_LOCAL;
3329 r.in.server = "";
3330 r.in.level = levels[i];
3331 r.in.buffer = NULL;
3332 r.in.offered = 0;
3333 r.out.needed = &needed;
3334 r.out.count = &count;
3335 r.out.info = &info;
3337 torture_comment(tctx, "Testing EnumPrinters level %u\n", r.in.level);
3339 status = dcerpc_spoolss_EnumPrinters(p, tctx, &r);
3340 torture_assert_ntstatus_ok(tctx, status, "EnumPrinters failed");
3342 if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
3343 DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed);
3344 data_blob_clear(&blob);
3345 r.in.buffer = &blob;
3346 r.in.offered = needed;
3347 status = dcerpc_spoolss_EnumPrinters(p, tctx, &r);
3350 torture_assert_ntstatus_ok(tctx, status, "EnumPrinters failed");
3352 torture_assert_werr_ok(tctx, r.out.result, "EnumPrinters failed");
3354 CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumPrinters, info, r.in.level, count, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
3356 if (!info) {
3357 torture_comment(tctx, "No printers returned\n");
3358 return true;
3361 for (j=0;j<count;j++) {
3362 if (r.in.level == 1) {
3363 char *unc = talloc_strdup(tctx, info[j].info1.name);
3364 char *slash, *name;
3365 name = unc;
3366 if (unc[0] == '\\' && unc[1] == '\\') {
3367 unc +=2;
3369 slash = strchr(unc, '\\');
3370 if (slash) {
3371 slash++;
3372 name = slash;
3374 if (!test_OpenPrinter(tctx, p, name)) {
3375 ret = false;
3377 if (!test_OpenPrinterEx(tctx, p, name)) {
3378 ret = false;
3384 return ret;
3387 static bool test_GetPrinterDriver(struct torture_context *tctx,
3388 struct dcerpc_pipe *p,
3389 struct policy_handle *handle,
3390 const char *driver_name)
3392 struct spoolss_GetPrinterDriver r;
3393 uint32_t needed;
3395 r.in.handle = handle;
3396 r.in.architecture = "W32X86";
3397 r.in.level = 1;
3398 r.in.buffer = NULL;
3399 r.in.offered = 0;
3400 r.out.needed = &needed;
3402 torture_comment(tctx, "Testing GetPrinterDriver level %d\n", r.in.level);
3404 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_GetPrinterDriver(p, tctx, &r),
3405 "failed to call GetPrinterDriver");
3406 if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
3407 DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed);
3408 data_blob_clear(&blob);
3409 r.in.buffer = &blob;
3410 r.in.offered = needed;
3411 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_GetPrinterDriver(p, tctx, &r),
3412 "failed to call GetPrinterDriver");
3415 torture_assert_werr_ok(tctx, r.out.result,
3416 "failed to call GetPrinterDriver");
3418 CHECK_NEEDED_SIZE_LEVEL(spoolss_DriverInfo, r.out.info, r.in.level, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
3420 return true;
3423 static bool test_GetPrinterDriver2(struct torture_context *tctx,
3424 struct dcerpc_pipe *p,
3425 struct policy_handle *handle,
3426 const char *driver_name)
3428 struct spoolss_GetPrinterDriver2 r;
3429 uint16_t levels[] = {1, 2, 3, 4, 5, 6, 8, 101 };
3430 uint32_t needed;
3431 uint32_t server_major_version;
3432 uint32_t server_minor_version;
3433 int i;
3435 r.in.handle = handle;
3436 r.in.architecture = SPOOLSS_ARCHITECTURE_NT_X86;
3437 r.in.client_major_version = 3;
3438 r.in.client_minor_version = 0;
3439 r.out.needed = &needed;
3440 r.out.server_major_version = &server_major_version;
3441 r.out.server_minor_version = &server_minor_version;
3443 for (i=0;i<ARRAY_SIZE(levels);i++) {
3445 r.in.buffer = NULL;
3446 r.in.offered = 0;
3447 r.in.level = levels[i];
3449 torture_comment(tctx, "Testing GetPrinterDriver2(%s) level %d\n",
3450 driver_name, r.in.level);
3452 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_GetPrinterDriver2(p, tctx, &r),
3453 "failed to call GetPrinterDriver2");
3454 if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
3455 DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed);
3456 data_blob_clear(&blob);
3457 r.in.buffer = &blob;
3458 r.in.offered = needed;
3459 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_GetPrinterDriver2(p, tctx, &r),
3460 "failed to call GetPrinterDriver2");
3463 if (W_ERROR_EQUAL(r.out.result, WERR_INVALID_LEVEL)) {
3464 switch (r.in.level) {
3465 case 101:
3466 case 8:
3467 continue;
3468 default:
3469 break;
3473 torture_assert_werr_ok(tctx, r.out.result,
3474 "failed to call GetPrinterDriver2");
3476 CHECK_NEEDED_SIZE_LEVEL(spoolss_DriverInfo, r.out.info, r.in.level, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
3479 return true;
3482 static bool test_EnumPrinterDrivers_old(struct torture_context *tctx,
3483 struct dcerpc_pipe *p)
3485 struct spoolss_EnumPrinterDrivers r;
3486 NTSTATUS status;
3487 uint16_t levels[] = {1, 2, 3, 4, 5, 6};
3488 int i;
3490 for (i=0;i<ARRAY_SIZE(levels);i++) {
3492 uint32_t needed;
3493 uint32_t count;
3494 union spoolss_DriverInfo *info;
3496 r.in.server = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
3497 r.in.environment = SPOOLSS_ARCHITECTURE_NT_X86;
3498 r.in.level = levels[i];
3499 r.in.buffer = NULL;
3500 r.in.offered = 0;
3501 r.out.needed = &needed;
3502 r.out.count = &count;
3503 r.out.info = &info;
3505 torture_comment(tctx, "Testing EnumPrinterDrivers level %u\n", r.in.level);
3507 status = dcerpc_spoolss_EnumPrinterDrivers(p, tctx, &r);
3509 torture_assert_ntstatus_ok(tctx, status, "EnumPrinterDrivers failed");
3511 if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
3512 DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed);
3513 data_blob_clear(&blob);
3514 r.in.buffer = &blob;
3515 r.in.offered = needed;
3516 status = dcerpc_spoolss_EnumPrinterDrivers(p, tctx, &r);
3519 torture_assert_ntstatus_ok(tctx, status, "EnumPrinterDrivers failed");
3521 torture_assert_werr_ok(tctx, r.out.result, "EnumPrinterDrivers failed");
3523 if (!info) {
3524 torture_comment(tctx, "No printer drivers returned\n");
3525 break;
3528 CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumPrinterDrivers, info, r.in.level, count, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
3531 return true;
3534 static bool test_DeletePrinter(struct torture_context *tctx,
3535 struct dcerpc_pipe *p,
3536 struct policy_handle *handle)
3538 struct spoolss_DeletePrinter r;
3540 torture_comment(tctx, "Testing DeletePrinter\n");
3542 r.in.handle = handle;
3544 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_DeletePrinter(p, tctx, &r),
3545 "failed to delete printer");
3546 torture_assert_werr_ok(tctx, r.out.result,
3547 "failed to delete printer");
3549 return true;
3552 static bool test_EnumPrinters_findname(struct torture_context *tctx,
3553 struct dcerpc_pipe *p,
3554 uint32_t flags,
3555 uint32_t level,
3556 const char *name,
3557 bool *found)
3559 struct spoolss_EnumPrinters e;
3560 uint32_t count;
3561 union spoolss_PrinterInfo *info;
3562 uint32_t needed;
3563 int i;
3565 *found = false;
3567 e.in.flags = flags;
3568 e.in.server = NULL;
3569 e.in.level = level;
3570 e.in.buffer = NULL;
3571 e.in.offered = 0;
3572 e.out.count = &count;
3573 e.out.info = &info;
3574 e.out.needed = &needed;
3576 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_EnumPrinters(p, tctx, &e),
3577 "failed to enum printers");
3579 if (W_ERROR_EQUAL(e.out.result, WERR_INSUFFICIENT_BUFFER)) {
3580 DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed);
3581 data_blob_clear(&blob);
3582 e.in.buffer = &blob;
3583 e.in.offered = needed;
3585 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_EnumPrinters(p, tctx, &e),
3586 "failed to enum printers");
3589 torture_assert_werr_ok(tctx, e.out.result,
3590 "failed to enum printers");
3592 for (i=0; i < count; i++) {
3594 const char *current = NULL;
3596 switch (level) {
3597 case 1:
3598 current = info[i].info1.name;
3599 break;
3602 if (strequal(current, name)) {
3603 *found = true;
3604 break;
3608 return true;
3611 static bool test_AddPrinter_wellknown(struct torture_context *tctx,
3612 struct dcerpc_pipe *p,
3613 const char *printername,
3614 bool ex)
3616 WERROR result;
3617 struct spoolss_AddPrinter r;
3618 struct spoolss_AddPrinterEx rex;
3619 struct spoolss_SetPrinterInfoCtr info_ctr;
3620 struct spoolss_SetPrinterInfo1 info1;
3621 struct spoolss_DevmodeContainer devmode_ctr;
3622 struct sec_desc_buf secdesc_ctr;
3623 struct spoolss_UserLevelCtr userlevel_ctr;
3624 struct policy_handle handle;
3625 bool found = false;
3627 ZERO_STRUCT(devmode_ctr);
3628 ZERO_STRUCT(secdesc_ctr);
3629 ZERO_STRUCT(userlevel_ctr);
3630 ZERO_STRUCT(info1);
3632 torture_comment(tctx, "Testing AddPrinter%s level 1\n", ex ? "Ex":"");
3634 /* try to add printer to wellknown printer list (level 1) */
3636 userlevel_ctr.level = 1;
3638 info_ctr.info.info1 = &info1;
3639 info_ctr.level = 1;
3641 rex.in.server = NULL;
3642 rex.in.info_ctr = &info_ctr;
3643 rex.in.devmode_ctr = &devmode_ctr;
3644 rex.in.secdesc_ctr = &secdesc_ctr;
3645 rex.in.userlevel_ctr = &userlevel_ctr;
3646 rex.out.handle = &handle;
3648 r.in.server = NULL;
3649 r.in.info_ctr = &info_ctr;
3650 r.in.devmode_ctr = &devmode_ctr;
3651 r.in.secdesc_ctr = &secdesc_ctr;
3652 r.out.handle = &handle;
3654 torture_assert_ntstatus_ok(tctx, ex ? dcerpc_spoolss_AddPrinterEx(p, tctx, &rex) :
3655 dcerpc_spoolss_AddPrinter(p, tctx, &r),
3656 "failed to add printer");
3657 result = ex ? rex.out.result : r.out.result;
3658 torture_assert_werr_equal(tctx, result, WERR_INVALID_PRINTER_NAME,
3659 "unexpected result code");
3661 info1.name = printername;
3662 info1.flags = PRINTER_ATTRIBUTE_SHARED;
3664 torture_assert_ntstatus_ok(tctx, ex ? dcerpc_spoolss_AddPrinterEx(p, tctx, &rex) :
3665 dcerpc_spoolss_AddPrinter(p, tctx, &r),
3666 "failed to add printer");
3667 result = ex ? rex.out.result : r.out.result;
3668 torture_assert_werr_equal(tctx, result, WERR_PRINTER_ALREADY_EXISTS,
3669 "unexpected result code");
3671 /* bizarre protocol, WERR_PRINTER_ALREADY_EXISTS means success here,
3672 better do a real check to see the printer is really there */
3674 torture_assert(tctx, test_EnumPrinters_findname(tctx, p,
3675 PRINTER_ENUM_NETWORK, 1,
3676 printername,
3677 &found),
3678 "failed to enum printers");
3680 torture_assert(tctx, found, "failed to find newly added printer");
3682 info1.flags = 0;
3684 torture_assert_ntstatus_ok(tctx, ex ? dcerpc_spoolss_AddPrinterEx(p, tctx, &rex) :
3685 dcerpc_spoolss_AddPrinter(p, tctx, &r),
3686 "failed to add printer");
3687 result = ex ? rex.out.result : r.out.result;
3688 torture_assert_werr_equal(tctx, result, WERR_PRINTER_ALREADY_EXISTS,
3689 "unexpected result code");
3691 /* bizarre protocol, WERR_PRINTER_ALREADY_EXISTS means success here,
3692 better do a real check to see the printer has really been removed
3693 from the well known printer list */
3695 found = false;
3697 torture_assert(tctx, test_EnumPrinters_findname(tctx, p,
3698 PRINTER_ENUM_NETWORK, 1,
3699 printername,
3700 &found),
3701 "failed to enum printers");
3702 #if 0
3703 torture_assert(tctx, !found, "printer still in well known printer list");
3704 #endif
3705 return true;
3708 static bool test_AddPrinter_normal(struct torture_context *tctx,
3709 struct dcerpc_pipe *p,
3710 struct policy_handle *handle_p,
3711 const char *printername,
3712 const char *drivername,
3713 const char *portname,
3714 bool ex)
3716 WERROR result;
3717 struct spoolss_AddPrinter r;
3718 struct spoolss_AddPrinterEx rex;
3719 struct spoolss_SetPrinterInfoCtr info_ctr;
3720 struct spoolss_SetPrinterInfo2 info2;
3721 struct spoolss_DevmodeContainer devmode_ctr;
3722 struct sec_desc_buf secdesc_ctr;
3723 struct spoolss_UserLevelCtr userlevel_ctr;
3724 struct policy_handle handle;
3725 bool found = false;
3727 ZERO_STRUCT(devmode_ctr);
3728 ZERO_STRUCT(secdesc_ctr);
3729 ZERO_STRUCT(userlevel_ctr);
3731 torture_comment(tctx, "Testing AddPrinter%s level 2\n", ex ? "Ex":"");
3733 userlevel_ctr.level = 1;
3735 rex.in.server = NULL;
3736 rex.in.info_ctr = &info_ctr;
3737 rex.in.devmode_ctr = &devmode_ctr;
3738 rex.in.secdesc_ctr = &secdesc_ctr;
3739 rex.in.userlevel_ctr = &userlevel_ctr;
3740 rex.out.handle = &handle;
3742 r.in.server = NULL;
3743 r.in.info_ctr = &info_ctr;
3744 r.in.devmode_ctr = &devmode_ctr;
3745 r.in.secdesc_ctr = &secdesc_ctr;
3746 r.out.handle = &handle;
3748 again:
3750 /* try to add printer to printer list (level 2) */
3752 ZERO_STRUCT(info2);
3754 info_ctr.info.info2 = &info2;
3755 info_ctr.level = 2;
3757 torture_assert_ntstatus_ok(tctx, ex ? dcerpc_spoolss_AddPrinterEx(p, tctx, &rex) :
3758 dcerpc_spoolss_AddPrinter(p, tctx, &r),
3759 "failed to add printer");
3760 result = ex ? rex.out.result : r.out.result;
3761 torture_assert_werr_equal(tctx, result, WERR_INVALID_PRINTER_NAME,
3762 "unexpected result code");
3764 info2.printername = printername;
3766 torture_assert_ntstatus_ok(tctx, ex ? dcerpc_spoolss_AddPrinterEx(p, tctx, &rex) :
3767 dcerpc_spoolss_AddPrinter(p, tctx, &r),
3768 "failed to add printer");
3769 result = ex ? rex.out.result : r.out.result;
3771 if (W_ERROR_EQUAL(result, WERR_PRINTER_ALREADY_EXISTS)) {
3772 struct policy_handle printer_handle;
3774 torture_assert(tctx, call_OpenPrinterEx(tctx, p, printername, &printer_handle),
3775 "failed to open printer handle");
3777 torture_assert(tctx, test_DeletePrinter(tctx, p, &printer_handle),
3778 "failed to delete printer");
3780 torture_assert(tctx, test_ClosePrinter(tctx, p, &printer_handle),
3781 "failed to close server handle");
3783 goto again;
3786 torture_assert_werr_equal(tctx, result, WERR_UNKNOWN_PORT,
3787 "unexpected result code");
3789 info2.portname = portname;
3791 torture_assert_ntstatus_ok(tctx, ex ? dcerpc_spoolss_AddPrinterEx(p, tctx, &rex) :
3792 dcerpc_spoolss_AddPrinter(p, tctx, &r),
3793 "failed to add printer");
3794 result = ex ? rex.out.result : r.out.result;
3795 torture_assert_werr_equal(tctx, result, WERR_UNKNOWN_PRINTER_DRIVER,
3796 "unexpected result code");
3798 info2.drivername = drivername;
3800 torture_assert_ntstatus_ok(tctx, ex ? dcerpc_spoolss_AddPrinterEx(p, tctx, &rex) :
3801 dcerpc_spoolss_AddPrinter(p, tctx, &r),
3802 "failed to add printer");
3803 result = ex ? rex.out.result : r.out.result;
3805 /* w2k8r2 allows to add printer w/o defining printprocessor */
3807 if (!W_ERROR_IS_OK(result)) {
3808 torture_assert_werr_equal(tctx, result, WERR_UNKNOWN_PRINTPROCESSOR,
3809 "unexpected result code");
3811 info2.printprocessor = "winprint";
3813 torture_assert_ntstatus_ok(tctx, ex ? dcerpc_spoolss_AddPrinterEx(p, tctx, &rex) :
3814 dcerpc_spoolss_AddPrinter(p, tctx, &r),
3815 "failed to add printer");
3816 result = ex ? rex.out.result : r.out.result;
3817 torture_assert_werr_ok(tctx, result,
3818 "failed to add printer");
3821 *handle_p = handle;
3823 /* we are paranoid, really check if the printer is there now */
3825 torture_assert(tctx, test_EnumPrinters_findname(tctx, p,
3826 PRINTER_ENUM_LOCAL, 1,
3827 printername,
3828 &found),
3829 "failed to enum printers");
3830 torture_assert(tctx, found, "failed to find newly added printer");
3832 torture_assert_ntstatus_ok(tctx, ex ? dcerpc_spoolss_AddPrinterEx(p, tctx, &rex) :
3833 dcerpc_spoolss_AddPrinter(p, tctx, &r),
3834 "failed to add printer");
3835 result = ex ? rex.out.result : r.out.result;
3836 torture_assert_werr_equal(tctx, result, WERR_PRINTER_ALREADY_EXISTS,
3837 "unexpected result code");
3839 return true;
3842 static bool test_AddPrinterEx(struct torture_context *tctx,
3843 struct dcerpc_pipe *p,
3844 struct policy_handle *handle_p,
3845 const char *printername,
3846 const char *drivername,
3847 const char *portname)
3849 bool ret = true;
3851 if (!torture_setting_bool(tctx, "samba3", false)) {
3852 if (!test_AddPrinter_wellknown(tctx, p, TORTURE_WELLKNOWN_PRINTER_EX, true)) {
3853 torture_comment(tctx, "failed to add printer to well known list\n");
3854 ret = false;
3858 if (!test_AddPrinter_normal(tctx, p, handle_p,
3859 printername, drivername, portname,
3860 true)) {
3861 torture_comment(tctx, "failed to add printer to printer list\n");
3862 ret = false;
3865 return ret;
3868 static bool test_AddPrinter(struct torture_context *tctx,
3869 struct dcerpc_pipe *p,
3870 struct policy_handle *handle_p,
3871 const char *printername,
3872 const char *drivername,
3873 const char *portname)
3875 bool ret = true;
3877 if (!torture_setting_bool(tctx, "samba3", false)) {
3878 if (!test_AddPrinter_wellknown(tctx, p, TORTURE_WELLKNOWN_PRINTER, false)) {
3879 torture_comment(tctx, "failed to add printer to well known list\n");
3880 ret = false;
3884 if (!test_AddPrinter_normal(tctx, p, handle_p,
3885 printername, drivername, portname,
3886 false)) {
3887 torture_comment(tctx, "failed to add printer to printer list\n");
3888 ret = false;
3891 return ret;
3894 static bool test_printer_info(struct torture_context *tctx,
3895 struct dcerpc_pipe *p,
3896 struct policy_handle *handle)
3898 bool ret = true;
3900 if (!test_PrinterInfo(tctx, p, handle)) {
3901 ret = false;
3904 if (!test_SetPrinter_errors(tctx, p, handle)) {
3905 ret = false;
3908 return ret;
3911 static bool test_EnumPrinterKey(struct torture_context *tctx,
3912 struct dcerpc_pipe *p,
3913 struct policy_handle *handle,
3914 const char *key_name,
3915 const char ***array)
3917 struct spoolss_EnumPrinterKey r;
3918 uint32_t needed = 0;
3919 union spoolss_KeyNames key_buffer;
3920 int32_t offered[] = { 0, 1, 2, 3, 4, 5, -1, -2, -3, -4, -5, 256, 512, 1024, 2048 };
3921 uint32_t _ndr_size;
3922 int i;
3924 r.in.handle = handle;
3925 r.in.key_name = key_name;
3926 r.out.key_buffer = &key_buffer;
3927 r.out.needed = &needed;
3928 r.out._ndr_size = &_ndr_size;
3930 for (i=0; i < ARRAY_SIZE(offered); i++) {
3932 if (offered[i] < 0 && needed) {
3933 if (needed <= 4) {
3934 continue;
3936 r.in.offered = needed + offered[i];
3937 } else {
3938 r.in.offered = offered[i];
3941 ZERO_STRUCT(key_buffer);
3943 torture_comment(tctx, "Testing EnumPrinterKey(%s) with %d offered\n", r.in.key_name, r.in.offered);
3945 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_EnumPrinterKey(p, tctx, &r),
3946 "failed to call EnumPrinterKey");
3947 if (W_ERROR_EQUAL(r.out.result, WERR_MORE_DATA)) {
3949 torture_assert(tctx, (_ndr_size == r.in.offered/2),
3950 talloc_asprintf(tctx, "EnumPrinterKey size mismatch, _ndr_size %d (expected %d)",
3951 _ndr_size, r.in.offered/2));
3953 r.in.offered = needed;
3954 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_EnumPrinterKey(p, tctx, &r),
3955 "failed to call EnumPrinterKey");
3958 if (offered[i] > 0) {
3959 torture_assert_werr_ok(tctx, r.out.result,
3960 "failed to call EnumPrinterKey");
3963 torture_assert(tctx, (_ndr_size == r.in.offered/2),
3964 talloc_asprintf(tctx, "EnumPrinterKey size mismatch, _ndr_size %d (expected %d)",
3965 _ndr_size, r.in.offered/2));
3967 torture_assert(tctx, (*r.out.needed <= r.in.offered),
3968 talloc_asprintf(tctx, "EnumPrinterKey size mismatch: needed %d is not <= offered %d", *r.out.needed, r.in.offered));
3970 torture_assert(tctx, (*r.out.needed <= _ndr_size * 2),
3971 talloc_asprintf(tctx, "EnumPrinterKey size mismatch: needed %d is not <= _ndr_size %d * 2", *r.out.needed, _ndr_size));
3973 if (key_buffer.string_array) {
3974 uint32_t calc_needed = 0;
3975 int s;
3976 for (s=0; key_buffer.string_array[s]; s++) {
3977 calc_needed += strlen_m_term(key_buffer.string_array[s])*2;
3979 if (!key_buffer.string_array[0]) {
3980 calc_needed += 2;
3982 calc_needed += 2;
3984 torture_assert_int_equal(tctx, *r.out.needed, calc_needed,
3985 "EnumPrinterKey unexpected size");
3989 if (array) {
3990 *array = key_buffer.string_array;
3993 return true;
3996 bool test_printer_keys(struct torture_context *tctx,
3997 struct dcerpc_pipe *p,
3998 struct policy_handle *handle)
4000 const char **key_array = NULL;
4001 int i;
4003 torture_assert(tctx, test_EnumPrinterKey(tctx, p, handle, "", &key_array),
4004 "failed to call test_EnumPrinterKey");
4006 for (i=0; key_array && key_array[i]; i++) {
4007 torture_assert(tctx, test_EnumPrinterKey(tctx, p, handle, key_array[i], NULL),
4008 "failed to call test_EnumPrinterKey");
4010 for (i=0; key_array && key_array[i]; i++) {
4011 torture_assert(tctx, test_EnumPrinterDataEx(tctx, p, handle, key_array[i]),
4012 "failed to call test_EnumPrinterDataEx");
4015 return true;
4018 static bool test_printer(struct torture_context *tctx,
4019 struct dcerpc_pipe *p)
4021 bool ret = true;
4022 struct policy_handle handle[2];
4023 bool found = false;
4024 const char *drivername = "Microsoft XPS Document Writer";
4025 const char *portname = "LPT1:";
4027 /* test printer created via AddPrinter */
4029 if (!test_AddPrinter(tctx, p, &handle[0], TORTURE_PRINTER, drivername, portname)) {
4030 return false;
4033 if (!test_printer_info(tctx, p, &handle[0])) {
4034 ret = false;
4037 if (!test_PrinterInfo_SD(tctx, p, &handle[0])) {
4038 ret = false;
4041 if (!test_printer_keys(tctx, p, &handle[0])) {
4042 ret = false;
4045 if (!test_DeletePrinter(tctx, p, &handle[0])) {
4046 ret = false;
4049 if (!test_EnumPrinters_findname(tctx, p, PRINTER_ENUM_LOCAL, 1,
4050 TORTURE_PRINTER, &found)) {
4051 ret = false;
4054 torture_assert(tctx, !found, "deleted printer still there");
4056 /* test printer created via AddPrinterEx */
4058 if (!test_AddPrinterEx(tctx, p, &handle[1], TORTURE_PRINTER_EX, drivername, portname)) {
4059 return false;
4062 if (!test_printer_info(tctx, p, &handle[1])) {
4063 ret = false;
4066 if (!test_printer_keys(tctx, p, &handle[1])) {
4067 ret = false;
4070 if (!test_DeletePrinter(tctx, p, &handle[1])) {
4071 ret = false;
4074 if (!test_EnumPrinters_findname(tctx, p, PRINTER_ENUM_LOCAL, 1,
4075 TORTURE_PRINTER_EX, &found)) {
4076 ret = false;
4079 torture_assert(tctx, !found, "deleted printer still there");
4081 return ret;
4084 bool torture_rpc_spoolss(struct torture_context *torture)
4086 NTSTATUS status;
4087 struct dcerpc_pipe *p;
4088 bool ret = true;
4089 struct test_spoolss_context *ctx;
4091 status = torture_rpc_connection(torture, &p, &ndr_table_spoolss);
4092 if (!NT_STATUS_IS_OK(status)) {
4093 return false;
4096 ctx = talloc_zero(torture, struct test_spoolss_context);
4098 ret &= test_OpenPrinter_server(torture, p, &ctx->server_handle);
4099 ret &= test_GetPrinterData_list(torture, p, &ctx->server_handle);
4100 ret &= test_EnumForms(torture, p, &ctx->server_handle, true);
4101 ret &= test_AddForm(torture, p, &ctx->server_handle, true);
4102 ret &= test_EnumPorts(torture, p, ctx);
4103 ret &= test_GetPrinterDriverDirectory(torture, p, ctx);
4104 ret &= test_GetPrintProcessorDirectory(torture, p, ctx);
4105 ret &= test_EnumPrinterDrivers(torture, p, ctx, SPOOLSS_ARCHITECTURE_NT_X86);
4106 ret &= test_EnumPrinterDrivers(torture, p, ctx, SPOOLSS_ARCHITECTURE_ALL);
4107 ret &= test_EnumMonitors(torture, p, ctx);
4108 ret &= test_EnumPrintProcessors(torture, p, ctx);
4109 ret &= test_EnumPrintProcDataTypes(torture, p, ctx);
4110 ret &= test_EnumPrinters(torture, p, ctx);
4111 ret &= test_OpenPrinter_badname(torture, p, "__INVALID_PRINTER__");
4112 ret &= test_OpenPrinter_badname(torture, p, "\\\\__INVALID_HOST__");
4113 ret &= test_OpenPrinter_badname(torture, p, "");
4114 ret &= test_OpenPrinter_badname(torture, p, "\\\\\\");
4115 ret &= test_OpenPrinter_badname(torture, p, "\\\\\\__INVALID_PRINTER__");
4116 ret &= test_OpenPrinter_badname(torture, p, talloc_asprintf(torture, "\\\\%s\\", dcerpc_server_name(p)));
4117 ret &= test_OpenPrinter_badname(torture, p,
4118 talloc_asprintf(torture, "\\\\%s\\__INVALID_PRINTER__", dcerpc_server_name(p)));
4121 ret &= test_AddPort(torture, p);
4122 ret &= test_EnumPorts_old(torture, p);
4123 ret &= test_EnumPrinters_old(torture, p);
4124 ret &= test_EnumPrinterDrivers_old(torture, p);
4126 return ret;
4129 struct torture_suite *torture_rpc_spoolss_printer(TALLOC_CTX *mem_ctx)
4131 struct torture_suite *suite = torture_suite_create(mem_ctx, "SPOOLSS-PRINTER");
4133 struct torture_rpc_tcase *tcase = torture_suite_add_rpc_iface_tcase(suite,
4134 "printer", &ndr_table_spoolss);
4136 torture_rpc_tcase_add_test(tcase, "printer", test_printer);
4138 return suite;