s4-smbtorture: add --option=torture:spoolss_check_size=yes.
[Samba/ekacnet.git] / source4 / torture / rpc / spoolss.c
blobe22032d8bc618ae6f911fe359694527c2a9693ed
1 /*
2 Unix SMB/CIFS implementation.
3 test suite for spoolss rpc operations
5 Copyright (C) Tim Potter 2003
6 Copyright (C) Stefan Metzmacher 2005
7 Copyright (C) Jelmer Vernooij 2007
8 Copyright (C) Guenther Deschner 2009-2010
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 3 of the License, or
13 (at your option) any later version.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program. If not, see <http://www.gnu.org/licenses/>.
24 #include "includes.h"
25 #include "torture/torture.h"
26 #include "librpc/gen_ndr/ndr_misc.h"
27 #include "librpc/gen_ndr/ndr_spoolss.h"
28 #include "librpc/gen_ndr/ndr_spoolss_c.h"
29 #include "librpc/gen_ndr/ndr_security.h"
30 #include "libcli/security/security.h"
31 #include "torture/rpc/rpc.h"
32 #include "param/param.h"
34 #define TORTURE_WELLKNOWN_PRINTER "torture_wkn_printer"
35 #define TORTURE_PRINTER "torture_printer"
36 #define TORTURE_WELLKNOWN_PRINTER_EX "torture_wkn_printer_ex"
37 #define TORTURE_PRINTER_EX "torture_printer_ex"
39 struct test_spoolss_context {
40 /* print server handle */
41 struct policy_handle server_handle;
43 /* for EnumPorts */
44 uint32_t port_count[3];
45 union spoolss_PortInfo *ports[3];
47 /* for EnumPrinterDrivers */
48 uint32_t driver_count[8];
49 union spoolss_DriverInfo *drivers[8];
51 /* for EnumMonitors */
52 uint32_t monitor_count[3];
53 union spoolss_MonitorInfo *monitors[3];
55 /* for EnumPrintProcessors */
56 uint32_t print_processor_count[2];
57 union spoolss_PrintProcessorInfo *print_processors[2];
59 /* for EnumPrinters */
60 uint32_t printer_count[6];
61 union spoolss_PrinterInfo *printers[6];
64 #define COMPARE_STRING(tctx, c,r,e) \
65 torture_assert_str_equal(tctx, c.e, r.e, "invalid value")
67 /* not every compiler supports __typeof__() */
68 #if (__GNUC__ >= 3)
69 #define _CHECK_FIELD_SIZE(c,r,e,type) do {\
70 if (sizeof(__typeof__(c.e)) != sizeof(type)) { \
71 torture_fail(tctx, #c "." #e "field is not " #type "\n"); \
73 if (sizeof(__typeof__(r.e)) != sizeof(type)) { \
74 torture_fail(tctx, #r "." #e "field is not " #type "\n"); \
76 } while(0)
77 #else
78 #define _CHECK_FIELD_SIZE(c,r,e,type) do {} while(0)
79 #endif
81 #define COMPARE_UINT32(tctx, c, r, e) do {\
82 _CHECK_FIELD_SIZE(c, r, e, uint32_t); \
83 torture_assert_int_equal(tctx, c.e, r.e, "invalid value"); \
84 } while(0)
86 #define COMPARE_UINT64(tctx, c, r, e) do {\
87 _CHECK_FIELD_SIZE(c, r, e, uint64_t); \
88 torture_assert_int_equal(tctx, c.e, r.e, "invalid value"); \
89 } while(0)
92 #define COMPARE_NTTIME(tctx, c, r, e) do {\
93 _CHECK_FIELD_SIZE(c, r, e, NTTIME); \
94 torture_assert_int_equal(tctx, c.e, r.e, "invalid value"); \
95 } while(0)
97 #define COMPARE_STRING_ARRAY(tctx, c,r,e) do {\
98 int __i; \
99 if (!c.e && !r.e) { \
100 break; \
102 if (c.e && !r.e) { \
103 torture_fail(tctx, #r "." #e " field is NULL and " #c "." #e " is not\n"); \
105 if (!c.e && r.e) { \
106 torture_fail(tctx, #c "." #e " field is NULL and " #r "." #e " is not\n"); \
108 for (__i=0;c.e[__i] != NULL; __i++) { \
109 torture_assert_str_equal(tctx, c.e[__i], r.e[__i], "invalid value"); \
111 } while(0)
113 #define CHECK_ALIGN(size, n) do {\
114 if (size % n) {\
115 torture_warning(tctx, "%d is *NOT* %d byte aligned, should be %d",\
116 size, n, size + n - (size % n));\
118 } while(0)
120 #define DO_ROUND(size, n) (((size)+((n)-1)) & ~((n)-1))
122 #define CHECK_NEEDED_SIZE_ENUM_LEVEL(fn, info, level, count, ic, needed, align) do { \
123 if (torture_setting_bool(tctx, "spoolss_check_size", false)) {\
124 uint32_t size = ndr_size_##fn##_info(tctx, ic, level, count, info);\
125 uint32_t round_size = DO_ROUND(size, align);\
126 if (round_size != needed) {\
127 torture_warning(tctx, __location__": "#fn" level %d (count: %d) got unexpected needed size: %d, we calculated: %d", level, count, needed, round_size);\
128 CHECK_ALIGN(size, align);\
131 } while(0)
133 #define CHECK_NEEDED_SIZE_ENUM(fn, info, count, ic, needed, align) do { \
134 if (torture_setting_bool(tctx, "spoolss_check_size", false)) {\
135 uint32_t size = ndr_size_##fn##_info(tctx, ic, count, info);\
136 uint32_t round_size = DO_ROUND(size, align);\
137 if (round_size != needed) {\
138 torture_warning(tctx, __location__": "#fn" (count: %d) got unexpected needed size: %d, we calculated: %d", count, needed, round_size);\
139 CHECK_ALIGN(size, align);\
142 } while(0)
144 #define CHECK_NEEDED_SIZE_LEVEL(fn, info, level, ic, needed, align) do { \
145 if (torture_setting_bool(tctx, "spoolss_check_size", false)) {\
146 uint32_t size = ndr_size_##fn(info, level, ic, 0);\
147 uint32_t round_size = DO_ROUND(size, align);\
148 if (round_size != needed) {\
149 torture_warning(tctx, __location__": "#fn" level %d got unexpected needed size: %d, we calculated: %d", level, needed, round_size);\
150 CHECK_ALIGN(size, align);\
153 } while(0)
155 static bool test_OpenPrinter_server(struct torture_context *tctx,
156 struct dcerpc_pipe *p,
157 struct policy_handle *server_handle)
159 NTSTATUS status;
160 struct spoolss_OpenPrinter op;
162 op.in.printername = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
163 op.in.datatype = NULL;
164 op.in.devmode_ctr.devmode= NULL;
165 op.in.access_mask = 0;
166 op.out.handle = server_handle;
168 torture_comment(tctx, "Testing OpenPrinter(%s)\n", op.in.printername);
170 status = dcerpc_spoolss_OpenPrinter(p, tctx, &op);
171 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_OpenPrinter failed");
172 torture_assert_werr_ok(tctx, op.out.result, "dcerpc_spoolss_OpenPrinter failed");
174 return true;
177 static bool test_EnumPorts(struct torture_context *tctx,
178 struct dcerpc_pipe *p,
179 struct test_spoolss_context *ctx)
181 NTSTATUS status;
182 struct spoolss_EnumPorts r;
183 uint16_t levels[] = { 1, 2 };
184 int i, j;
186 for (i=0;i<ARRAY_SIZE(levels);i++) {
187 int level = levels[i];
188 DATA_BLOB blob;
189 uint32_t needed;
190 uint32_t count;
191 union spoolss_PortInfo *info;
193 r.in.servername = "";
194 r.in.level = level;
195 r.in.buffer = NULL;
196 r.in.offered = 0;
197 r.out.needed = &needed;
198 r.out.count = &count;
199 r.out.info = &info;
201 torture_comment(tctx, "Testing EnumPorts level %u\n", r.in.level);
203 status = dcerpc_spoolss_EnumPorts(p, ctx, &r);
204 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EnumPorts failed");
205 if (W_ERROR_IS_OK(r.out.result)) {
206 /* TODO: do some more checks here */
207 continue;
209 torture_assert_werr_equal(tctx, r.out.result, WERR_INSUFFICIENT_BUFFER,
210 "EnumPorts unexpected return code");
212 blob = data_blob_talloc(ctx, NULL, needed);
213 data_blob_clear(&blob);
214 r.in.buffer = &blob;
215 r.in.offered = needed;
217 status = dcerpc_spoolss_EnumPorts(p, ctx, &r);
218 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EnumPorts failed");
220 torture_assert_werr_ok(tctx, r.out.result, "EnumPorts failed");
222 torture_assert(tctx, info, "EnumPorts returned no info");
224 CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumPorts, info, r.in.level, count, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
226 ctx->port_count[level] = count;
227 ctx->ports[level] = info;
230 for (i=1;i<ARRAY_SIZE(levels);i++) {
231 int level = levels[i];
232 int old_level = levels[i-1];
233 torture_assert_int_equal(tctx, ctx->port_count[level], ctx->port_count[old_level],
234 "EnumPorts invalid value");
236 /* if the array sizes are not the same we would maybe segfault in the following code */
238 for (i=0;i<ARRAY_SIZE(levels);i++) {
239 int level = levels[i];
240 for (j=0;j<ctx->port_count[level];j++) {
241 union spoolss_PortInfo *cur = &ctx->ports[level][j];
242 union spoolss_PortInfo *ref = &ctx->ports[2][j];
243 switch (level) {
244 case 1:
245 COMPARE_STRING(tctx, cur->info1, ref->info2, port_name);
246 break;
247 case 2:
248 /* level 2 is our reference, and it makes no sense to compare it to itself */
249 break;
254 return true;
257 static bool test_GetPrintProcessorDirectory(struct torture_context *tctx,
258 struct dcerpc_pipe *p,
259 struct test_spoolss_context *ctx)
261 NTSTATUS status;
262 struct spoolss_GetPrintProcessorDirectory r;
263 struct {
264 uint16_t level;
265 const char *server;
266 } levels[] = {{
267 .level = 1,
268 .server = NULL
270 .level = 1,
271 .server = ""
273 .level = 78,
274 .server = ""
276 .level = 1,
277 .server = talloc_asprintf(ctx, "\\\\%s", dcerpc_server_name(p))
279 .level = 1024,
280 .server = talloc_asprintf(ctx, "\\\\%s", dcerpc_server_name(p))
283 int i;
284 uint32_t needed;
286 for (i=0;i<ARRAY_SIZE(levels);i++) {
287 int level = levels[i].level;
288 DATA_BLOB blob;
290 r.in.server = levels[i].server;
291 r.in.environment = SPOOLSS_ARCHITECTURE_NT_X86;
292 r.in.level = level;
293 r.in.buffer = NULL;
294 r.in.offered = 0;
295 r.out.needed = &needed;
297 torture_comment(tctx, "Testing GetPrintProcessorDirectory level %u\n", r.in.level);
299 status = dcerpc_spoolss_GetPrintProcessorDirectory(p, ctx, &r);
300 torture_assert_ntstatus_ok(tctx, status,
301 "dcerpc_spoolss_GetPrintProcessorDirectory failed");
302 torture_assert_werr_equal(tctx, r.out.result, WERR_INSUFFICIENT_BUFFER,
303 "GetPrintProcessorDirectory unexpected return code");
305 blob = data_blob_talloc(ctx, NULL, needed);
306 data_blob_clear(&blob);
307 r.in.buffer = &blob;
308 r.in.offered = needed;
310 status = dcerpc_spoolss_GetPrintProcessorDirectory(p, ctx, &r);
311 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_GetPrintProcessorDirectory failed");
313 torture_assert_werr_ok(tctx, r.out.result, "GetPrintProcessorDirectory failed");
315 CHECK_NEEDED_SIZE_LEVEL(spoolss_PrintProcessorDirectoryInfo, r.out.info, r.in.level, lp_iconv_convenience(tctx->lp_ctx), needed, 2);
318 return true;
322 static bool test_GetPrinterDriverDirectory(struct torture_context *tctx,
323 struct dcerpc_pipe *p,
324 struct test_spoolss_context *ctx)
326 NTSTATUS status;
327 struct spoolss_GetPrinterDriverDirectory r;
328 struct {
329 uint16_t level;
330 const char *server;
331 } levels[] = {{
332 .level = 1,
333 .server = NULL
335 .level = 1,
336 .server = ""
338 .level = 78,
339 .server = ""
341 .level = 1,
342 .server = talloc_asprintf(ctx, "\\\\%s", dcerpc_server_name(p))
344 .level = 1024,
345 .server = talloc_asprintf(ctx, "\\\\%s", dcerpc_server_name(p))
348 int i;
349 uint32_t needed;
351 for (i=0;i<ARRAY_SIZE(levels);i++) {
352 int level = levels[i].level;
353 DATA_BLOB blob;
355 r.in.server = levels[i].server;
356 r.in.environment = SPOOLSS_ARCHITECTURE_NT_X86;
357 r.in.level = level;
358 r.in.buffer = NULL;
359 r.in.offered = 0;
360 r.out.needed = &needed;
362 torture_comment(tctx, "Testing GetPrinterDriverDirectory level %u\n", r.in.level);
364 status = dcerpc_spoolss_GetPrinterDriverDirectory(p, ctx, &r);
365 torture_assert_ntstatus_ok(tctx, status,
366 "dcerpc_spoolss_GetPrinterDriverDirectory failed");
367 torture_assert_werr_equal(tctx, r.out.result, WERR_INSUFFICIENT_BUFFER,
368 "GetPrinterDriverDirectory unexpected return code");
370 blob = data_blob_talloc(ctx, NULL, needed);
371 data_blob_clear(&blob);
372 r.in.buffer = &blob;
373 r.in.offered = needed;
375 status = dcerpc_spoolss_GetPrinterDriverDirectory(p, ctx, &r);
376 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_GetPrinterDriverDirectory failed");
378 torture_assert_werr_ok(tctx, r.out.result, "GetPrinterDriverDirectory failed");
380 CHECK_NEEDED_SIZE_LEVEL(spoolss_DriverDirectoryInfo, r.out.info, r.in.level, lp_iconv_convenience(tctx->lp_ctx), needed, 2);
383 return true;
386 static bool test_EnumPrinterDrivers(struct torture_context *tctx,
387 struct dcerpc_pipe *p,
388 struct test_spoolss_context *ctx,
389 const char *architecture)
391 NTSTATUS status;
392 struct spoolss_EnumPrinterDrivers r;
393 uint16_t levels[] = { 1, 2, 3, 4, 5, 6, 8 };
394 int i, j;
396 for (i=0;i<ARRAY_SIZE(levels);i++) {
397 int level = levels[i];
398 DATA_BLOB blob;
399 uint32_t needed;
400 uint32_t count;
401 union spoolss_DriverInfo *info;
403 /* FIXME: gd, come back and fix "" as server, and handle
404 * priority of returned error codes in torture test and samba 3
405 * server */
407 r.in.server = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
408 r.in.environment = architecture;
409 r.in.level = level;
410 r.in.buffer = NULL;
411 r.in.offered = 0;
412 r.out.needed = &needed;
413 r.out.count = &count;
414 r.out.info = &info;
416 torture_comment(tctx, "Testing EnumPrinterDrivers level %u (%s)\n", r.in.level, r.in.environment);
418 status = dcerpc_spoolss_EnumPrinterDrivers(p, ctx, &r);
419 torture_assert_ntstatus_ok(tctx, status,
420 "dcerpc_spoolss_EnumPrinterDrivers failed");
421 if (W_ERROR_IS_OK(r.out.result)) {
422 /* TODO: do some more checks here */
423 continue;
425 if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
426 blob = data_blob_talloc(ctx, NULL, needed);
427 data_blob_clear(&blob);
428 r.in.buffer = &blob;
429 r.in.offered = needed;
431 status = dcerpc_spoolss_EnumPrinterDrivers(p, ctx, &r);
432 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EnumPrinterDrivers failed");
435 torture_assert_werr_ok(tctx, r.out.result, "EnumPrinterDrivers failed");
437 CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumPrinterDrivers, info, r.in.level, count, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
439 ctx->driver_count[level] = count;
440 ctx->drivers[level] = info;
443 for (i=1;i<ARRAY_SIZE(levels);i++) {
444 int level = levels[i];
445 int old_level = levels[i-1];
447 torture_assert_int_equal(tctx, ctx->driver_count[level], ctx->driver_count[old_level],
448 "EnumPrinterDrivers invalid value");
451 for (i=0;i<ARRAY_SIZE(levels);i++) {
452 int level = levels[i];
454 for (j=0;j<ctx->driver_count[level];j++) {
455 union spoolss_DriverInfo *cur = &ctx->drivers[level][j];
456 union spoolss_DriverInfo *ref = &ctx->drivers[8][j];
458 switch (level) {
459 case 1:
460 COMPARE_STRING(tctx, cur->info1, ref->info8, driver_name);
461 break;
462 case 2:
463 COMPARE_UINT32(tctx, cur->info2, ref->info8, version);
464 COMPARE_STRING(tctx, cur->info2, ref->info8, driver_name);
465 COMPARE_STRING(tctx, cur->info2, ref->info8, architecture);
466 COMPARE_STRING(tctx, cur->info2, ref->info8, driver_path);
467 COMPARE_STRING(tctx, cur->info2, ref->info8, data_file);
468 COMPARE_STRING(tctx, cur->info2, ref->info8, config_file);
469 break;
470 case 3:
471 COMPARE_UINT32(tctx, cur->info3, ref->info8, version);
472 COMPARE_STRING(tctx, cur->info3, ref->info8, driver_name);
473 COMPARE_STRING(tctx, cur->info3, ref->info8, architecture);
474 COMPARE_STRING(tctx, cur->info3, ref->info8, driver_path);
475 COMPARE_STRING(tctx, cur->info3, ref->info8, data_file);
476 COMPARE_STRING(tctx, cur->info3, ref->info8, config_file);
477 COMPARE_STRING(tctx, cur->info3, ref->info8, help_file);
478 COMPARE_STRING_ARRAY(tctx, cur->info3, ref->info8, dependent_files);
479 COMPARE_STRING(tctx, cur->info3, ref->info8, monitor_name);
480 COMPARE_STRING(tctx, cur->info3, ref->info8, default_datatype);
481 break;
482 case 4:
483 COMPARE_UINT32(tctx, cur->info4, ref->info8, version);
484 COMPARE_STRING(tctx, cur->info4, ref->info8, driver_name);
485 COMPARE_STRING(tctx, cur->info4, ref->info8, architecture);
486 COMPARE_STRING(tctx, cur->info4, ref->info8, driver_path);
487 COMPARE_STRING(tctx, cur->info4, ref->info8, data_file);
488 COMPARE_STRING(tctx, cur->info4, ref->info8, config_file);
489 COMPARE_STRING(tctx, cur->info4, ref->info8, help_file);
490 COMPARE_STRING_ARRAY(tctx, cur->info4, ref->info8, dependent_files);
491 COMPARE_STRING(tctx, cur->info4, ref->info8, monitor_name);
492 COMPARE_STRING(tctx, cur->info4, ref->info8, default_datatype);
493 COMPARE_STRING_ARRAY(tctx, cur->info4, ref->info8, previous_names);
494 break;
495 case 5:
496 COMPARE_UINT32(tctx, cur->info5, ref->info8, version);
497 COMPARE_STRING(tctx, cur->info5, ref->info8, driver_name);
498 COMPARE_STRING(tctx, cur->info5, ref->info8, architecture);
499 COMPARE_STRING(tctx, cur->info5, ref->info8, driver_path);
500 COMPARE_STRING(tctx, cur->info5, ref->info8, data_file);
501 COMPARE_STRING(tctx, cur->info5, ref->info8, config_file);
502 /*COMPARE_UINT32(tctx, cur->info5, ref->info8, driver_attributes);*/
503 /*COMPARE_UINT32(tctx, cur->info5, ref->info8, config_version);*/
504 /*TODO: ! COMPARE_UINT32(tctx, cur->info5, ref->info8, driver_version); */
505 break;
506 case 6:
507 COMPARE_UINT32(tctx, cur->info6, ref->info8, version);
508 COMPARE_STRING(tctx, cur->info6, ref->info8, driver_name);
509 COMPARE_STRING(tctx, cur->info6, ref->info8, architecture);
510 COMPARE_STRING(tctx, cur->info6, ref->info8, driver_path);
511 COMPARE_STRING(tctx, cur->info6, ref->info8, data_file);
512 COMPARE_STRING(tctx, cur->info6, ref->info8, config_file);
513 COMPARE_STRING(tctx, cur->info6, ref->info8, help_file);
514 COMPARE_STRING_ARRAY(tctx, cur->info6, ref->info8, dependent_files);
515 COMPARE_STRING(tctx, cur->info6, ref->info8, monitor_name);
516 COMPARE_STRING(tctx, cur->info6, ref->info8, default_datatype);
517 COMPARE_STRING_ARRAY(tctx, cur->info6, ref->info8, previous_names);
518 COMPARE_NTTIME(tctx, cur->info6, ref->info8, driver_date);
519 COMPARE_UINT64(tctx, cur->info6, ref->info8, driver_version);
520 COMPARE_STRING(tctx, cur->info6, ref->info8, manufacturer_name);
521 COMPARE_STRING(tctx, cur->info6, ref->info8, manufacturer_url);
522 COMPARE_STRING(tctx, cur->info6, ref->info8, hardware_id);
523 COMPARE_STRING(tctx, cur->info6, ref->info8, provider);
524 break;
525 case 8:
526 /* level 8 is our reference, and it makes no sense to compare it to itself */
527 break;
532 return true;
535 static bool test_EnumMonitors(struct torture_context *tctx,
536 struct dcerpc_pipe *p,
537 struct test_spoolss_context *ctx)
539 NTSTATUS status;
540 struct spoolss_EnumMonitors r;
541 uint16_t levels[] = { 1, 2 };
542 int i, j;
544 for (i=0;i<ARRAY_SIZE(levels);i++) {
545 int level = levels[i];
546 DATA_BLOB blob;
547 uint32_t needed;
548 uint32_t count;
549 union spoolss_MonitorInfo *info;
551 r.in.servername = "";
552 r.in.level = level;
553 r.in.buffer = NULL;
554 r.in.offered = 0;
555 r.out.needed = &needed;
556 r.out.count = &count;
557 r.out.info = &info;
559 torture_comment(tctx, "Testing EnumMonitors level %u\n", r.in.level);
561 status = dcerpc_spoolss_EnumMonitors(p, ctx, &r);
562 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EnumMonitors failed");
563 if (W_ERROR_IS_OK(r.out.result)) {
564 /* TODO: do some more checks here */
565 continue;
567 torture_assert_werr_equal(tctx, r.out.result, WERR_INSUFFICIENT_BUFFER,
568 "EnumMonitors failed");
570 blob = data_blob_talloc(ctx, NULL, needed);
571 data_blob_clear(&blob);
572 r.in.buffer = &blob;
573 r.in.offered = needed;
575 status = dcerpc_spoolss_EnumMonitors(p, ctx, &r);
576 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EnumMonitors failed");
578 torture_assert_werr_ok(tctx, r.out.result, "EnumMonitors failed");
580 CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumMonitors, info, r.in.level, count, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
582 ctx->monitor_count[level] = count;
583 ctx->monitors[level] = info;
586 for (i=1;i<ARRAY_SIZE(levels);i++) {
587 int level = levels[i];
588 int old_level = levels[i-1];
589 torture_assert_int_equal(tctx, ctx->monitor_count[level], ctx->monitor_count[old_level],
590 "EnumMonitors invalid value");
593 for (i=0;i<ARRAY_SIZE(levels);i++) {
594 int level = levels[i];
595 for (j=0;j<ctx->monitor_count[level];j++) {
596 union spoolss_MonitorInfo *cur = &ctx->monitors[level][j];
597 union spoolss_MonitorInfo *ref = &ctx->monitors[2][j];
598 switch (level) {
599 case 1:
600 COMPARE_STRING(tctx, cur->info1, ref->info2, monitor_name);
601 break;
602 case 2:
603 /* level 2 is our reference, and it makes no sense to compare it to itself */
604 break;
609 return true;
612 static bool test_EnumPrintProcessors(struct torture_context *tctx,
613 struct dcerpc_pipe *p,
614 struct test_spoolss_context *ctx)
616 NTSTATUS status;
617 struct spoolss_EnumPrintProcessors r;
618 uint16_t levels[] = { 1 };
619 int i, j;
621 for (i=0;i<ARRAY_SIZE(levels);i++) {
622 int level = levels[i];
623 DATA_BLOB blob;
624 uint32_t needed;
625 uint32_t count;
626 union spoolss_PrintProcessorInfo *info;
628 r.in.servername = "";
629 r.in.environment = SPOOLSS_ARCHITECTURE_NT_X86;
630 r.in.level = level;
631 r.in.buffer = NULL;
632 r.in.offered = 0;
633 r.out.needed = &needed;
634 r.out.count = &count;
635 r.out.info = &info;
637 torture_comment(tctx, "Testing EnumPrintProcessors level %u\n", r.in.level);
639 status = dcerpc_spoolss_EnumPrintProcessors(p, ctx, &r);
640 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EnumPrintProcessors failed");
641 if (W_ERROR_IS_OK(r.out.result)) {
642 /* TODO: do some more checks here */
643 continue;
645 torture_assert_werr_equal(tctx, r.out.result, WERR_INSUFFICIENT_BUFFER,
646 "EnumPrintProcessors unexpected return code");
648 blob = data_blob_talloc(ctx, NULL, needed);
649 data_blob_clear(&blob);
650 r.in.buffer = &blob;
651 r.in.offered = needed;
653 status = dcerpc_spoolss_EnumPrintProcessors(p, ctx, &r);
654 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EnumPrintProcessors failed");
656 torture_assert_werr_ok(tctx, r.out.result, "EnumPrintProcessors failed");
658 CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumPrintProcessors, info, r.in.level, count, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
660 ctx->print_processor_count[level] = count;
661 ctx->print_processors[level] = info;
664 for (i=1;i<ARRAY_SIZE(levels);i++) {
665 int level = levels[i];
666 int old_level = levels[i-1];
667 torture_assert_int_equal(tctx, ctx->print_processor_count[level], ctx->print_processor_count[old_level],
668 "EnumPrintProcessors failed");
671 for (i=0;i<ARRAY_SIZE(levels);i++) {
672 int level = levels[i];
673 for (j=0;j<ctx->print_processor_count[level];j++) {
674 #if 0
675 union spoolss_PrintProcessorInfo *cur = &ctx->print_processors[level][j];
676 union spoolss_PrintProcessorInfo *ref = &ctx->print_processors[1][j];
677 #endif
678 switch (level) {
679 case 1:
680 /* level 1 is our reference, and it makes no sense to compare it to itself */
681 break;
686 return true;
689 static bool test_EnumPrintProcDataTypes(struct torture_context *tctx,
690 struct dcerpc_pipe *p,
691 struct test_spoolss_context *ctx)
693 NTSTATUS status;
694 struct spoolss_EnumPrintProcDataTypes r;
695 uint16_t levels[] = { 1 };
696 int i;
698 for (i=0;i<ARRAY_SIZE(levels);i++) {
699 int level = levels[i];
700 DATA_BLOB blob;
701 uint32_t needed;
702 uint32_t count;
703 union spoolss_PrintProcDataTypesInfo *info;
705 r.in.servername = "";
706 r.in.print_processor_name = "winprint";
707 r.in.level = level;
708 r.in.buffer = NULL;
709 r.in.offered = 0;
710 r.out.needed = &needed;
711 r.out.count = &count;
712 r.out.info = &info;
714 torture_comment(tctx, "Testing EnumPrintProcDataTypes level %u\n", r.in.level);
716 status = dcerpc_spoolss_EnumPrintProcDataTypes(p, ctx, &r);
717 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EnumPrintProcDataType failed");
718 if (W_ERROR_IS_OK(r.out.result)) {
719 /* TODO: do some more checks here */
720 continue;
722 torture_assert_werr_equal(tctx, r.out.result, WERR_INSUFFICIENT_BUFFER,
723 "EnumPrintProcDataTypes unexpected return code");
725 blob = data_blob_talloc(ctx, NULL, needed);
726 data_blob_clear(&blob);
727 r.in.buffer = &blob;
728 r.in.offered = needed;
730 status = dcerpc_spoolss_EnumPrintProcDataTypes(p, ctx, &r);
731 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EnumPrintProcDataTypes failed");
733 torture_assert_werr_ok(tctx, r.out.result, "EnumPrintProcDataTypes failed");
735 CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumPrintProcDataTypes, info, r.in.level, count, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
739 return true;
743 static bool test_EnumPrinters(struct torture_context *tctx,
744 struct dcerpc_pipe *p,
745 struct test_spoolss_context *ctx)
747 struct spoolss_EnumPrinters r;
748 NTSTATUS status;
749 uint16_t levels[] = { 0, 1, 2, 4, 5 };
750 int i, j;
752 for (i=0;i<ARRAY_SIZE(levels);i++) {
753 int level = levels[i];
754 DATA_BLOB blob;
755 uint32_t needed;
756 uint32_t count;
757 union spoolss_PrinterInfo *info;
759 r.in.flags = PRINTER_ENUM_LOCAL;
760 r.in.server = "";
761 r.in.level = level;
762 r.in.buffer = NULL;
763 r.in.offered = 0;
764 r.out.needed = &needed;
765 r.out.count = &count;
766 r.out.info = &info;
768 torture_comment(tctx, "Testing EnumPrinters level %u\n", r.in.level);
770 status = dcerpc_spoolss_EnumPrinters(p, ctx, &r);
771 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EnumPrinters failed");
772 if (W_ERROR_IS_OK(r.out.result)) {
773 /* TODO: do some more checks here */
774 continue;
776 torture_assert_werr_equal(tctx, r.out.result, WERR_INSUFFICIENT_BUFFER,
777 "EnumPrinters unexpected return code");
779 blob = data_blob_talloc(ctx, NULL, needed);
780 data_blob_clear(&blob);
781 r.in.buffer = &blob;
782 r.in.offered = needed;
784 status = dcerpc_spoolss_EnumPrinters(p, ctx, &r);
785 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EnumPrinters failed");
787 torture_assert_werr_ok(tctx, r.out.result, "EnumPrinters failed");
789 CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumPrinters, info, r.in.level, count, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
791 ctx->printer_count[level] = count;
792 ctx->printers[level] = info;
795 for (i=1;i<ARRAY_SIZE(levels);i++) {
796 int level = levels[i];
797 int old_level = levels[i-1];
798 torture_assert_int_equal(tctx, ctx->printer_count[level], ctx->printer_count[old_level],
799 "EnumPrinters invalid value");
802 for (i=0;i<ARRAY_SIZE(levels);i++) {
803 int level = levels[i];
804 for (j=0;j<ctx->printer_count[level];j++) {
805 union spoolss_PrinterInfo *cur = &ctx->printers[level][j];
806 union spoolss_PrinterInfo *ref = &ctx->printers[2][j];
807 switch (level) {
808 case 0:
809 COMPARE_STRING(tctx, cur->info0, ref->info2, printername);
810 COMPARE_STRING(tctx, cur->info0, ref->info2, servername);
811 COMPARE_UINT32(tctx, cur->info0, ref->info2, cjobs);
812 /*COMPARE_UINT32(tctx, cur->info0, ref->info2, total_jobs);
813 COMPARE_UINT32(tctx, cur->info0, ref->info2, total_bytes);
814 COMPARE_SPOOLSS_TIME(cur->info0, ref->info2, spoolss_Time time);
815 COMPARE_UINT32(tctx, cur->info0, ref->info2, global_counter);
816 COMPARE_UINT32(tctx, cur->info0, ref->info2, total_pages);
817 COMPARE_UINT32(tctx, cur->info0, ref->info2, version);
818 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown10);
819 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown11);
820 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown12);
821 COMPARE_UINT32(tctx, cur->info0, ref->info2, session_counter);
822 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown14);
823 COMPARE_UINT32(tctx, cur->info0, ref->info2, printer_errors);
824 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown16);
825 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown17);
826 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown18);
827 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown19);
828 COMPARE_UINT32(tctx, cur->info0, ref->info2, change_id);
829 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown21);*/
830 COMPARE_UINT32(tctx, cur->info0, ref->info2, status);
831 /*COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown23);
832 COMPARE_UINT32(tctx, cur->info0, ref->info2, c_setprinter);
833 COMPARE_UINT16(cur->info0, ref->info2, unknown25);
834 COMPARE_UINT16(cur->info0, ref->info2, unknown26);
835 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown27);
836 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown28);
837 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown29);*/
838 break;
839 case 1:
840 /*COMPARE_UINT32(tctx, cur->info1, ref->info2, flags);*/
841 /*COMPARE_STRING(tctx, cur->info1, ref->info2, name);*/
842 /*COMPARE_STRING(tctx, cur->info1, ref->info2, description);*/
843 COMPARE_STRING(tctx, cur->info1, ref->info2, comment);
844 break;
845 case 2:
846 /* level 2 is our reference, and it makes no sense to compare it to itself */
847 break;
848 case 4:
849 COMPARE_STRING(tctx, cur->info4, ref->info2, printername);
850 COMPARE_STRING(tctx, cur->info4, ref->info2, servername);
851 COMPARE_UINT32(tctx, cur->info4, ref->info2, attributes);
852 break;
853 case 5:
854 COMPARE_STRING(tctx, cur->info5, ref->info2, printername);
855 COMPARE_STRING(tctx, cur->info5, ref->info2, portname);
856 COMPARE_UINT32(tctx, cur->info5, ref->info2, attributes);
857 /*COMPARE_UINT32(tctx, cur->info5, ref->info2, device_not_selected_timeout);
858 COMPARE_UINT32(tctx, cur->info5, ref->info2, transmission_retry_timeout);*/
859 break;
864 /* TODO:
865 * - verify that the port of a printer was in the list returned by EnumPorts
868 return true;
871 static bool test_GetPrinterDriver2(struct torture_context *tctx,
872 struct dcerpc_pipe *p,
873 struct policy_handle *handle,
874 const char *driver_name);
876 bool test_GetPrinter_level(struct torture_context *tctx,
877 struct dcerpc_pipe *p,
878 struct policy_handle *handle,
879 uint32_t level,
880 union spoolss_PrinterInfo *info)
882 struct spoolss_GetPrinter r;
883 uint32_t needed;
885 r.in.handle = handle;
886 r.in.level = level;
887 r.in.buffer = NULL;
888 r.in.offered = 0;
889 r.out.needed = &needed;
891 torture_comment(tctx, "Testing GetPrinter level %u\n", r.in.level);
893 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_GetPrinter(p, tctx, &r),
894 "GetPrinter failed");
896 if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
897 DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed);
898 data_blob_clear(&blob);
899 r.in.buffer = &blob;
900 r.in.offered = needed;
902 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_GetPrinter(p, tctx, &r),
903 "GetPrinter failed");
906 torture_assert_werr_ok(tctx, r.out.result, "GetPrinter failed");
908 CHECK_NEEDED_SIZE_LEVEL(spoolss_PrinterInfo, r.out.info, r.in.level, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
910 if (info && r.out.info) {
911 *info = *r.out.info;
914 return true;
918 static bool test_GetPrinter(struct torture_context *tctx,
919 struct dcerpc_pipe *p,
920 struct policy_handle *handle)
922 uint32_t levels[] = {0, 1, 2, 3, 4, 5, 6, 7, 8};
923 int i;
925 for (i=0;i<ARRAY_SIZE(levels);i++) {
927 union spoolss_PrinterInfo info;
929 ZERO_STRUCT(info);
931 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, levels[i], &info),
932 "failed to call GetPrinter");
934 if ((levels[i] == 2) && info.info2.drivername && strlen(info.info2.drivername)) {
935 torture_assert(tctx,
936 test_GetPrinterDriver2(tctx, p, handle, info.info2.drivername),
937 "failed to call test_GetPrinterDriver2");
941 return true;
944 static bool test_SetPrinter(struct torture_context *tctx,
945 struct dcerpc_pipe *p,
946 struct policy_handle *handle,
947 struct spoolss_SetPrinterInfoCtr *info_ctr,
948 struct spoolss_DevmodeContainer *devmode_ctr,
949 struct sec_desc_buf *secdesc_ctr,
950 enum spoolss_PrinterControl command)
952 struct spoolss_SetPrinter r;
954 r.in.handle = handle;
955 r.in.info_ctr = info_ctr;
956 r.in.devmode_ctr = devmode_ctr;
957 r.in.secdesc_ctr = secdesc_ctr;
958 r.in.command = command;
960 torture_comment(tctx, "Testing SetPrinter level %d\n", r.in.info_ctr->level);
962 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_SetPrinter(p, tctx, &r),
963 "failed to call SetPrinter");
964 torture_assert_werr_ok(tctx, r.out.result,
965 "failed to call SetPrinter");
967 return true;
970 static bool test_SetPrinter_errors(struct torture_context *tctx,
971 struct dcerpc_pipe *p,
972 struct policy_handle *handle)
974 struct spoolss_SetPrinter r;
975 uint16_t levels[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
976 int i;
978 struct spoolss_SetPrinterInfoCtr info_ctr;
979 struct spoolss_DevmodeContainer devmode_ctr;
980 struct sec_desc_buf secdesc_ctr;
982 info_ctr.level = 0;
983 info_ctr.info.info0 = NULL;
985 ZERO_STRUCT(devmode_ctr);
986 ZERO_STRUCT(secdesc_ctr);
988 r.in.handle = handle;
989 r.in.info_ctr = &info_ctr;
990 r.in.devmode_ctr = &devmode_ctr;
991 r.in.secdesc_ctr = &secdesc_ctr;
992 r.in.command = 0;
994 torture_comment(tctx, "Testing SetPrinter all zero\n");
996 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_SetPrinter(p, tctx, &r),
997 "failed to call SetPrinter");
998 torture_assert_werr_equal(tctx, r.out.result, WERR_INVALID_PARAM,
999 "failed to call SetPrinter");
1001 again:
1002 for (i=0; i < ARRAY_SIZE(levels); i++) {
1004 struct spoolss_SetPrinterInfo0 info0;
1005 struct spoolss_SetPrinterInfo1 info1;
1006 struct spoolss_SetPrinterInfo2 info2;
1007 struct spoolss_SetPrinterInfo3 info3;
1008 struct spoolss_SetPrinterInfo4 info4;
1009 struct spoolss_SetPrinterInfo5 info5;
1010 struct spoolss_SetPrinterInfo6 info6;
1011 struct spoolss_SetPrinterInfo7 info7;
1012 struct spoolss_SetPrinterInfo8 info8;
1013 struct spoolss_SetPrinterInfo9 info9;
1016 info_ctr.level = levels[i];
1017 switch (levels[i]) {
1018 case 0:
1019 ZERO_STRUCT(info0);
1020 info_ctr.info.info0 = &info0;
1021 break;
1022 case 1:
1023 ZERO_STRUCT(info1);
1024 info_ctr.info.info1 = &info1;
1025 break;
1026 case 2:
1027 ZERO_STRUCT(info2);
1028 info_ctr.info.info2 = &info2;
1029 break;
1030 case 3:
1031 ZERO_STRUCT(info3);
1032 info_ctr.info.info3 = &info3;
1033 break;
1034 case 4:
1035 ZERO_STRUCT(info4);
1036 info_ctr.info.info4 = &info4;
1037 break;
1038 case 5:
1039 ZERO_STRUCT(info5);
1040 info_ctr.info.info5 = &info5;
1041 break;
1042 case 6:
1043 ZERO_STRUCT(info6);
1044 info_ctr.info.info6 = &info6;
1045 break;
1046 case 7:
1047 ZERO_STRUCT(info7);
1048 info_ctr.info.info7 = &info7;
1049 break;
1050 case 8:
1051 ZERO_STRUCT(info8);
1052 info_ctr.info.info8 = &info8;
1053 break;
1054 case 9:
1055 ZERO_STRUCT(info9);
1056 info_ctr.info.info9 = &info9;
1057 break;
1060 torture_comment(tctx, "Testing SetPrinter level %d, command %d\n",
1061 info_ctr.level, r.in.command);
1063 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_SetPrinter(p, tctx, &r),
1064 "failed to call SetPrinter");
1066 switch (r.in.command) {
1067 case SPOOLSS_PRINTER_CONTROL_UNPAUSE: /* 0 */
1068 /* is ignored for all levels other then 0 */
1069 if (info_ctr.level > 0) {
1070 /* ignored then */
1071 break;
1073 case SPOOLSS_PRINTER_CONTROL_PAUSE: /* 1 */
1074 case SPOOLSS_PRINTER_CONTROL_RESUME: /* 2 */
1075 case SPOOLSS_PRINTER_CONTROL_PURGE: /* 3 */
1076 if (info_ctr.level > 0) {
1077 /* is invalid for all levels other then 0 */
1078 torture_assert_werr_equal(tctx, r.out.result, WERR_INVALID_PRINTER_COMMAND,
1079 "unexpected error code returned");
1080 continue;
1081 } else {
1082 torture_assert_werr_ok(tctx, r.out.result,
1083 "failed to call SetPrinter with non 0 command");
1084 continue;
1086 break;
1088 case SPOOLSS_PRINTER_CONTROL_SET_STATUS: /* 4 */
1089 /* FIXME: gd needs further investigation */
1090 default:
1091 torture_assert_werr_equal(tctx, r.out.result, WERR_INVALID_PRINTER_COMMAND,
1092 "unexpected error code returned");
1093 continue;
1096 switch (info_ctr.level) {
1097 case 1:
1098 torture_assert_werr_equal(tctx, r.out.result, WERR_UNKNOWN_LEVEL,
1099 "unexpected error code returned");
1100 break;
1101 case 2:
1102 torture_assert_werr_equal(tctx, r.out.result, WERR_UNKNOWN_PRINTER_DRIVER,
1103 "unexpected error code returned");
1104 break;
1105 case 3:
1106 case 4:
1107 case 5:
1108 case 7:
1109 torture_assert_werr_equal(tctx, r.out.result, WERR_INVALID_PARAM,
1110 "unexpected error code returned");
1111 break;
1112 case 9:
1113 torture_assert_werr_equal(tctx, r.out.result, WERR_NOT_SUPPORTED,
1114 "unexpected error code returned");
1115 break;
1116 default:
1117 torture_assert_werr_ok(tctx, r.out.result,
1118 "failed to call SetPrinter");
1119 break;
1123 if (r.in.command < 5) {
1124 r.in.command++;
1125 goto again;
1128 return true;
1131 static void clear_info2(struct spoolss_SetPrinterInfoCtr *r)
1133 if ((r->level == 2) && (r->info.info2)) {
1134 r->info.info2->secdesc_ptr = 0;
1135 r->info.info2->devmode_ptr = 0;
1139 static bool test_PrinterInfo(struct torture_context *tctx,
1140 struct dcerpc_pipe *p,
1141 struct policy_handle *handle)
1143 NTSTATUS status;
1144 struct spoolss_SetPrinter s;
1145 struct spoolss_GetPrinter q;
1146 struct spoolss_GetPrinter q0;
1147 struct spoolss_SetPrinterInfoCtr info_ctr;
1148 union spoolss_PrinterInfo info;
1149 struct spoolss_DevmodeContainer devmode_ctr;
1150 struct sec_desc_buf secdesc_ctr;
1151 uint32_t needed;
1152 bool ret = true;
1153 int i;
1155 uint32_t status_list[] = {
1156 /* these do not stick
1157 PRINTER_STATUS_PAUSED,
1158 PRINTER_STATUS_ERROR,
1159 PRINTER_STATUS_PENDING_DELETION, */
1160 PRINTER_STATUS_PAPER_JAM,
1161 PRINTER_STATUS_PAPER_OUT,
1162 PRINTER_STATUS_MANUAL_FEED,
1163 PRINTER_STATUS_PAPER_PROBLEM,
1164 PRINTER_STATUS_OFFLINE,
1165 PRINTER_STATUS_IO_ACTIVE,
1166 PRINTER_STATUS_BUSY,
1167 PRINTER_STATUS_PRINTING,
1168 PRINTER_STATUS_OUTPUT_BIN_FULL,
1169 PRINTER_STATUS_NOT_AVAILABLE,
1170 PRINTER_STATUS_WAITING,
1171 PRINTER_STATUS_PROCESSING,
1172 PRINTER_STATUS_INITIALIZING,
1173 PRINTER_STATUS_WARMING_UP,
1174 PRINTER_STATUS_TONER_LOW,
1175 PRINTER_STATUS_NO_TONER,
1176 PRINTER_STATUS_PAGE_PUNT,
1177 PRINTER_STATUS_USER_INTERVENTION,
1178 PRINTER_STATUS_OUT_OF_MEMORY,
1179 PRINTER_STATUS_DOOR_OPEN,
1180 PRINTER_STATUS_SERVER_UNKNOWN,
1181 PRINTER_STATUS_POWER_SAVE,
1182 /* these do not stick
1183 0x02000000,
1184 0x04000000,
1185 0x08000000,
1186 0x10000000,
1187 0x20000000,
1188 0x40000000,
1189 0x80000000 */
1191 uint32_t default_attribute = PRINTER_ATTRIBUTE_LOCAL;
1192 uint32_t attribute_list[] = {
1193 PRINTER_ATTRIBUTE_QUEUED,
1194 /* fails with WERR_INVALID_DATATYPE:
1195 PRINTER_ATTRIBUTE_DIRECT, */
1196 /* does not stick
1197 PRINTER_ATTRIBUTE_DEFAULT, */
1198 PRINTER_ATTRIBUTE_SHARED,
1199 /* does not stick
1200 PRINTER_ATTRIBUTE_NETWORK, */
1201 PRINTER_ATTRIBUTE_HIDDEN,
1202 PRINTER_ATTRIBUTE_LOCAL,
1203 PRINTER_ATTRIBUTE_ENABLE_DEVQ,
1204 PRINTER_ATTRIBUTE_KEEPPRINTEDJOBS,
1205 PRINTER_ATTRIBUTE_DO_COMPLETE_FIRST,
1206 PRINTER_ATTRIBUTE_WORK_OFFLINE,
1207 /* does not stick
1208 PRINTER_ATTRIBUTE_ENABLE_BIDI, */
1209 /* fails with WERR_INVALID_DATATYPE:
1210 PRINTER_ATTRIBUTE_RAW_ONLY, */
1211 /* these do not stick
1212 PRINTER_ATTRIBUTE_PUBLISHED,
1213 PRINTER_ATTRIBUTE_FAX,
1214 PRINTER_ATTRIBUTE_TS,
1215 0x00010000,
1216 0x00020000,
1217 0x00040000,
1218 0x00080000,
1219 0x00100000,
1220 0x00200000,
1221 0x00400000,
1222 0x00800000,
1223 0x01000000,
1224 0x02000000,
1225 0x04000000,
1226 0x08000000,
1227 0x10000000,
1228 0x20000000,
1229 0x40000000,
1230 0x80000000 */
1233 ZERO_STRUCT(devmode_ctr);
1234 ZERO_STRUCT(secdesc_ctr);
1236 s.in.handle = handle;
1237 s.in.command = 0;
1238 s.in.info_ctr = &info_ctr;
1239 s.in.devmode_ctr = &devmode_ctr;
1240 s.in.secdesc_ctr = &secdesc_ctr;
1242 q.in.handle = handle;
1243 q.out.info = &info;
1244 q0 = q;
1246 #define TESTGETCALL(call, r) \
1247 r.in.buffer = NULL; \
1248 r.in.offered = 0;\
1249 r.out.needed = &needed; \
1250 status = dcerpc_spoolss_ ##call(p, tctx, &r); \
1251 if (!NT_STATUS_IS_OK(status)) { \
1252 torture_comment(tctx, #call " level %u failed - %s (%s)\n", \
1253 r.in.level, nt_errstr(status), __location__); \
1254 ret = false; \
1255 break; \
1257 if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {\
1258 DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed); \
1259 data_blob_clear(&blob); \
1260 r.in.buffer = &blob; \
1261 r.in.offered = needed; \
1263 status = dcerpc_spoolss_ ##call(p, tctx, &r); \
1264 if (!NT_STATUS_IS_OK(status)) { \
1265 torture_comment(tctx, #call " level %u failed - %s (%s)\n", \
1266 r.in.level, nt_errstr(status), __location__); \
1267 ret = false; \
1268 break; \
1270 if (!W_ERROR_IS_OK(r.out.result)) { \
1271 torture_comment(tctx, #call " level %u failed - %s (%s)\n", \
1272 r.in.level, win_errstr(r.out.result), __location__); \
1273 ret = false; \
1274 break; \
1278 #define TESTSETCALL_EXP(call, r, err) \
1279 clear_info2(&info_ctr);\
1280 status = dcerpc_spoolss_ ##call(p, tctx, &r); \
1281 if (!NT_STATUS_IS_OK(status)) { \
1282 torture_comment(tctx, #call " level %u failed - %s (%s)\n", \
1283 r.in.info_ctr->level, nt_errstr(status), __location__); \
1284 ret = false; \
1285 break; \
1287 if (!W_ERROR_IS_OK(err)) { \
1288 if (!W_ERROR_EQUAL(err, r.out.result)) { \
1289 torture_comment(tctx, #call " level %u failed - %s, expected %s (%s)\n", \
1290 r.in.info_ctr->level, win_errstr(r.out.result), win_errstr(err), __location__); \
1291 ret = false; \
1293 break; \
1295 if (!W_ERROR_IS_OK(r.out.result)) { \
1296 torture_comment(tctx, #call " level %u failed - %s (%s)\n", \
1297 r.in.info_ctr->level, win_errstr(r.out.result), __location__); \
1298 ret = false; \
1299 break; \
1302 #define TESTSETCALL(call, r) \
1303 TESTSETCALL_EXP(call, r, WERR_OK)
1305 #define STRING_EQUAL(s1, s2, field) \
1306 if ((s1 && !s2) || (s2 && !s1) || strcmp(s1, s2)) { \
1307 torture_comment(tctx, "Failed to set %s to '%s' (%s)\n", \
1308 #field, s2, __location__); \
1309 ret = false; \
1310 break; \
1313 #define MEM_EQUAL(s1, s2, length, field) \
1314 if ((s1 && !s2) || (s2 && !s1) || memcmp(s1, s2, length)) { \
1315 torture_comment(tctx, "Failed to set %s to '%s' (%s)\n", \
1316 #field, (const char *)s2, __location__); \
1317 ret = false; \
1318 break; \
1321 #define INT_EQUAL(i1, i2, field) \
1322 if (i1 != i2) { \
1323 torture_comment(tctx, "Failed to set %s to 0x%llx - got 0x%llx (%s)\n", \
1324 #field, (unsigned long long)i2, (unsigned long long)i1, __location__); \
1325 ret = false; \
1326 break; \
1329 #define SD_EQUAL(sd1, sd2, field) \
1330 if (!security_descriptor_equal(sd1, sd2)) { \
1331 torture_comment(tctx, "Failed to set %s (%s)\n", \
1332 #field, __location__); \
1333 ret = false; \
1334 break; \
1337 #define TEST_PRINTERINFO_STRING_EXP_ERR(lvl1, field1, lvl2, field2, value, err) do { \
1338 torture_comment(tctx, "field test %d/%s vs %d/%s\n", lvl1, #field1, lvl2, #field2); \
1339 q.in.level = lvl1; \
1340 TESTGETCALL(GetPrinter, q) \
1341 info_ctr.level = lvl1; \
1342 info_ctr.info.info ## lvl1 = (struct spoolss_SetPrinterInfo ## lvl1 *)&q.out.info->info ## lvl1; \
1343 info_ctr.info.info ## lvl1->field1 = value;\
1344 TESTSETCALL_EXP(SetPrinter, s, err) \
1345 info_ctr.info.info ## lvl1->field1 = ""; \
1346 TESTGETCALL(GetPrinter, q) \
1347 info_ctr.info.info ## lvl1->field1 = value; \
1348 STRING_EQUAL(info_ctr.info.info ## lvl1->field1, value, field1); \
1349 q.in.level = lvl2; \
1350 TESTGETCALL(GetPrinter, q) \
1351 info_ctr.info.info ## lvl2 = (struct spoolss_SetPrinterInfo ## lvl2 *)&q.out.info->info ## lvl2; \
1352 STRING_EQUAL(info_ctr.info.info ## lvl2->field2, value, field2); \
1353 } while (0)
1355 #define TEST_PRINTERINFO_STRING(lvl1, field1, lvl2, field2, value) do { \
1356 TEST_PRINTERINFO_STRING_EXP_ERR(lvl1, field1, lvl2, field2, value, WERR_OK); \
1357 } while (0);
1359 #define TEST_PRINTERINFO_INT_EXP(lvl1, field1, lvl2, field2, value, exp_value) do { \
1360 torture_comment(tctx, "field test %d/%s vs %d/%s\n", lvl1, #field1, lvl2, #field2); \
1361 q.in.level = lvl1; \
1362 TESTGETCALL(GetPrinter, q) \
1363 info_ctr.level = lvl1; \
1364 info_ctr.info.info ## lvl1 = (struct spoolss_SetPrinterInfo ## lvl1 *)&q.out.info->info ## lvl1; \
1365 info_ctr.info.info ## lvl1->field1 = value; \
1366 TESTSETCALL(SetPrinter, s) \
1367 info_ctr.info.info ## lvl1->field1 = 0; \
1368 TESTGETCALL(GetPrinter, q) \
1369 info_ctr.info.info ## lvl1 = (struct spoolss_SetPrinterInfo ## lvl1 *)&q.out.info->info ## lvl1; \
1370 INT_EQUAL(info_ctr.info.info ## lvl1->field1, exp_value, field1); \
1371 q.in.level = lvl2; \
1372 TESTGETCALL(GetPrinter, q) \
1373 info_ctr.info.info ## lvl2 = (struct spoolss_SetPrinterInfo ## lvl2 *)&q.out.info->info ## lvl2; \
1374 INT_EQUAL(info_ctr.info.info ## lvl2->field2, exp_value, field1); \
1375 } while (0)
1377 #define TEST_PRINTERINFO_INT(lvl1, field1, lvl2, field2, value) do { \
1378 TEST_PRINTERINFO_INT_EXP(lvl1, field1, lvl2, field2, value, value); \
1379 } while (0)
1381 q0.in.level = 0;
1382 do { TESTGETCALL(GetPrinter, q0) } while (0);
1384 TEST_PRINTERINFO_STRING(2, comment, 1, comment, "xx2-1 comment");
1385 TEST_PRINTERINFO_STRING(2, comment, 2, comment, "xx2-2 comment");
1387 /* level 0 printername does not stick */
1388 /* TEST_PRINTERINFO_STRING(2, printername, 0, printername, "xx2-0 printer"); */
1389 TEST_PRINTERINFO_STRING(2, printername, 1, name, "xx2-1 printer");
1390 TEST_PRINTERINFO_STRING(2, printername, 2, printername, "xx2-2 printer");
1391 TEST_PRINTERINFO_STRING(2, printername, 4, printername, "xx2-4 printer");
1392 TEST_PRINTERINFO_STRING(2, printername, 5, printername, "xx2-5 printer");
1393 /* TEST_PRINTERINFO_STRING(4, printername, 0, printername, "xx4-0 printer"); */
1394 TEST_PRINTERINFO_STRING(4, printername, 1, name, "xx4-1 printer");
1395 TEST_PRINTERINFO_STRING(4, printername, 2, printername, "xx4-2 printer");
1396 TEST_PRINTERINFO_STRING(4, printername, 4, printername, "xx4-4 printer");
1397 TEST_PRINTERINFO_STRING(4, printername, 5, printername, "xx4-5 printer");
1398 /* TEST_PRINTERINFO_STRING(5, printername, 0, printername, "xx5-0 printer"); */
1399 TEST_PRINTERINFO_STRING(5, printername, 1, name, "xx5-1 printer");
1400 TEST_PRINTERINFO_STRING(5, printername, 2, printername, "xx5-2 printer");
1401 TEST_PRINTERINFO_STRING(5, printername, 4, printername, "xx5-4 printer");
1402 TEST_PRINTERINFO_STRING(5, printername, 5, printername, "xx5-5 printer");
1404 /* servername can be set but does not stick
1405 TEST_PRINTERINFO_STRING(2, servername, 0, servername, "xx2-0 servername");
1406 TEST_PRINTERINFO_STRING(2, servername, 2, servername, "xx2-2 servername");
1407 TEST_PRINTERINFO_STRING(2, servername, 4, servername, "xx2-4 servername");
1410 /* passing an invalid port will result in WERR_UNKNOWN_PORT */
1411 TEST_PRINTERINFO_STRING_EXP_ERR(2, portname, 2, portname, "xx2-2 portname", WERR_UNKNOWN_PORT);
1412 TEST_PRINTERINFO_STRING_EXP_ERR(2, portname, 5, portname, "xx2-5 portname", WERR_UNKNOWN_PORT);
1413 TEST_PRINTERINFO_STRING_EXP_ERR(5, portname, 2, portname, "xx5-2 portname", WERR_UNKNOWN_PORT);
1414 TEST_PRINTERINFO_STRING_EXP_ERR(5, portname, 5, portname, "xx5-5 portname", WERR_UNKNOWN_PORT);
1416 TEST_PRINTERINFO_STRING(2, sharename, 2, sharename, "xx2-2 sharename");
1417 /* passing an invalid driver will result in WERR_UNKNOWN_PRINTER_DRIVER */
1418 TEST_PRINTERINFO_STRING_EXP_ERR(2, drivername, 2, drivername, "xx2-2 drivername", WERR_UNKNOWN_PRINTER_DRIVER);
1419 TEST_PRINTERINFO_STRING(2, location, 2, location, "xx2-2 location");
1420 /* passing an invalid sepfile will result in WERR_INVALID_SEPARATOR_FILE */
1421 TEST_PRINTERINFO_STRING_EXP_ERR(2, sepfile, 2, sepfile, "xx2-2 sepfile", WERR_INVALID_SEPARATOR_FILE);
1422 /* passing an invalid printprocessor will result in WERR_UNKNOWN_PRINTPROCESSOR */
1423 TEST_PRINTERINFO_STRING_EXP_ERR(2, printprocessor, 2, printprocessor, "xx2-2 printprocessor", WERR_UNKNOWN_PRINTPROCESSOR);
1424 TEST_PRINTERINFO_STRING(2, datatype, 2, datatype, "xx2-2 datatype");
1425 TEST_PRINTERINFO_STRING(2, parameters, 2, parameters, "xx2-2 parameters");
1427 for (i=0; i < ARRAY_SIZE(attribute_list); i++) {
1428 /* TEST_PRINTERINFO_INT_EXP(2, attributes, 1, flags,
1429 attribute_list[i],
1430 (attribute_list[i] | default_attribute)
1431 ); */
1432 TEST_PRINTERINFO_INT_EXP(2, attributes, 2, attributes,
1433 attribute_list[i],
1434 (attribute_list[i] | default_attribute)
1436 TEST_PRINTERINFO_INT_EXP(2, attributes, 4, attributes,
1437 attribute_list[i],
1438 (attribute_list[i] | default_attribute)
1440 TEST_PRINTERINFO_INT_EXP(2, attributes, 5, attributes,
1441 attribute_list[i],
1442 (attribute_list[i] | default_attribute)
1444 /* TEST_PRINTERINFO_INT_EXP(4, attributes, 1, flags,
1445 attribute_list[i],
1446 (attribute_list[i] | default_attribute)
1447 ); */
1448 TEST_PRINTERINFO_INT_EXP(4, attributes, 2, attributes,
1449 attribute_list[i],
1450 (attribute_list[i] | default_attribute)
1452 TEST_PRINTERINFO_INT_EXP(4, attributes, 4, attributes,
1453 attribute_list[i],
1454 (attribute_list[i] | default_attribute)
1456 TEST_PRINTERINFO_INT_EXP(4, attributes, 5, attributes,
1457 attribute_list[i],
1458 (attribute_list[i] | default_attribute)
1460 /* TEST_PRINTERINFO_INT_EXP(5, attributes, 1, flags,
1461 attribute_list[i],
1462 (attribute_list[i] | default_attribute)
1463 ); */
1464 TEST_PRINTERINFO_INT_EXP(5, attributes, 2, attributes,
1465 attribute_list[i],
1466 (attribute_list[i] | default_attribute)
1468 TEST_PRINTERINFO_INT_EXP(5, attributes, 4, attributes,
1469 attribute_list[i],
1470 (attribute_list[i] | default_attribute)
1472 TEST_PRINTERINFO_INT_EXP(5, attributes, 5, attributes,
1473 attribute_list[i],
1474 (attribute_list[i] | default_attribute)
1478 for (i=0; i < ARRAY_SIZE(status_list); i++) {
1479 /* level 2 sets do not stick
1480 TEST_PRINTERINFO_INT(2, status, 0, status, status_list[i]);
1481 TEST_PRINTERINFO_INT(2, status, 2, status, status_list[i]);
1482 TEST_PRINTERINFO_INT(2, status, 6, status, status_list[i]); */
1483 TEST_PRINTERINFO_INT(6, status, 0, status, status_list[i]);
1484 TEST_PRINTERINFO_INT(6, status, 2, status, status_list[i]);
1485 TEST_PRINTERINFO_INT(6, status, 6, status, status_list[i]);
1488 /* priorities need to be between 0 and 99
1489 passing an invalid priority will result in WERR_INVALID_PRIORITY */
1490 TEST_PRINTERINFO_INT(2, priority, 2, priority, 0);
1491 TEST_PRINTERINFO_INT(2, priority, 2, priority, 1);
1492 TEST_PRINTERINFO_INT(2, priority, 2, priority, 99);
1493 /* TEST_PRINTERINFO_INT(2, priority, 2, priority, 100); */
1494 TEST_PRINTERINFO_INT(2, defaultpriority,2, defaultpriority, 0);
1495 TEST_PRINTERINFO_INT(2, defaultpriority,2, defaultpriority, 1);
1496 TEST_PRINTERINFO_INT(2, defaultpriority,2, defaultpriority, 99);
1497 /* TEST_PRINTERINFO_INT(2, defaultpriority,2, defaultpriority, 100); */
1499 TEST_PRINTERINFO_INT(2, starttime, 2, starttime, __LINE__);
1500 TEST_PRINTERINFO_INT(2, untiltime, 2, untiltime, __LINE__);
1502 /* does not stick
1503 TEST_PRINTERINFO_INT(2, cjobs, 2, cjobs, __LINE__);
1504 TEST_PRINTERINFO_INT(2, averageppm, 2, averageppm, __LINE__); */
1506 /* does not stick
1507 TEST_PRINTERINFO_INT(5, device_not_selected_timeout, 5, device_not_selected_timeout, __LINE__);
1508 TEST_PRINTERINFO_INT(5, transmission_retry_timeout, 5, transmission_retry_timeout, __LINE__); */
1510 /* FIXME: gd also test devmode and secdesc behavior */
1513 /* verify composition of level 1 description field */
1514 const char *description;
1515 const char *tmp;
1517 q0.in.level = 1;
1518 do { TESTGETCALL(GetPrinter, q0) } while (0);
1520 description = talloc_strdup(tctx, q0.out.info->info1.description);
1522 q0.in.level = 2;
1523 do { TESTGETCALL(GetPrinter, q0) } while (0);
1525 tmp = talloc_asprintf(tctx, "%s,%s,%s",
1526 q0.out.info->info2.printername,
1527 q0.out.info->info2.drivername,
1528 q0.out.info->info2.location);
1530 do { STRING_EQUAL(description, tmp, "description")} while (0);
1533 return ret;
1536 #define torture_assert_sid_equal(torture_ctx,got,expected,cmt)\
1537 do { struct dom_sid *__got = (got), *__expected = (expected); \
1538 if (!dom_sid_equal(__got, __expected)) { \
1539 torture_result(torture_ctx, TORTURE_FAIL, \
1540 __location__": "#got" was %s, expected %s: %s", \
1541 dom_sid_string(torture_ctx, __got), dom_sid_string(torture_ctx, __expected), cmt); \
1542 return false; \
1544 } while(0)
1546 static bool test_security_descriptor_equal(struct torture_context *tctx,
1547 const struct security_descriptor *sd1,
1548 const struct security_descriptor *sd2)
1550 if (sd1 == sd2) {
1551 return true;
1554 if (!sd1 || !sd2) {
1555 torture_comment(tctx, "%s\n", __location__);
1556 return false;
1559 torture_assert_int_equal(tctx, sd1->revision, sd2->revision, "revision mismatch");
1560 torture_assert_int_equal(tctx, sd1->type, sd2->type, "type mismatch");
1562 torture_assert_sid_equal(tctx, sd1->owner_sid, sd2->owner_sid, "owner mismatch");
1563 torture_assert_sid_equal(tctx, sd1->group_sid, sd2->group_sid, "group mismatch");
1565 if (!security_acl_equal(sd1->sacl, sd2->sacl)) {
1566 torture_comment(tctx, "%s: sacl mismatch\n", __location__);
1567 NDR_PRINT_DEBUG(security_acl, sd1->sacl);
1568 NDR_PRINT_DEBUG(security_acl, sd2->sacl);
1569 return false;
1571 if (!security_acl_equal(sd1->dacl, sd2->dacl)) {
1572 torture_comment(tctx, "%s: dacl mismatch\n", __location__);
1573 NDR_PRINT_DEBUG(security_acl, sd1->dacl);
1574 NDR_PRINT_DEBUG(security_acl, sd2->dacl);
1575 return false;
1578 return true;
1581 static bool test_sd_set_level(struct torture_context *tctx,
1582 struct dcerpc_pipe *p,
1583 struct policy_handle *handle,
1584 uint32_t level,
1585 struct security_descriptor *sd)
1587 struct spoolss_SetPrinterInfoCtr info_ctr;
1588 struct spoolss_DevmodeContainer devmode_ctr;
1589 struct sec_desc_buf secdesc_ctr;
1591 ZERO_STRUCT(devmode_ctr);
1592 ZERO_STRUCT(secdesc_ctr);
1594 switch (level) {
1595 case 2: {
1596 union spoolss_PrinterInfo info;
1597 struct spoolss_SetPrinterInfo2 info2;
1598 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 2, &info), "");
1600 info2.servername = info.info2.servername;
1601 info2.printername = info.info2.printername;
1602 info2.sharename = info.info2.sharename;
1603 info2.portname = info.info2.portname;
1604 info2.drivername = info.info2.drivername;
1605 info2.comment = info.info2.comment;
1606 info2.location = info.info2.location;
1607 info2.devmode_ptr = 0;
1608 info2.sepfile = info.info2.sepfile;
1609 info2.printprocessor = info.info2.printprocessor;
1610 info2.datatype = info.info2.datatype;
1611 info2.parameters = info.info2.parameters;
1612 info2.secdesc_ptr = 0;
1613 info2.attributes = info.info2.attributes;
1614 info2.priority = info.info2.priority;
1615 info2.defaultpriority = info.info2.defaultpriority;
1616 info2.starttime = info.info2.starttime;
1617 info2.untiltime = info.info2.untiltime;
1618 info2.status = info.info2.status;
1619 info2.cjobs = info.info2.cjobs;
1620 info2.averageppm = info.info2.averageppm;
1622 info_ctr.level = 2;
1623 info_ctr.info.info2 = &info2;
1625 break;
1627 case 3: {
1628 struct spoolss_SetPrinterInfo3 info3;
1630 info3.sec_desc_ptr = 0;
1632 info_ctr.level = 3;
1633 info_ctr.info.info3 = &info3;
1635 break;
1637 default:
1638 return false;
1641 secdesc_ctr.sd = sd;
1643 torture_assert(tctx,
1644 test_SetPrinter(tctx, p, handle, &info_ctr, &devmode_ctr, &secdesc_ctr, 0), "");
1646 return true;
1649 static bool test_PrinterInfo_SDs(struct torture_context *tctx,
1650 struct dcerpc_pipe *p,
1651 struct policy_handle *handle)
1653 union spoolss_PrinterInfo info;
1654 struct security_descriptor *sd1, *sd2;
1655 int i;
1657 /* just compare level 2 and level 3 */
1659 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 2, &info), "");
1661 sd1 = info.info2.secdesc;
1663 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 3, &info), "");
1665 sd2 = info.info3.secdesc;
1667 torture_assert(tctx, test_security_descriptor_equal(tctx, sd1, sd2), "");
1670 /* query level 2, set level 2, query level 2 */
1672 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 2, &info), "");
1674 sd1 = info.info2.secdesc;
1676 torture_assert(tctx, test_sd_set_level(tctx, p, handle, 2, sd1), "");
1678 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 2, &info), "");
1680 sd2 = info.info2.secdesc;
1681 if (sd1->type & SEC_DESC_DACL_DEFAULTED) {
1682 torture_comment(tctx, "removing SEC_DESC_DACL_DEFAULTED\n");
1683 sd1->type &= ~SEC_DESC_DACL_DEFAULTED;
1686 torture_assert(tctx, test_security_descriptor_equal(tctx, sd1, sd2), "");
1689 /* query level 2, set level 3, query level 2 */
1691 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 2, &info), "");
1693 sd1 = info.info2.secdesc;
1695 torture_assert(tctx, test_sd_set_level(tctx, p, handle, 3, sd1), "");
1697 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 2, &info), "");
1699 sd2 = info.info2.secdesc;
1701 torture_assert(tctx, test_security_descriptor_equal(tctx, sd1, sd2), "");
1704 /* set modified sd level 3, query level 2 */
1706 for (i=0; i < 93; i++) {
1707 struct security_ace a;
1708 const char *sid_string = talloc_asprintf(tctx, "S-1-5-32-9999%i", i);
1709 a.type = SEC_ACE_TYPE_ACCESS_ALLOWED;
1710 a.flags = 0;
1711 a.size = 0; /* autogenerated */
1712 a.access_mask = 0;
1713 a.trustee = *dom_sid_parse_talloc(tctx, sid_string);
1714 torture_assert_ntstatus_ok(tctx, security_descriptor_dacl_add(sd1, &a), "");
1717 torture_assert(tctx, test_sd_set_level(tctx, p, handle, 3, sd1), "");
1719 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 2, &info), "");
1720 sd2 = info.info2.secdesc;
1722 if (sd1->type & SEC_DESC_DACL_DEFAULTED) {
1723 torture_comment(tctx, "removing SEC_DESC_DACL_DEFAULTED\n");
1724 sd1->type &= ~SEC_DESC_DACL_DEFAULTED;
1727 torture_assert(tctx, test_security_descriptor_equal(tctx, sd1, sd2), "");
1729 return true;
1733 * wrapper call that saves original sd, runs tests, and restores sd
1736 static bool test_PrinterInfo_SD(struct torture_context *tctx,
1737 struct dcerpc_pipe *p,
1738 struct policy_handle *handle)
1740 union spoolss_PrinterInfo info;
1741 struct security_descriptor *sd;
1742 bool ret = true;
1744 torture_comment(tctx, "\nTesting Printer Security Descriptors\n");
1746 /* save original sd */
1748 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 2, &info),
1749 "failed to get initial security descriptor");
1751 sd = security_descriptor_copy(tctx, info.info2.secdesc);
1753 /* run tests */
1755 ret = test_PrinterInfo_SDs(tctx, p, handle);
1757 /* restore original sd */
1759 torture_assert(tctx, test_sd_set_level(tctx, p, handle, 3, sd),
1760 "failed to restore initial security descriptor");
1762 torture_comment(tctx, "Printer Security Descriptors test %s\n",
1763 ret ? "succeeded" : "failed");
1766 return ret;
1769 static bool test_devmode_set_level(struct torture_context *tctx,
1770 struct dcerpc_pipe *p,
1771 struct policy_handle *handle,
1772 uint32_t level,
1773 struct spoolss_DeviceMode *devmode)
1775 struct spoolss_SetPrinterInfoCtr info_ctr;
1776 struct spoolss_DevmodeContainer devmode_ctr;
1777 struct sec_desc_buf secdesc_ctr;
1779 ZERO_STRUCT(devmode_ctr);
1780 ZERO_STRUCT(secdesc_ctr);
1782 switch (level) {
1783 case 2: {
1784 union spoolss_PrinterInfo info;
1785 struct spoolss_SetPrinterInfo2 info2;
1786 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 2, &info), "");
1788 info2.servername = info.info2.servername;
1789 info2.printername = info.info2.printername;
1790 info2.sharename = info.info2.sharename;
1791 info2.portname = info.info2.portname;
1792 info2.drivername = info.info2.drivername;
1793 info2.comment = info.info2.comment;
1794 info2.location = info.info2.location;
1795 info2.devmode_ptr = 0;
1796 info2.sepfile = info.info2.sepfile;
1797 info2.printprocessor = info.info2.printprocessor;
1798 info2.datatype = info.info2.datatype;
1799 info2.parameters = info.info2.parameters;
1800 info2.secdesc_ptr = 0;
1801 info2.attributes = info.info2.attributes;
1802 info2.priority = info.info2.priority;
1803 info2.defaultpriority = info.info2.defaultpriority;
1804 info2.starttime = info.info2.starttime;
1805 info2.untiltime = info.info2.untiltime;
1806 info2.status = info.info2.status;
1807 info2.cjobs = info.info2.cjobs;
1808 info2.averageppm = info.info2.averageppm;
1810 info_ctr.level = 2;
1811 info_ctr.info.info2 = &info2;
1813 break;
1815 case 8: {
1816 struct spoolss_SetPrinterInfo8 info8;
1818 info8.devmode_ptr = 0;
1820 info_ctr.level = 8;
1821 info_ctr.info.info8 = &info8;
1823 break;
1825 default:
1826 return false;
1829 devmode_ctr.devmode = devmode;
1831 torture_assert(tctx,
1832 test_SetPrinter(tctx, p, handle, &info_ctr, &devmode_ctr, &secdesc_ctr, 0), "");
1834 return true;
1838 static bool test_devicemode_equal(struct torture_context *tctx,
1839 const struct spoolss_DeviceMode *d1,
1840 const struct spoolss_DeviceMode *d2)
1842 if (d1 == d2) {
1843 return true;
1846 if (!d1 || !d2) {
1847 torture_comment(tctx, "%s\n", __location__);
1848 return false;
1850 torture_assert_str_equal(tctx, d1->devicename, d2->devicename, "devicename mismatch");
1851 torture_assert_int_equal(tctx, d1->specversion, d2->specversion, "specversion mismatch");
1852 torture_assert_int_equal(tctx, d1->driverversion, d2->driverversion, "driverversion mismatch");
1853 torture_assert_int_equal(tctx, d1->size, d2->size, "size mismatch");
1854 torture_assert_int_equal(tctx, d1->__driverextra_length, d2->__driverextra_length, "__driverextra_length mismatch");
1855 torture_assert_int_equal(tctx, d1->fields, d2->fields, "fields mismatch");
1856 torture_assert_int_equal(tctx, d1->orientation, d2->orientation, "orientation mismatch");
1857 torture_assert_int_equal(tctx, d1->papersize, d2->papersize, "papersize mismatch");
1858 torture_assert_int_equal(tctx, d1->paperlength, d2->paperlength, "paperlength mismatch");
1859 torture_assert_int_equal(tctx, d1->paperwidth, d2->paperwidth, "paperwidth mismatch");
1860 torture_assert_int_equal(tctx, d1->scale, d2->scale, "scale mismatch");
1861 torture_assert_int_equal(tctx, d1->copies, d2->copies, "copies mismatch");
1862 torture_assert_int_equal(tctx, d1->defaultsource, d2->defaultsource, "defaultsource mismatch");
1863 torture_assert_int_equal(tctx, d1->printquality, d2->printquality, "printquality mismatch");
1864 torture_assert_int_equal(tctx, d1->color, d2->color, "color mismatch");
1865 torture_assert_int_equal(tctx, d1->duplex, d2->duplex, "duplex mismatch");
1866 torture_assert_int_equal(tctx, d1->yresolution, d2->yresolution, "yresolution mismatch");
1867 torture_assert_int_equal(tctx, d1->ttoption, d2->ttoption, "ttoption mismatch");
1868 torture_assert_int_equal(tctx, d1->collate, d2->collate, "collate mismatch");
1869 torture_assert_str_equal(tctx, d1->formname, d2->formname, "formname mismatch");
1870 torture_assert_int_equal(tctx, d1->logpixels, d2->logpixels, "logpixels mismatch");
1871 torture_assert_int_equal(tctx, d1->bitsperpel, d2->bitsperpel, "bitsperpel mismatch");
1872 torture_assert_int_equal(tctx, d1->pelswidth, d2->pelswidth, "pelswidth mismatch");
1873 torture_assert_int_equal(tctx, d1->pelsheight, d2->pelsheight, "pelsheight mismatch");
1874 torture_assert_int_equal(tctx, d1->displayflags, d2->displayflags, "displayflags mismatch");
1875 torture_assert_int_equal(tctx, d1->displayfrequency, d2->displayfrequency, "displayfrequency mismatch");
1876 torture_assert_int_equal(tctx, d1->icmmethod, d2->icmmethod, "icmmethod mismatch");
1877 torture_assert_int_equal(tctx, d1->icmintent, d2->icmintent, "icmintent mismatch");
1878 torture_assert_int_equal(tctx, d1->mediatype, d2->mediatype, "mediatype mismatch");
1879 torture_assert_int_equal(tctx, d1->dithertype, d2->dithertype, "dithertype mismatch");
1880 torture_assert_int_equal(tctx, d1->reserved1, d2->reserved1, "reserved1 mismatch");
1881 torture_assert_int_equal(tctx, d1->reserved2, d2->reserved2, "reserved2 mismatch");
1882 torture_assert_int_equal(tctx, d1->panningwidth, d2->panningwidth, "panningwidth mismatch");
1883 torture_assert_int_equal(tctx, d1->panningheight, d2->panningheight, "panningheight mismatch");
1884 torture_assert_data_blob_equal(tctx, d1->driverextra_data, d2->driverextra_data, "driverextra_data mismatch");
1886 return true;
1889 static bool call_OpenPrinterEx(struct torture_context *tctx,
1890 struct dcerpc_pipe *p,
1891 const char *name,
1892 struct spoolss_DeviceMode *devmode,
1893 struct policy_handle *handle);
1895 static bool test_ClosePrinter(struct torture_context *tctx,
1896 struct dcerpc_pipe *p,
1897 struct policy_handle *handle);
1899 static bool test_PrinterInfo_DevModes(struct torture_context *tctx,
1900 struct dcerpc_pipe *p,
1901 struct policy_handle *handle,
1902 const char *name)
1904 union spoolss_PrinterInfo info;
1905 struct spoolss_DeviceMode *devmode;
1906 struct spoolss_DeviceMode *devmode2;
1907 struct policy_handle handle_devmode;
1909 /* simply compare level8 and level2 devmode */
1911 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 8, &info), "");
1913 devmode = info.info8.devmode;
1915 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 2, &info), "");
1917 devmode2 = info.info2.devmode;
1919 torture_assert(tctx, test_devicemode_equal(tctx, devmode, devmode2), "");
1922 /* change formname upon open and see if it persists in getprinter calls */
1924 devmode->formname = talloc_strdup(tctx, "A4");
1926 torture_assert(tctx, call_OpenPrinterEx(tctx, p, name, devmode, &handle_devmode),
1927 "failed to open printer handle");
1929 torture_assert(tctx, test_GetPrinter_level(tctx, p, &handle_devmode, 8, &info), "");
1931 devmode2 = info.info8.devmode;
1933 if (strequal(devmode->devicename, devmode2->devicename)) {
1934 torture_fail(tctx, "devicename is the same");
1937 if (strequal(devmode->formname, devmode2->formname)) {
1938 torture_fail(tctx, "formname is the same");
1941 torture_assert(tctx, test_GetPrinter_level(tctx, p, &handle_devmode, 2, &info), "");
1943 devmode2 = info.info2.devmode;
1945 if (strequal(devmode->devicename, devmode2->devicename)) {
1946 torture_fail(tctx, "devicename is the same");
1949 if (strequal(devmode->formname, devmode2->formname)) {
1950 torture_fail(tctx, "formname is the same");
1953 test_ClosePrinter(tctx, p, &handle_devmode);
1956 /* set devicemode level 8 and see if it persists */
1958 devmode->copies = 93;
1959 devmode->formname = talloc_strdup(tctx, "Legal");
1961 torture_assert(tctx, test_devmode_set_level(tctx, p, handle, 8, devmode), "");
1963 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 8, &info), "");
1965 devmode2 = info.info8.devmode;
1967 torture_assert(tctx, test_devicemode_equal(tctx, devmode, devmode2), "");
1969 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 2, &info), "");
1971 devmode2 = info.info2.devmode;
1973 torture_assert(tctx, test_devicemode_equal(tctx, devmode, devmode2), "");
1976 /* set devicemode level 2 and see if it persists */
1978 devmode->copies = 39;
1979 devmode->formname = talloc_strdup(tctx, "Letter");
1981 torture_assert(tctx, test_devmode_set_level(tctx, p, handle, 8, devmode), "");
1983 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 8, &info), "");
1985 devmode2 = info.info8.devmode;
1987 torture_assert(tctx, test_devicemode_equal(tctx, devmode, devmode2), "");
1989 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 2, &info), "");
1991 devmode2 = info.info2.devmode;
1993 torture_assert(tctx, test_devicemode_equal(tctx, devmode, devmode2), "");
1996 return true;
2000 * wrapper call that saves original devmode, runs tests, and restores devmode
2003 static bool test_PrinterInfo_DevMode(struct torture_context *tctx,
2004 struct dcerpc_pipe *p,
2005 struct policy_handle *handle,
2006 const char *name)
2008 union spoolss_PrinterInfo info;
2009 struct spoolss_DeviceMode *devmode;
2010 bool ret = true;
2012 torture_comment(tctx, "\nTesting Printer Devicemodes\n");
2014 /* save original devmode */
2016 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 8, &info),
2017 "failed to get initial global devicemode");
2019 devmode = info.info8.devmode;
2021 /* run tests */
2023 ret = test_PrinterInfo_DevModes(tctx, p, handle, name);
2025 /* restore original devmode */
2027 torture_assert(tctx, test_devmode_set_level(tctx, p, handle, 8, devmode),
2028 "failed to restore initial global device mode");
2030 torture_comment(tctx, "Printer Devicemodes test %s\n",
2031 ret ? "succeeded" : "failed");
2034 return ret;
2037 static bool test_ClosePrinter(struct torture_context *tctx,
2038 struct dcerpc_pipe *p,
2039 struct policy_handle *handle)
2041 NTSTATUS status;
2042 struct spoolss_ClosePrinter r;
2044 r.in.handle = handle;
2045 r.out.handle = handle;
2047 torture_comment(tctx, "Testing ClosePrinter\n");
2049 status = dcerpc_spoolss_ClosePrinter(p, tctx, &r);
2050 torture_assert_ntstatus_ok(tctx, status, "ClosePrinter failed");
2051 torture_assert_werr_ok(tctx, r.out.result, "ClosePrinter failed");
2053 return true;
2056 static bool test_GetForm(struct torture_context *tctx,
2057 struct dcerpc_pipe *p,
2058 struct policy_handle *handle,
2059 const char *form_name,
2060 uint32_t level)
2062 NTSTATUS status;
2063 struct spoolss_GetForm r;
2064 uint32_t needed;
2066 r.in.handle = handle;
2067 r.in.form_name = form_name;
2068 r.in.level = level;
2069 r.in.buffer = NULL;
2070 r.in.offered = 0;
2071 r.out.needed = &needed;
2073 torture_comment(tctx, "Testing GetForm level %d\n", r.in.level);
2075 status = dcerpc_spoolss_GetForm(p, tctx, &r);
2076 torture_assert_ntstatus_ok(tctx, status, "GetForm failed");
2078 if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
2079 DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed);
2080 data_blob_clear(&blob);
2081 r.in.buffer = &blob;
2082 r.in.offered = needed;
2083 status = dcerpc_spoolss_GetForm(p, tctx, &r);
2084 torture_assert_ntstatus_ok(tctx, status, "GetForm failed");
2086 torture_assert_werr_ok(tctx, r.out.result, "GetForm failed");
2088 torture_assert(tctx, r.out.info, "No form info returned");
2091 torture_assert_werr_ok(tctx, r.out.result, "GetForm failed");
2093 CHECK_NEEDED_SIZE_LEVEL(spoolss_FormInfo, r.out.info, r.in.level, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
2095 return true;
2098 static bool test_EnumForms(struct torture_context *tctx,
2099 struct dcerpc_pipe *p,
2100 struct policy_handle *handle, bool print_server)
2102 NTSTATUS status;
2103 struct spoolss_EnumForms r;
2104 bool ret = true;
2105 uint32_t needed;
2106 uint32_t count;
2107 uint32_t levels[] = { 1, 2 };
2108 int i;
2110 for (i=0; i<ARRAY_SIZE(levels); i++) {
2112 union spoolss_FormInfo *info;
2114 r.in.handle = handle;
2115 r.in.level = levels[i];
2116 r.in.buffer = NULL;
2117 r.in.offered = 0;
2118 r.out.needed = &needed;
2119 r.out.count = &count;
2120 r.out.info = &info;
2122 torture_comment(tctx, "Testing EnumForms level %d\n", levels[i]);
2124 status = dcerpc_spoolss_EnumForms(p, tctx, &r);
2125 torture_assert_ntstatus_ok(tctx, status, "EnumForms failed");
2127 if ((r.in.level == 2) && (W_ERROR_EQUAL(r.out.result, WERR_UNKNOWN_LEVEL))) {
2128 break;
2131 if (print_server && W_ERROR_EQUAL(r.out.result, WERR_BADFID))
2132 torture_fail(tctx, "EnumForms on the PrintServer isn't supported by test server (NT4)");
2134 if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
2135 int j;
2136 DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed);
2137 data_blob_clear(&blob);
2138 r.in.buffer = &blob;
2139 r.in.offered = needed;
2141 status = dcerpc_spoolss_EnumForms(p, tctx, &r);
2143 torture_assert(tctx, info, "No forms returned");
2145 for (j = 0; j < count; j++) {
2146 if (!print_server)
2147 ret &= test_GetForm(tctx, p, handle, info[j].info1.form_name, levels[i]);
2151 torture_assert_ntstatus_ok(tctx, status, "EnumForms failed");
2153 torture_assert_werr_ok(tctx, r.out.result, "EnumForms failed");
2155 CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumForms, info, r.in.level, count, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
2158 return true;
2161 static bool test_DeleteForm(struct torture_context *tctx,
2162 struct dcerpc_pipe *p,
2163 struct policy_handle *handle,
2164 const char *form_name)
2166 NTSTATUS status;
2167 struct spoolss_DeleteForm r;
2169 r.in.handle = handle;
2170 r.in.form_name = form_name;
2172 status = dcerpc_spoolss_DeleteForm(p, tctx, &r);
2174 torture_assert_ntstatus_ok(tctx, status, "DeleteForm failed");
2176 torture_assert_werr_ok(tctx, r.out.result, "DeleteForm failed");
2178 return true;
2181 static bool test_AddForm(struct torture_context *tctx,
2182 struct dcerpc_pipe *p,
2183 struct policy_handle *handle, bool print_server)
2185 struct spoolss_AddForm r;
2186 struct spoolss_AddFormInfo1 addform;
2187 const char *form_name = "testform3";
2188 NTSTATUS status;
2189 bool ret = true;
2191 r.in.handle = handle;
2192 r.in.level = 1;
2193 r.in.info.info1 = &addform;
2194 addform.flags = SPOOLSS_FORM_USER;
2195 addform.form_name = form_name;
2196 addform.size.width = 50;
2197 addform.size.height = 25;
2198 addform.area.left = 5;
2199 addform.area.top = 10;
2200 addform.area.right = 45;
2201 addform.area.bottom = 15;
2203 status = dcerpc_spoolss_AddForm(p, tctx, &r);
2205 torture_assert_ntstatus_ok(tctx, status, "AddForm failed");
2207 torture_assert_werr_ok(tctx, r.out.result, "AddForm failed");
2209 if (!print_server) ret &= test_GetForm(tctx, p, handle, form_name, 1);
2212 struct spoolss_SetForm sf;
2213 struct spoolss_AddFormInfo1 setform;
2215 sf.in.handle = handle;
2216 sf.in.form_name = form_name;
2217 sf.in.level = 1;
2218 sf.in.info.info1= &setform;
2219 setform.flags = addform.flags;
2220 setform.form_name = addform.form_name;
2221 setform.size = addform.size;
2222 setform.area = addform.area;
2224 setform.size.width = 1234;
2226 status = dcerpc_spoolss_SetForm(p, tctx, &sf);
2228 torture_assert_ntstatus_ok(tctx, status, "SetForm failed");
2230 torture_assert_werr_ok(tctx, r.out.result, "SetForm failed");
2233 if (!print_server) ret &= test_GetForm(tctx, p, handle, form_name, 1);
2236 struct spoolss_EnumForms e;
2237 union spoolss_FormInfo *info;
2238 uint32_t needed;
2239 uint32_t count;
2240 bool found = false;
2242 e.in.handle = handle;
2243 e.in.level = 1;
2244 e.in.buffer = NULL;
2245 e.in.offered = 0;
2246 e.out.needed = &needed;
2247 e.out.count = &count;
2248 e.out.info = &info;
2250 torture_comment(tctx, "Testing EnumForms level 1\n");
2252 status = dcerpc_spoolss_EnumForms(p, tctx, &e);
2253 torture_assert_ntstatus_ok(tctx, status, "EnumForms failed");
2255 if (print_server && W_ERROR_EQUAL(e.out.result, WERR_BADFID))
2256 torture_fail(tctx, "EnumForms on the PrintServer isn't supported by test server (NT4)");
2258 if (W_ERROR_EQUAL(e.out.result, WERR_INSUFFICIENT_BUFFER)) {
2259 int j;
2260 DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed);
2261 data_blob_clear(&blob);
2262 e.in.buffer = &blob;
2263 e.in.offered = needed;
2265 status = dcerpc_spoolss_EnumForms(p, tctx, &e);
2267 torture_assert(tctx, info, "No forms returned");
2269 for (j = 0; j < count; j++) {
2270 if (strequal(form_name, info[j].info1.form_name)) {
2271 found = true;
2272 break;
2276 torture_assert(tctx, found, "Newly added form not found in enum call");
2279 if (!test_DeleteForm(tctx, p, handle, form_name)) {
2280 ret = false;
2283 return ret;
2286 static bool test_EnumPorts_old(struct torture_context *tctx,
2287 struct dcerpc_pipe *p)
2289 NTSTATUS status;
2290 struct spoolss_EnumPorts r;
2291 uint32_t needed;
2292 uint32_t count;
2293 union spoolss_PortInfo *info;
2295 r.in.servername = talloc_asprintf(tctx, "\\\\%s",
2296 dcerpc_server_name(p));
2297 r.in.level = 2;
2298 r.in.buffer = NULL;
2299 r.in.offered = 0;
2300 r.out.needed = &needed;
2301 r.out.count = &count;
2302 r.out.info = &info;
2304 torture_comment(tctx, "Testing EnumPorts\n");
2306 status = dcerpc_spoolss_EnumPorts(p, tctx, &r);
2308 torture_assert_ntstatus_ok(tctx, status, "EnumPorts failed");
2310 if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
2311 DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed);
2312 data_blob_clear(&blob);
2313 r.in.buffer = &blob;
2314 r.in.offered = needed;
2316 status = dcerpc_spoolss_EnumPorts(p, tctx, &r);
2317 torture_assert_ntstatus_ok(tctx, status, "EnumPorts failed");
2318 torture_assert_werr_ok(tctx, r.out.result, "EnumPorts failed");
2320 torture_assert(tctx, info, "No ports returned");
2323 torture_assert_werr_ok(tctx, r.out.result, "EnumPorts failed");
2325 CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumPorts, info, 2, count, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
2327 return true;
2330 static bool test_AddPort(struct torture_context *tctx,
2331 struct dcerpc_pipe *p)
2333 NTSTATUS status;
2334 struct spoolss_AddPort r;
2336 r.in.server_name = talloc_asprintf(tctx, "\\\\%s",
2337 dcerpc_server_name(p));
2338 r.in.unknown = 0;
2339 r.in.monitor_name = "foo";
2341 torture_comment(tctx, "Testing AddPort\n");
2343 status = dcerpc_spoolss_AddPort(p, tctx, &r);
2345 torture_assert_ntstatus_ok(tctx, status, "AddPort failed");
2347 /* win2k3 returns WERR_NOT_SUPPORTED */
2349 #if 0
2351 if (!W_ERROR_IS_OK(r.out.result)) {
2352 printf("AddPort failed - %s\n", win_errstr(r.out.result));
2353 return false;
2356 #endif
2358 return true;
2361 static bool test_GetJob(struct torture_context *tctx,
2362 struct dcerpc_pipe *p,
2363 struct policy_handle *handle, uint32_t job_id)
2365 NTSTATUS status;
2366 struct spoolss_GetJob r;
2367 union spoolss_JobInfo info;
2368 uint32_t needed;
2369 uint32_t levels[] = {1, 2 /* 3, 4 */};
2370 uint32_t i;
2372 r.in.handle = handle;
2373 r.in.job_id = job_id;
2374 r.in.level = 0;
2375 r.in.buffer = NULL;
2376 r.in.offered = 0;
2377 r.out.needed = &needed;
2378 r.out.info = &info;
2380 torture_comment(tctx, "Testing GetJob level %d\n", r.in.level);
2382 status = dcerpc_spoolss_GetJob(p, tctx, &r);
2383 torture_assert_werr_equal(tctx, r.out.result, WERR_UNKNOWN_LEVEL, "Unexpected return code");
2385 for (i = 0; i < ARRAY_SIZE(levels); i++) {
2387 torture_comment(tctx, "Testing GetJob level %d\n", r.in.level);
2389 needed = 0;
2391 r.in.level = levels[i];
2392 r.in.offered = 0;
2393 r.in.buffer = NULL;
2395 status = dcerpc_spoolss_GetJob(p, tctx, &r);
2396 torture_assert_ntstatus_ok(tctx, status, "GetJob failed");
2398 if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
2399 DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed);
2400 data_blob_clear(&blob);
2401 r.in.buffer = &blob;
2402 r.in.offered = needed;
2404 status = dcerpc_spoolss_GetJob(p, tctx, &r);
2405 torture_assert_ntstatus_ok(tctx, status, "GetJob failed");
2408 torture_assert(tctx, r.out.info, "No job info returned");
2409 torture_assert_werr_ok(tctx, r.out.result, "GetJob failed");
2411 CHECK_NEEDED_SIZE_LEVEL(spoolss_JobInfo, r.out.info, r.in.level, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
2414 return true;
2417 static bool test_SetJob(struct torture_context *tctx,
2418 struct dcerpc_pipe *p,
2419 struct policy_handle *handle, uint32_t job_id,
2420 enum spoolss_JobControl command)
2422 NTSTATUS status;
2423 struct spoolss_SetJob r;
2425 r.in.handle = handle;
2426 r.in.job_id = job_id;
2427 r.in.ctr = NULL;
2428 r.in.command = command;
2430 switch (command) {
2431 case SPOOLSS_JOB_CONTROL_PAUSE:
2432 torture_comment(tctx, "Testing SetJob: SPOOLSS_JOB_CONTROL_PAUSE\n");
2433 break;
2434 case SPOOLSS_JOB_CONTROL_RESUME:
2435 torture_comment(tctx, "Testing SetJob: SPOOLSS_JOB_CONTROL_RESUME\n");
2436 break;
2437 case SPOOLSS_JOB_CONTROL_CANCEL:
2438 torture_comment(tctx, "Testing SetJob: SPOOLSS_JOB_CONTROL_CANCEL\n");
2439 break;
2440 case SPOOLSS_JOB_CONTROL_RESTART:
2441 torture_comment(tctx, "Testing SetJob: SPOOLSS_JOB_CONTROL_RESTART\n");
2442 break;
2443 case SPOOLSS_JOB_CONTROL_DELETE:
2444 torture_comment(tctx, "Testing SetJob: SPOOLSS_JOB_CONTROL_DELETE\n");
2445 break;
2446 case SPOOLSS_JOB_CONTROL_SEND_TO_PRINTER:
2447 torture_comment(tctx, "Testing SetJob: SPOOLSS_JOB_CONTROL_SEND_TO_PRINTER\n");
2448 break;
2449 case SPOOLSS_JOB_CONTROL_LAST_PAGE_EJECTED:
2450 torture_comment(tctx, "Testing SetJob: SPOOLSS_JOB_CONTROL_LAST_PAGE_EJECTED\n");
2451 break;
2452 case SPOOLSS_JOB_CONTROL_RETAIN:
2453 torture_comment(tctx, "Testing SetJob: SPOOLSS_JOB_CONTROL_RETAIN\n");
2454 break;
2455 case SPOOLSS_JOB_CONTROL_RELEASE:
2456 torture_comment(tctx, "Testing SetJob: SPOOLSS_JOB_CONTROL_RELEASE\n");
2457 break;
2458 default:
2459 torture_comment(tctx, "Testing SetJob\n");
2460 break;
2463 status = dcerpc_spoolss_SetJob(p, tctx, &r);
2464 torture_assert_ntstatus_ok(tctx, status, "SetJob failed");
2465 torture_assert_werr_ok(tctx, r.out.result, "SetJob failed");
2467 return true;
2470 static bool test_AddJob(struct torture_context *tctx,
2471 struct dcerpc_pipe *p,
2472 struct policy_handle *handle)
2474 NTSTATUS status;
2475 struct spoolss_AddJob r;
2476 uint32_t needed;
2478 r.in.level = 0;
2479 r.in.handle = handle;
2480 r.in.offered = 0;
2481 r.out.needed = &needed;
2482 r.in.buffer = r.out.buffer = NULL;
2484 torture_comment(tctx, "Testing AddJob\n");
2486 status = dcerpc_spoolss_AddJob(p, tctx, &r);
2487 torture_assert_werr_equal(tctx, r.out.result, WERR_UNKNOWN_LEVEL, "AddJob failed");
2489 r.in.level = 1;
2491 status = dcerpc_spoolss_AddJob(p, tctx, &r);
2492 torture_assert_werr_equal(tctx, r.out.result, WERR_INVALID_PARAM, "AddJob failed");
2494 return true;
2498 static bool test_EnumJobs(struct torture_context *tctx,
2499 struct dcerpc_pipe *p,
2500 struct policy_handle *handle)
2502 NTSTATUS status;
2503 struct spoolss_EnumJobs r;
2504 uint32_t needed;
2505 uint32_t count;
2506 union spoolss_JobInfo *info;
2508 r.in.handle = handle;
2509 r.in.firstjob = 0;
2510 r.in.numjobs = 0xffffffff;
2511 r.in.level = 1;
2512 r.in.buffer = NULL;
2513 r.in.offered = 0;
2514 r.out.needed = &needed;
2515 r.out.count = &count;
2516 r.out.info = &info;
2518 torture_comment(tctx, "Testing EnumJobs\n");
2520 status = dcerpc_spoolss_EnumJobs(p, tctx, &r);
2522 torture_assert_ntstatus_ok(tctx, status, "EnumJobs failed");
2524 if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
2525 int j;
2526 DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed);
2527 data_blob_clear(&blob);
2528 r.in.buffer = &blob;
2529 r.in.offered = needed;
2531 status = dcerpc_spoolss_EnumJobs(p, tctx, &r);
2533 torture_assert_ntstatus_ok(tctx, status, "EnumJobs failed");
2534 torture_assert_werr_ok(tctx, r.out.result, "EnumJobs failed");
2535 torture_assert(tctx, info, "No jobs returned");
2537 CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumJobs, *r.out.info, r.in.level, count, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
2539 for (j = 0; j < count; j++) {
2541 torture_assert(tctx, test_GetJob(tctx, p, handle, info[j].info1.job_id),
2542 "failed to call test_GetJob");
2544 /* FIXME - gd */
2545 if (!torture_setting_bool(tctx, "samba3", false)) {
2546 test_SetJob(tctx, p, handle, info[j].info1.job_id, SPOOLSS_JOB_CONTROL_PAUSE);
2547 test_SetJob(tctx, p, handle, info[j].info1.job_id, SPOOLSS_JOB_CONTROL_RESUME);
2551 } else {
2552 torture_assert_werr_ok(tctx, r.out.result, "EnumJobs failed");
2555 return true;
2558 static bool test_DoPrintTest(struct torture_context *tctx,
2559 struct dcerpc_pipe *p,
2560 struct policy_handle *handle)
2562 bool ret = true;
2563 NTSTATUS status;
2564 struct spoolss_StartDocPrinter s;
2565 struct spoolss_DocumentInfo1 info1;
2566 struct spoolss_StartPagePrinter sp;
2567 struct spoolss_WritePrinter w;
2568 struct spoolss_EndPagePrinter ep;
2569 struct spoolss_EndDocPrinter e;
2570 int i;
2571 uint32_t job_id;
2572 uint32_t num_written;
2574 torture_comment(tctx, "Testing StartDocPrinter\n");
2576 s.in.handle = handle;
2577 s.in.level = 1;
2578 s.in.info.info1 = &info1;
2579 s.out.job_id = &job_id;
2580 info1.document_name = "TorturePrintJob";
2581 info1.output_file = NULL;
2582 info1.datatype = "RAW";
2584 status = dcerpc_spoolss_StartDocPrinter(p, tctx, &s);
2585 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_StartDocPrinter failed");
2586 torture_assert_werr_ok(tctx, s.out.result, "StartDocPrinter failed");
2588 for (i=1; i < 4; i++) {
2589 torture_comment(tctx, "Testing StartPagePrinter: Page[%d]\n", i);
2591 sp.in.handle = handle;
2593 status = dcerpc_spoolss_StartPagePrinter(p, tctx, &sp);
2594 torture_assert_ntstatus_ok(tctx, status,
2595 "dcerpc_spoolss_StartPagePrinter failed");
2596 torture_assert_werr_ok(tctx, sp.out.result, "StartPagePrinter failed");
2598 torture_comment(tctx, "Testing WritePrinter: Page[%d]\n", i);
2600 w.in.handle = handle;
2601 w.in.data = data_blob_string_const(talloc_asprintf(tctx,"TortureTestPage: %d\nData\n",i));
2602 w.out.num_written = &num_written;
2604 status = dcerpc_spoolss_WritePrinter(p, tctx, &w);
2605 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_WritePrinter failed");
2606 torture_assert_werr_ok(tctx, w.out.result, "WritePrinter failed");
2608 torture_comment(tctx, "Testing EndPagePrinter: Page[%d]\n", i);
2610 ep.in.handle = handle;
2612 status = dcerpc_spoolss_EndPagePrinter(p, tctx, &ep);
2613 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EndPagePrinter failed");
2614 torture_assert_werr_ok(tctx, ep.out.result, "EndPagePrinter failed");
2617 torture_comment(tctx, "Testing EndDocPrinter\n");
2619 e.in.handle = handle;
2621 status = dcerpc_spoolss_EndDocPrinter(p, tctx, &e);
2622 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EndDocPrinter failed");
2623 torture_assert_werr_ok(tctx, e.out.result, "EndDocPrinter failed");
2625 ret &= test_AddJob(tctx, p, handle);
2626 ret &= test_EnumJobs(tctx, p, handle);
2628 ret &= test_SetJob(tctx, p, handle, job_id, SPOOLSS_JOB_CONTROL_DELETE);
2630 return ret;
2633 static bool test_PausePrinter(struct torture_context *tctx,
2634 struct dcerpc_pipe *p,
2635 struct policy_handle *handle)
2637 NTSTATUS status;
2638 struct spoolss_SetPrinter r;
2639 struct spoolss_SetPrinterInfoCtr info_ctr;
2640 struct spoolss_DevmodeContainer devmode_ctr;
2641 struct sec_desc_buf secdesc_ctr;
2643 info_ctr.level = 0;
2644 info_ctr.info.info0 = NULL;
2646 ZERO_STRUCT(devmode_ctr);
2647 ZERO_STRUCT(secdesc_ctr);
2649 r.in.handle = handle;
2650 r.in.info_ctr = &info_ctr;
2651 r.in.devmode_ctr = &devmode_ctr;
2652 r.in.secdesc_ctr = &secdesc_ctr;
2653 r.in.command = SPOOLSS_PRINTER_CONTROL_PAUSE;
2655 torture_comment(tctx, "Testing SetPrinter: SPOOLSS_PRINTER_CONTROL_PAUSE\n");
2657 status = dcerpc_spoolss_SetPrinter(p, tctx, &r);
2659 torture_assert_ntstatus_ok(tctx, status, "SetPrinter failed");
2661 torture_assert_werr_ok(tctx, r.out.result, "SetPrinter failed");
2663 return true;
2666 static bool test_ResumePrinter(struct torture_context *tctx,
2667 struct dcerpc_pipe *p,
2668 struct policy_handle *handle)
2670 NTSTATUS status;
2671 struct spoolss_SetPrinter r;
2672 struct spoolss_SetPrinterInfoCtr info_ctr;
2673 struct spoolss_DevmodeContainer devmode_ctr;
2674 struct sec_desc_buf secdesc_ctr;
2676 info_ctr.level = 0;
2677 info_ctr.info.info0 = NULL;
2679 ZERO_STRUCT(devmode_ctr);
2680 ZERO_STRUCT(secdesc_ctr);
2682 r.in.handle = handle;
2683 r.in.info_ctr = &info_ctr;
2684 r.in.devmode_ctr = &devmode_ctr;
2685 r.in.secdesc_ctr = &secdesc_ctr;
2686 r.in.command = SPOOLSS_PRINTER_CONTROL_RESUME;
2688 torture_comment(tctx, "Testing SetPrinter: SPOOLSS_PRINTER_CONTROL_RESUME\n");
2690 status = dcerpc_spoolss_SetPrinter(p, tctx, &r);
2692 torture_assert_ntstatus_ok(tctx, status, "SetPrinter failed");
2694 torture_assert_werr_ok(tctx, r.out.result, "SetPrinter failed");
2696 return true;
2699 static bool test_GetPrinterData(struct torture_context *tctx,
2700 struct dcerpc_pipe *p,
2701 struct policy_handle *handle,
2702 const char *value_name,
2703 enum winreg_Type *type_p,
2704 union spoolss_PrinterData *data_p)
2706 NTSTATUS status;
2707 struct spoolss_GetPrinterData r;
2708 uint32_t needed;
2709 enum winreg_Type type;
2710 union spoolss_PrinterData data;
2712 r.in.handle = handle;
2713 r.in.value_name = value_name;
2714 r.in.offered = 0;
2715 r.out.needed = &needed;
2716 r.out.type = &type;
2717 r.out.data = &data;
2719 torture_comment(tctx, "Testing GetPrinterData(%s)\n", r.in.value_name);
2721 status = dcerpc_spoolss_GetPrinterData(p, tctx, &r);
2722 torture_assert_ntstatus_ok(tctx, status, "GetPrinterData failed");
2724 if (W_ERROR_EQUAL(r.out.result, WERR_MORE_DATA)) {
2725 r.in.offered = needed;
2727 status = dcerpc_spoolss_GetPrinterData(p, tctx, &r);
2728 torture_assert_ntstatus_ok(tctx, status, "GetPrinterData failed");
2731 torture_assert_werr_ok(tctx, r.out.result,
2732 talloc_asprintf(tctx, "GetPrinterData(%s) failed", r.in.value_name));
2734 CHECK_NEEDED_SIZE_LEVEL(spoolss_PrinterData, &data, type, lp_iconv_convenience(tctx->lp_ctx), needed, 1);
2736 if (type_p) {
2737 *type_p = type;
2740 if (data_p) {
2741 *data_p = data;
2744 return true;
2747 static bool test_GetPrinterDataEx(struct torture_context *tctx,
2748 struct dcerpc_pipe *p,
2749 struct policy_handle *handle,
2750 const char *key_name,
2751 const char *value_name,
2752 enum winreg_Type *type_p,
2753 union spoolss_PrinterData *data_p)
2755 NTSTATUS status;
2756 struct spoolss_GetPrinterDataEx r;
2757 enum winreg_Type type;
2758 uint32_t needed;
2759 union spoolss_PrinterData data;
2761 r.in.handle = handle;
2762 r.in.key_name = key_name;
2763 r.in.value_name = value_name;
2764 r.in.offered = 0;
2765 r.out.type = &type;
2766 r.out.needed = &needed;
2767 r.out.data = &data;
2769 torture_comment(tctx, "Testing GetPrinterDataEx(%s - %s)\n",
2770 r.in.key_name, r.in.value_name);
2772 status = dcerpc_spoolss_GetPrinterDataEx(p, tctx, &r);
2773 if (!NT_STATUS_IS_OK(status)) {
2774 if (NT_STATUS_EQUAL(status,NT_STATUS_NET_WRITE_FAULT) &&
2775 p->last_fault_code == DCERPC_FAULT_OP_RNG_ERROR) {
2776 torture_skip(tctx, "GetPrinterDataEx not supported by server\n");
2778 torture_assert_ntstatus_ok(tctx, status, "GetPrinterDataEx failed");
2781 if (W_ERROR_EQUAL(r.out.result, WERR_MORE_DATA)) {
2782 r.in.offered = needed;
2783 status = dcerpc_spoolss_GetPrinterDataEx(p, tctx, &r);
2784 torture_assert_ntstatus_ok(tctx, status, "GetPrinterDataEx failed");
2787 torture_assert_werr_ok(tctx, r.out.result,
2788 talloc_asprintf(tctx, "GetPrinterDataEx(%s - %s) failed", r.in.key_name, r.in.value_name));
2790 CHECK_NEEDED_SIZE_LEVEL(spoolss_PrinterData, &data, type, lp_iconv_convenience(tctx->lp_ctx), needed, 1);
2792 if (type_p) {
2793 *type_p = type;
2796 if (data_p) {
2797 *data_p = data;
2800 return true;
2803 static bool test_GetPrinterData_list(struct torture_context *tctx,
2804 struct dcerpc_pipe *p,
2805 struct policy_handle *handle)
2807 const char *list[] = {
2808 "W3SvcInstalled",
2809 "BeepEnabled",
2810 "EventLog",
2811 /* "NetPopup", not on w2k8 */
2812 /* "NetPopupToComputer", not on w2k8 */
2813 "MajorVersion",
2814 "MinorVersion",
2815 "DefaultSpoolDirectory",
2816 "Architecture",
2817 "DsPresent",
2818 "OSVersion",
2819 /* "OSVersionEx", not on s3 */
2820 "DNSMachineName"
2822 int i;
2824 for (i=0; i < ARRAY_SIZE(list); i++) {
2825 enum winreg_Type type, type_ex;
2826 union spoolss_PrinterData data, data_ex;
2828 torture_assert(tctx, test_GetPrinterData(tctx, p, handle, list[i], &type, &data),
2829 talloc_asprintf(tctx, "GetPrinterData failed on %s\n", list[i]));
2830 torture_assert(tctx, test_GetPrinterDataEx(tctx, p, handle, "random_string", list[i], &type_ex, &data_ex),
2831 talloc_asprintf(tctx, "GetPrinterDataEx failed on %s\n", list[i]));
2832 torture_assert_int_equal(tctx, type, type_ex, "type mismatch");
2833 switch (type) {
2834 case REG_SZ:
2835 torture_assert_str_equal(tctx, data.string, data_ex.string, "REG_SZ mismatch");
2836 break;
2837 case REG_DWORD:
2838 torture_assert_int_equal(tctx, data.value, data_ex.value, "REG_DWORD mismatch");
2839 break;
2840 case REG_BINARY:
2841 torture_assert_data_blob_equal(tctx, data.binary, data_ex.binary, "REG_BINARY mismatch");
2842 break;
2843 default:
2844 break;
2848 return true;
2851 static bool test_EnumPrinterData(struct torture_context *tctx, struct dcerpc_pipe *p,
2852 struct policy_handle *handle)
2854 NTSTATUS status;
2855 struct spoolss_EnumPrinterData r;
2857 ZERO_STRUCT(r);
2858 r.in.handle = handle;
2859 r.in.enum_index = 0;
2861 do {
2862 uint32_t value_size = 0;
2863 uint32_t data_size = 0;
2864 enum winreg_Type type = 0;
2866 r.in.value_offered = value_size;
2867 r.out.value_needed = &value_size;
2868 r.in.data_offered = data_size;
2869 r.out.data_needed = &data_size;
2871 r.out.type = &type;
2872 r.out.data = talloc_zero_array(tctx, uint8_t, 0);
2874 torture_comment(tctx, "Testing EnumPrinterData\n");
2876 status = dcerpc_spoolss_EnumPrinterData(p, tctx, &r);
2878 torture_assert_ntstatus_ok(tctx, status, "EnumPrinterData failed");
2879 if (W_ERROR_EQUAL(r.out.result, WERR_NO_MORE_ITEMS)) {
2880 break;
2882 torture_assert_werr_ok(tctx, r.out.result, "EnumPrinterData");
2884 r.in.value_offered = value_size;
2885 r.out.value_name = talloc_zero_array(tctx, const char, value_size);
2886 r.in.data_offered = data_size;
2887 r.out.data = talloc_zero_array(tctx, uint8_t, data_size);
2889 status = dcerpc_spoolss_EnumPrinterData(p, tctx, &r);
2891 torture_assert_ntstatus_ok(tctx, status, "EnumPrinterData failed");
2892 if (W_ERROR_EQUAL(r.out.result, WERR_NO_MORE_ITEMS)) {
2893 break;
2896 torture_assert_werr_ok(tctx, r.out.result, "EnumPrinterData failed");
2898 torture_assert(tctx, test_GetPrinterData(tctx, p, handle, r.out.value_name, NULL, NULL),
2899 talloc_asprintf(tctx, "failed to call GetPrinterData for %s\n", r.out.value_name));
2901 torture_assert(tctx, test_GetPrinterDataEx(tctx, p, handle, "PrinterDriverData", r.out.value_name, NULL, NULL),
2902 talloc_asprintf(tctx, "failed to call GetPrinterDataEx on PrinterDriverData for %s\n", r.out.value_name));
2904 r.in.enum_index++;
2906 } while (W_ERROR_IS_OK(r.out.result));
2908 return true;
2911 static bool test_EnumPrinterDataEx(struct torture_context *tctx,
2912 struct dcerpc_pipe *p,
2913 struct policy_handle *handle,
2914 const char *key_name)
2916 struct spoolss_EnumPrinterDataEx r;
2917 struct spoolss_PrinterEnumValues *info;
2918 uint32_t needed;
2919 uint32_t count;
2921 r.in.handle = handle;
2922 r.in.key_name = key_name;
2923 r.in.offered = 0;
2924 r.out.needed = &needed;
2925 r.out.count = &count;
2926 r.out.info = &info;
2928 torture_comment(tctx, "Testing EnumPrinterDataEx(%s)\n", key_name);
2930 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_EnumPrinterDataEx(p, tctx, &r),
2931 "EnumPrinterDataEx failed");
2932 if (W_ERROR_EQUAL(r.out.result, WERR_MORE_DATA)) {
2933 r.in.offered = needed;
2934 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_EnumPrinterDataEx(p, tctx, &r),
2935 "EnumPrinterDataEx failed");
2938 torture_assert_werr_ok(tctx, r.out.result, "EnumPrinterDataEx failed");
2940 CHECK_NEEDED_SIZE_ENUM(spoolss_EnumPrinterDataEx, info, count, lp_iconv_convenience(tctx->lp_ctx), needed, 1);
2942 return true;
2946 static bool test_DeletePrinterData(struct torture_context *tctx,
2947 struct dcerpc_pipe *p,
2948 struct policy_handle *handle,
2949 const char *value_name)
2951 NTSTATUS status;
2952 struct spoolss_DeletePrinterData r;
2954 r.in.handle = handle;
2955 r.in.value_name = value_name;
2957 torture_comment(tctx, "Testing DeletePrinterData(%s)\n",
2958 r.in.value_name);
2960 status = dcerpc_spoolss_DeletePrinterData(p, tctx, &r);
2962 torture_assert_ntstatus_ok(tctx, status, "DeletePrinterData failed");
2963 torture_assert_werr_ok(tctx, r.out.result, "DeletePrinterData failed");
2965 return true;
2968 static bool test_DeletePrinterDataEx(struct torture_context *tctx,
2969 struct dcerpc_pipe *p,
2970 struct policy_handle *handle,
2971 const char *key_name,
2972 const char *value_name)
2974 struct spoolss_DeletePrinterDataEx r;
2976 r.in.handle = handle;
2977 r.in.key_name = key_name;
2978 r.in.value_name = value_name;
2980 torture_comment(tctx, "Testing DeletePrinterDataEx(%s - %s)\n",
2981 r.in.key_name, r.in.value_name);
2983 torture_assert_ntstatus_ok(tctx,
2984 dcerpc_spoolss_DeletePrinterDataEx(p, tctx, &r),
2985 "DeletePrinterDataEx failed");
2986 torture_assert_werr_ok(tctx, r.out.result,
2987 "DeletePrinterDataEx failed");
2989 return true;
2992 static bool test_DeletePrinterKey(struct torture_context *tctx,
2993 struct dcerpc_pipe *p,
2994 struct policy_handle *handle,
2995 const char *key_name)
2997 struct spoolss_DeletePrinterKey r;
2999 r.in.handle = handle;
3000 r.in.key_name = key_name;
3002 torture_comment(tctx, "Testing DeletePrinterKey(%s)\n", r.in.key_name);
3004 if (strequal(key_name, "") && !torture_setting_bool(tctx, "dangerous", false)) {
3005 torture_skip(tctx, "not wiping out printer registry - enable dangerous tests to use\n");
3006 return true;
3009 torture_assert_ntstatus_ok(tctx,
3010 dcerpc_spoolss_DeletePrinterKey(p, tctx, &r),
3011 "DeletePrinterKey failed");
3012 torture_assert_werr_ok(tctx, r.out.result,
3013 "DeletePrinterKey failed");
3015 return true;
3018 static bool test_SetPrinterData(struct torture_context *tctx,
3019 struct dcerpc_pipe *p,
3020 struct policy_handle *handle)
3022 NTSTATUS status;
3023 struct spoolss_SetPrinterData r;
3024 const char *values[] = {
3025 "spootyfoot",
3026 "spooty\\foot",
3027 #if 0
3028 /* FIXME: not working with s3 atm. */
3029 "spooty,foot",
3030 "spooty,fo,ot",
3031 #endif
3032 "spooty foot",
3033 #if 0
3034 /* FIXME: not working with s3 atm. */
3035 "spooty\\fo,ot",
3036 "spooty,fo\\ot"
3037 #endif
3039 int i;
3041 for (i=0; i < ARRAY_SIZE(values); i++) {
3043 enum winreg_Type type;
3044 union spoolss_PrinterData data;
3046 r.in.handle = handle;
3047 r.in.value_name = values[i];
3048 r.in.type = REG_SZ;
3049 r.in.data.string = "dog";
3051 torture_comment(tctx, "Testing SetPrinterData(%s)\n",
3052 r.in.value_name);
3054 status = dcerpc_spoolss_SetPrinterData(p, tctx, &r);
3056 torture_assert_ntstatus_ok(tctx, status, "SetPrinterData failed");
3057 torture_assert_werr_ok(tctx, r.out.result, "SetPrinterData failed");
3059 if (!test_GetPrinterData(tctx, p, handle, r.in.value_name, &type, &data)) {
3060 return false;
3063 torture_assert_int_equal(tctx, r.in.type, type, "type mismatch");
3064 torture_assert_str_equal(tctx, r.in.data.string, data.string, "data mismatch");
3066 if (!test_DeletePrinterData(tctx, p, handle, r.in.value_name)) {
3067 return false;
3071 return true;
3074 static bool test_EnumPrinterKey(struct torture_context *tctx,
3075 struct dcerpc_pipe *p,
3076 struct policy_handle *handle,
3077 const char *key_name,
3078 const char ***array);
3080 static bool test_SetPrinterDataEx(struct torture_context *tctx,
3081 struct dcerpc_pipe *p,
3082 struct policy_handle *handle)
3084 NTSTATUS status;
3085 struct spoolss_SetPrinterDataEx r;
3086 const char *value_name = "dog";
3087 const char *keys[] = {
3088 "torturedataex",
3089 "torture data ex",
3090 #if 0
3091 /* FIXME: not working with s3 atm. */
3092 "torturedataex_with_subkey\\subkey",
3093 "torturedataex_with_subkey\\subkey:0",
3094 "torturedataex_with_subkey\\subkey:1",
3095 "torturedataex_with_subkey\\subkey\\subsubkey",
3096 "torturedataex_with_subkey\\subkey\\subsubkey:0",
3097 "torturedataex_with_subkey\\subkey\\subsubkey:1",
3098 #endif
3099 "torture,data",
3100 #if 0
3101 /* FIXME: not working with s3 atm. */
3103 "torture,data,ex",
3104 "torture,data\\ex",
3105 "torture\\data,ex"
3106 #endif
3108 int i;
3109 DATA_BLOB blob = data_blob_string_const("catfoobar");
3112 for (i=0; i < ARRAY_SIZE(keys); i++) {
3114 char *c;
3115 const char *key;
3116 enum winreg_Type type;
3117 const char **subkeys;
3118 union spoolss_PrinterData data;
3120 r.in.handle = handle;
3121 r.in.key_name = keys[i];
3122 r.in.value_name = value_name;
3123 r.in.type = REG_BINARY;
3124 r.in.data.binary = blob;
3126 torture_comment(tctx, "Testing SetPrinterDataEx(%s - %s)\n", r.in.key_name, value_name);
3128 status = dcerpc_spoolss_SetPrinterDataEx(p, tctx, &r);
3130 torture_assert_ntstatus_ok(tctx, status, "SetPrinterDataEx failed");
3131 torture_assert_werr_ok(tctx, r.out.result, "SetPrinterDataEx failed");
3133 key = talloc_strdup(tctx, r.in.key_name);
3135 if (!test_GetPrinterDataEx(tctx, p, handle, r.in.key_name, value_name, &type, &data)) {
3136 return false;
3139 torture_assert_int_equal(tctx, r.in.type, type, "type mismatch");
3140 torture_assert_data_blob_equal(tctx, blob, data.binary, "data mismatch");
3142 if (!test_EnumPrinterDataEx(tctx, p, handle, r.in.key_name)) {
3143 return false;
3146 if (!test_DeletePrinterDataEx(tctx, p, handle, r.in.key_name, value_name)) {
3147 return false;
3150 c = strchr(key, '\\');
3151 if (c) {
3152 int i;
3154 /* we have subkeys */
3156 *c = 0;
3158 if (!test_EnumPrinterKey(tctx, p, handle, key, &subkeys)) {
3159 return false;
3162 for (i=0; subkeys && subkeys[i]; i++) {
3164 const char *current_key = talloc_asprintf(tctx, "%s\\%s", key, subkeys[i]);
3166 if (!test_DeletePrinterKey(tctx, p, handle, current_key)) {
3167 return false;
3171 if (!test_DeletePrinterKey(tctx, p, handle, key)) {
3172 return false;
3175 } else {
3176 if (!test_DeletePrinterKey(tctx, p, handle, key)) {
3177 return false;
3182 return true;
3185 static bool test_GetChangeID_PrinterData(struct torture_context *tctx,
3186 struct dcerpc_pipe *p,
3187 struct policy_handle *handle,
3188 uint32_t *change_id)
3190 enum winreg_Type type;
3191 union spoolss_PrinterData data;
3193 torture_assert(tctx,
3194 test_GetPrinterData(tctx, p, handle, "ChangeID", &type, &data),
3195 "failed to call GetPrinterData");
3197 torture_assert(tctx, type == REG_DWORD, "unexpected type");
3199 *change_id = data.value;
3201 return true;
3204 static bool test_GetChangeID_PrinterDataEx(struct torture_context *tctx,
3205 struct dcerpc_pipe *p,
3206 struct policy_handle *handle,
3207 uint32_t *change_id)
3209 enum winreg_Type type;
3210 union spoolss_PrinterData data;
3212 torture_assert(tctx,
3213 test_GetPrinterDataEx(tctx, p, handle, "PrinterDriverData", "ChangeID", &type, &data),
3214 "failed to call GetPrinterData");
3216 torture_assert(tctx, type == REG_DWORD, "unexpected type");
3218 *change_id = data.value;
3220 return true;
3223 static bool test_GetChangeID_PrinterInfo(struct torture_context *tctx,
3224 struct dcerpc_pipe *p,
3225 struct policy_handle *handle,
3226 uint32_t *change_id)
3228 union spoolss_PrinterInfo info;
3230 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 0, &info),
3231 "failed to query Printer level 0");
3233 *change_id = info.info0.change_id;
3235 return true;
3238 static bool test_ChangeID(struct torture_context *tctx,
3239 struct dcerpc_pipe *p,
3240 struct policy_handle *handle)
3242 uint32_t change_id, change_id_ex, change_id_info;
3243 uint32_t change_id2, change_id_ex2, change_id_info2;
3244 union spoolss_PrinterInfo info;
3245 const char *comment;
3248 torture_comment(tctx, "Testing ChangeID: id change test #1\n");
3250 torture_assert(tctx, test_GetChangeID_PrinterData(tctx, p, handle, &change_id),
3251 "failed to query for ChangeID");
3252 torture_assert(tctx, test_GetChangeID_PrinterDataEx(tctx, p, handle, &change_id_ex),
3253 "failed to query for ChangeID");
3254 torture_assert(tctx, test_GetChangeID_PrinterInfo(tctx, p, handle, &change_id_info),
3255 "failed to query for ChangeID");
3257 torture_assert_int_equal(tctx, change_id, change_id_ex,
3258 "change_ids should all be equal");
3259 torture_assert_int_equal(tctx, change_id_ex, change_id_info,
3260 "change_ids should all be equal");
3263 torture_comment(tctx, "Testing ChangeID: id change test #2\n");
3265 torture_assert(tctx, test_GetChangeID_PrinterData(tctx, p, handle, &change_id),
3266 "failed to query for ChangeID");
3267 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 2, &info),
3268 "failed to query Printer level 2");
3269 torture_assert(tctx, test_GetChangeID_PrinterDataEx(tctx, p, handle, &change_id_ex),
3270 "failed to query for ChangeID");
3271 torture_assert(tctx, test_GetChangeID_PrinterInfo(tctx, p, handle, &change_id_info),
3272 "failed to query for ChangeID");
3273 torture_assert_int_equal(tctx, change_id, change_id_ex,
3274 "change_id should not have changed");
3275 torture_assert_int_equal(tctx, change_id_ex, change_id_info,
3276 "change_id should not have changed");
3279 torture_comment(tctx, "Testing ChangeID: id change test #3\n");
3281 torture_assert(tctx, test_GetChangeID_PrinterData(tctx, p, handle, &change_id),
3282 "failed to query for ChangeID");
3283 torture_assert(tctx, test_GetChangeID_PrinterDataEx(tctx, p, handle, &change_id_ex),
3284 "failed to query for ChangeID");
3285 torture_assert(tctx, test_GetChangeID_PrinterInfo(tctx, p, handle, &change_id_info),
3286 "failed to query for ChangeID");
3287 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 2, &info),
3288 "failed to query Printer level 2");
3289 comment = talloc_strdup(tctx, info.info2.comment);
3292 struct spoolss_SetPrinterInfoCtr info_ctr;
3293 struct spoolss_DevmodeContainer devmode_ctr;
3294 struct sec_desc_buf secdesc_ctr;
3295 struct spoolss_SetPrinterInfo2 info2;
3297 ZERO_STRUCT(info_ctr);
3298 ZERO_STRUCT(devmode_ctr);
3299 ZERO_STRUCT(secdesc_ctr);
3301 info2.servername = info.info2.servername;
3302 info2.printername = info.info2.printername;
3303 info2.sharename = info.info2.sharename;
3304 info2.portname = info.info2.portname;
3305 info2.drivername = info.info2.drivername;
3306 info2.comment = "torture_comment";
3307 info2.location = info.info2.location;
3308 info2.devmode_ptr = 0;
3309 info2.sepfile = info.info2.sepfile;
3310 info2.printprocessor = info.info2.printprocessor;
3311 info2.datatype = info.info2.datatype;
3312 info2.parameters = info.info2.parameters;
3313 info2.secdesc_ptr = 0;
3314 info2.attributes = info.info2.attributes;
3315 info2.priority = info.info2.priority;
3316 info2.defaultpriority = info.info2.defaultpriority;
3317 info2.starttime = info.info2.starttime;
3318 info2.untiltime = info.info2.untiltime;
3319 info2.status = info.info2.status;
3320 info2.cjobs = info.info2.cjobs;
3321 info2.averageppm = info.info2.averageppm;
3323 info_ctr.level = 2;
3324 info_ctr.info.info2 = &info2;
3326 torture_assert(tctx, test_SetPrinter(tctx, p, handle, &info_ctr, &devmode_ctr, &secdesc_ctr, 0),
3327 "failed to call SetPrinter");
3329 info2.comment = comment;
3331 torture_assert(tctx, test_SetPrinter(tctx, p, handle, &info_ctr, &devmode_ctr, &secdesc_ctr, 0),
3332 "failed to call SetPrinter");
3336 torture_assert(tctx, test_GetChangeID_PrinterData(tctx, p, handle, &change_id2),
3337 "failed to query for ChangeID");
3338 torture_assert(tctx, test_GetChangeID_PrinterDataEx(tctx, p, handle, &change_id_ex2),
3339 "failed to query for ChangeID");
3340 torture_assert(tctx, test_GetChangeID_PrinterInfo(tctx, p, handle, &change_id_info2),
3341 "failed to query for ChangeID");
3343 torture_assert_int_equal(tctx, change_id2, change_id_ex2,
3344 "change_ids should all be equal");
3345 torture_assert_int_equal(tctx, change_id_ex2, change_id_info2,
3346 "change_ids should all be equal");
3348 torture_assert(tctx, (change_id < change_id2),
3349 talloc_asprintf(tctx, "change_id %d needs to be larger than change_id %d",
3350 change_id2, change_id));
3351 torture_assert(tctx, (change_id_ex < change_id_ex2),
3352 talloc_asprintf(tctx, "change_id %d needs to be larger than change_id %d",
3353 change_id_ex2, change_id_ex));
3354 torture_assert(tctx, (change_id_info < change_id_info2),
3355 talloc_asprintf(tctx, "change_id %d needs to be larger than change_id %d",
3356 change_id_info2, change_id_info));
3358 return true;
3361 static bool test_SecondaryClosePrinter(struct torture_context *tctx,
3362 struct dcerpc_pipe *p,
3363 struct policy_handle *handle)
3365 NTSTATUS status;
3366 struct dcerpc_binding *b;
3367 struct dcerpc_pipe *p2;
3368 struct spoolss_ClosePrinter cp;
3370 /* only makes sense on SMB */
3371 if (p->conn->transport.transport != NCACN_NP) {
3372 return true;
3375 torture_comment(tctx, "testing close on secondary pipe\n");
3377 status = dcerpc_parse_binding(tctx, p->conn->binding_string, &b);
3378 torture_assert_ntstatus_ok(tctx, status, "Failed to parse dcerpc binding");
3380 status = dcerpc_secondary_connection(p, &p2, b);
3381 torture_assert_ntstatus_ok(tctx, status, "Failed to create secondary connection");
3383 status = dcerpc_bind_auth_none(p2, &ndr_table_spoolss);
3384 torture_assert_ntstatus_ok(tctx, status, "Failed to create bind on secondary connection");
3386 cp.in.handle = handle;
3387 cp.out.handle = handle;
3389 status = dcerpc_spoolss_ClosePrinter(p2, tctx, &cp);
3390 torture_assert_ntstatus_equal(tctx, status, NT_STATUS_NET_WRITE_FAULT,
3391 "ERROR: Allowed close on secondary connection");
3393 torture_assert_int_equal(tctx, p2->last_fault_code, DCERPC_FAULT_CONTEXT_MISMATCH,
3394 "Unexpected fault code");
3396 talloc_free(p2);
3398 return true;
3401 static bool test_OpenPrinter_badname(struct torture_context *tctx,
3402 struct dcerpc_pipe *p, const char *name)
3404 NTSTATUS status;
3405 struct spoolss_OpenPrinter op;
3406 struct spoolss_OpenPrinterEx opEx;
3407 struct policy_handle handle;
3408 bool ret = true;
3410 op.in.printername = name;
3411 op.in.datatype = NULL;
3412 op.in.devmode_ctr.devmode= NULL;
3413 op.in.access_mask = 0;
3414 op.out.handle = &handle;
3416 torture_comment(tctx, "\nTesting OpenPrinter(%s) with bad name\n", op.in.printername);
3418 status = dcerpc_spoolss_OpenPrinter(p, tctx, &op);
3419 torture_assert_ntstatus_ok(tctx, status, "OpenPrinter failed");
3420 if (!W_ERROR_EQUAL(WERR_INVALID_PRINTER_NAME,op.out.result)) {
3421 torture_comment(tctx, "OpenPrinter(%s) unexpected result[%s] should be WERR_INVALID_PRINTER_NAME\n",
3422 name, win_errstr(op.out.result));
3425 if (W_ERROR_IS_OK(op.out.result)) {
3426 ret &=test_ClosePrinter(tctx, p, &handle);
3429 opEx.in.printername = name;
3430 opEx.in.datatype = NULL;
3431 opEx.in.devmode_ctr.devmode = NULL;
3432 opEx.in.access_mask = 0;
3433 opEx.in.level = 1;
3434 opEx.in.userlevel.level1 = NULL;
3435 opEx.out.handle = &handle;
3437 torture_comment(tctx, "Testing OpenPrinterEx(%s) with bad name\n", opEx.in.printername);
3439 status = dcerpc_spoolss_OpenPrinterEx(p, tctx, &opEx);
3440 torture_assert_ntstatus_ok(tctx, status, "OpenPrinterEx failed");
3441 if (!W_ERROR_EQUAL(WERR_INVALID_PARAM,opEx.out.result)) {
3442 torture_comment(tctx, "OpenPrinterEx(%s) unexpected result[%s] should be WERR_INVALID_PARAM\n",
3443 name, win_errstr(opEx.out.result));
3446 if (W_ERROR_IS_OK(opEx.out.result)) {
3447 ret &=test_ClosePrinter(tctx, p, &handle);
3450 return ret;
3453 static bool test_OpenPrinter(struct torture_context *tctx,
3454 struct dcerpc_pipe *p,
3455 const char *name)
3457 NTSTATUS status;
3458 struct spoolss_OpenPrinter r;
3459 struct policy_handle handle;
3460 bool ret = true;
3462 r.in.printername = talloc_asprintf(tctx, "\\\\%s\\%s", dcerpc_server_name(p), name);
3463 r.in.datatype = NULL;
3464 r.in.devmode_ctr.devmode= NULL;
3465 r.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
3466 r.out.handle = &handle;
3468 torture_comment(tctx, "Testing OpenPrinter(%s)\n", r.in.printername);
3470 status = dcerpc_spoolss_OpenPrinter(p, tctx, &r);
3472 torture_assert_ntstatus_ok(tctx, status, "OpenPrinter failed");
3474 torture_assert_werr_ok(tctx, r.out.result, "OpenPrinter failed");
3476 if (!test_GetPrinter(tctx, p, &handle)) {
3477 ret = false;
3480 if (!torture_setting_bool(tctx, "samba3", false)) {
3481 if (!test_SecondaryClosePrinter(tctx, p, &handle)) {
3482 ret = false;
3486 if (!test_ClosePrinter(tctx, p, &handle)) {
3487 ret = false;
3490 return ret;
3493 static bool call_OpenPrinterEx(struct torture_context *tctx,
3494 struct dcerpc_pipe *p,
3495 const char *name,
3496 struct spoolss_DeviceMode *devmode,
3497 struct policy_handle *handle)
3499 struct spoolss_OpenPrinterEx r;
3500 struct spoolss_UserLevel1 userlevel1;
3501 NTSTATUS status;
3503 if (name && name[0]) {
3504 r.in.printername = talloc_asprintf(tctx, "\\\\%s\\%s",
3505 dcerpc_server_name(p), name);
3506 } else {
3507 r.in.printername = talloc_asprintf(tctx, "\\\\%s",
3508 dcerpc_server_name(p));
3511 r.in.datatype = NULL;
3512 r.in.devmode_ctr.devmode= devmode;
3513 r.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
3514 r.in.level = 1;
3515 r.in.userlevel.level1 = &userlevel1;
3516 r.out.handle = handle;
3518 userlevel1.size = 1234;
3519 userlevel1.client = "hello";
3520 userlevel1.user = "spottyfoot!";
3521 userlevel1.build = 1;
3522 userlevel1.major = 2;
3523 userlevel1.minor = 3;
3524 userlevel1.processor = 4;
3526 torture_comment(tctx, "Testing OpenPrinterEx(%s)\n", r.in.printername);
3528 status = dcerpc_spoolss_OpenPrinterEx(p, tctx, &r);
3530 torture_assert_ntstatus_ok(tctx, status, "OpenPrinterEx failed");
3532 torture_assert_werr_ok(tctx, r.out.result, "OpenPrinterEx failed");
3534 return true;
3537 static bool test_OpenPrinterEx(struct torture_context *tctx,
3538 struct dcerpc_pipe *p,
3539 const char *name)
3541 struct policy_handle handle;
3542 bool ret = true;
3544 if (!call_OpenPrinterEx(tctx, p, name, NULL, &handle)) {
3545 return false;
3548 if (!test_PrinterInfo_SD(tctx, p, &handle)) {
3549 ret = false;
3552 if (!test_GetPrinter(tctx, p, &handle)) {
3553 ret = false;
3556 if (!test_EnumForms(tctx, p, &handle, false)) {
3557 ret = false;
3560 if (!test_AddForm(tctx, p, &handle, false)) {
3561 ret = false;
3564 if (!test_EnumPrinterData(tctx, p, &handle)) {
3565 ret = false;
3568 if (!test_EnumPrinterDataEx(tctx, p, &handle, "PrinterDriverData")) {
3569 ret = false;
3572 if (!test_printer_keys(tctx, p, &handle)) {
3573 ret = false;
3576 if (!test_PausePrinter(tctx, p, &handle)) {
3577 ret = false;
3580 if (!test_DoPrintTest(tctx, p, &handle)) {
3581 ret = false;
3584 if (!test_ResumePrinter(tctx, p, &handle)) {
3585 ret = false;
3588 if (!test_SetPrinterData(tctx, p, &handle)) {
3589 ret = false;
3592 if (!test_SetPrinterDataEx(tctx, p, &handle)) {
3593 ret = false;
3596 if (!test_ChangeID(tctx, p, &handle)) {
3597 ret = false;
3600 if (!torture_setting_bool(tctx, "samba3", false)) {
3601 if (!test_SecondaryClosePrinter(tctx, p, &handle)) {
3602 ret = false;
3606 if (!test_ClosePrinter(tctx, p, &handle)) {
3607 ret = false;
3610 return ret;
3613 static bool test_EnumPrinters_old(struct torture_context *tctx, struct dcerpc_pipe *p)
3615 struct spoolss_EnumPrinters r;
3616 NTSTATUS status;
3617 uint16_t levels[] = {1, 2, 4, 5};
3618 int i;
3619 bool ret = true;
3621 for (i=0;i<ARRAY_SIZE(levels);i++) {
3622 union spoolss_PrinterInfo *info;
3623 int j;
3624 uint32_t needed;
3625 uint32_t count;
3627 r.in.flags = PRINTER_ENUM_LOCAL;
3628 r.in.server = "";
3629 r.in.level = levels[i];
3630 r.in.buffer = NULL;
3631 r.in.offered = 0;
3632 r.out.needed = &needed;
3633 r.out.count = &count;
3634 r.out.info = &info;
3636 torture_comment(tctx, "Testing EnumPrinters level %u\n", r.in.level);
3638 status = dcerpc_spoolss_EnumPrinters(p, tctx, &r);
3639 torture_assert_ntstatus_ok(tctx, status, "EnumPrinters failed");
3641 if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
3642 DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed);
3643 data_blob_clear(&blob);
3644 r.in.buffer = &blob;
3645 r.in.offered = needed;
3646 status = dcerpc_spoolss_EnumPrinters(p, tctx, &r);
3649 torture_assert_ntstatus_ok(tctx, status, "EnumPrinters failed");
3651 torture_assert_werr_ok(tctx, r.out.result, "EnumPrinters failed");
3653 CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumPrinters, info, r.in.level, count, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
3655 if (!info) {
3656 torture_comment(tctx, "No printers returned\n");
3657 return true;
3660 for (j=0;j<count;j++) {
3661 if (r.in.level == 1) {
3662 char *unc = talloc_strdup(tctx, info[j].info1.name);
3663 char *slash, *name;
3664 name = unc;
3665 if (unc[0] == '\\' && unc[1] == '\\') {
3666 unc +=2;
3668 slash = strchr(unc, '\\');
3669 if (slash) {
3670 slash++;
3671 name = slash;
3673 if (!test_OpenPrinter(tctx, p, name)) {
3674 ret = false;
3676 if (!test_OpenPrinterEx(tctx, p, name)) {
3677 ret = false;
3683 return ret;
3686 static bool test_GetPrinterDriver(struct torture_context *tctx,
3687 struct dcerpc_pipe *p,
3688 struct policy_handle *handle,
3689 const char *driver_name)
3691 struct spoolss_GetPrinterDriver r;
3692 uint32_t needed;
3694 r.in.handle = handle;
3695 r.in.architecture = "W32X86";
3696 r.in.level = 1;
3697 r.in.buffer = NULL;
3698 r.in.offered = 0;
3699 r.out.needed = &needed;
3701 torture_comment(tctx, "Testing GetPrinterDriver level %d\n", r.in.level);
3703 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_GetPrinterDriver(p, tctx, &r),
3704 "failed to call GetPrinterDriver");
3705 if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
3706 DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed);
3707 data_blob_clear(&blob);
3708 r.in.buffer = &blob;
3709 r.in.offered = needed;
3710 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_GetPrinterDriver(p, tctx, &r),
3711 "failed to call GetPrinterDriver");
3714 torture_assert_werr_ok(tctx, r.out.result,
3715 "failed to call GetPrinterDriver");
3717 CHECK_NEEDED_SIZE_LEVEL(spoolss_DriverInfo, r.out.info, r.in.level, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
3719 return true;
3722 static bool test_GetPrinterDriver2(struct torture_context *tctx,
3723 struct dcerpc_pipe *p,
3724 struct policy_handle *handle,
3725 const char *driver_name)
3727 struct spoolss_GetPrinterDriver2 r;
3728 uint16_t levels[] = {1, 2, 3, 4, 5, 6, 8, 101 };
3729 uint32_t needed;
3730 uint32_t server_major_version;
3731 uint32_t server_minor_version;
3732 int i;
3734 r.in.handle = handle;
3735 r.in.architecture = SPOOLSS_ARCHITECTURE_NT_X86;
3736 r.in.client_major_version = 3;
3737 r.in.client_minor_version = 0;
3738 r.out.needed = &needed;
3739 r.out.server_major_version = &server_major_version;
3740 r.out.server_minor_version = &server_minor_version;
3742 for (i=0;i<ARRAY_SIZE(levels);i++) {
3744 r.in.buffer = NULL;
3745 r.in.offered = 0;
3746 r.in.level = levels[i];
3748 torture_comment(tctx, "Testing GetPrinterDriver2(%s) level %d\n",
3749 driver_name, r.in.level);
3751 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_GetPrinterDriver2(p, tctx, &r),
3752 "failed to call GetPrinterDriver2");
3753 if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
3754 DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed);
3755 data_blob_clear(&blob);
3756 r.in.buffer = &blob;
3757 r.in.offered = needed;
3758 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_GetPrinterDriver2(p, tctx, &r),
3759 "failed to call GetPrinterDriver2");
3762 if (W_ERROR_EQUAL(r.out.result, WERR_INVALID_LEVEL)) {
3763 switch (r.in.level) {
3764 case 101:
3765 case 8:
3766 continue;
3767 default:
3768 break;
3772 torture_assert_werr_ok(tctx, r.out.result,
3773 "failed to call GetPrinterDriver2");
3775 CHECK_NEEDED_SIZE_LEVEL(spoolss_DriverInfo, r.out.info, r.in.level, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
3778 return true;
3781 static bool test_EnumPrinterDrivers_old(struct torture_context *tctx,
3782 struct dcerpc_pipe *p)
3784 struct spoolss_EnumPrinterDrivers r;
3785 NTSTATUS status;
3786 uint16_t levels[] = {1, 2, 3, 4, 5, 6};
3787 int i;
3789 for (i=0;i<ARRAY_SIZE(levels);i++) {
3791 uint32_t needed;
3792 uint32_t count;
3793 union spoolss_DriverInfo *info;
3795 r.in.server = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
3796 r.in.environment = SPOOLSS_ARCHITECTURE_NT_X86;
3797 r.in.level = levels[i];
3798 r.in.buffer = NULL;
3799 r.in.offered = 0;
3800 r.out.needed = &needed;
3801 r.out.count = &count;
3802 r.out.info = &info;
3804 torture_comment(tctx, "Testing EnumPrinterDrivers level %u\n", r.in.level);
3806 status = dcerpc_spoolss_EnumPrinterDrivers(p, tctx, &r);
3808 torture_assert_ntstatus_ok(tctx, status, "EnumPrinterDrivers failed");
3810 if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
3811 DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed);
3812 data_blob_clear(&blob);
3813 r.in.buffer = &blob;
3814 r.in.offered = needed;
3815 status = dcerpc_spoolss_EnumPrinterDrivers(p, tctx, &r);
3818 torture_assert_ntstatus_ok(tctx, status, "EnumPrinterDrivers failed");
3820 torture_assert_werr_ok(tctx, r.out.result, "EnumPrinterDrivers failed");
3822 if (!info) {
3823 torture_comment(tctx, "No printer drivers returned\n");
3824 break;
3827 CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumPrinterDrivers, info, r.in.level, count, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
3830 return true;
3833 static bool test_DeletePrinter(struct torture_context *tctx,
3834 struct dcerpc_pipe *p,
3835 struct policy_handle *handle)
3837 struct spoolss_DeletePrinter r;
3839 torture_comment(tctx, "Testing DeletePrinter\n");
3841 r.in.handle = handle;
3843 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_DeletePrinter(p, tctx, &r),
3844 "failed to delete printer");
3845 torture_assert_werr_ok(tctx, r.out.result,
3846 "failed to delete printer");
3848 return true;
3851 static bool test_EnumPrinters_findname(struct torture_context *tctx,
3852 struct dcerpc_pipe *p,
3853 uint32_t flags,
3854 uint32_t level,
3855 const char *name,
3856 bool *found)
3858 struct spoolss_EnumPrinters e;
3859 uint32_t count;
3860 union spoolss_PrinterInfo *info;
3861 uint32_t needed;
3862 int i;
3864 *found = false;
3866 e.in.flags = flags;
3867 e.in.server = NULL;
3868 e.in.level = level;
3869 e.in.buffer = NULL;
3870 e.in.offered = 0;
3871 e.out.count = &count;
3872 e.out.info = &info;
3873 e.out.needed = &needed;
3875 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_EnumPrinters(p, tctx, &e),
3876 "failed to enum printers");
3878 if (W_ERROR_EQUAL(e.out.result, WERR_INSUFFICIENT_BUFFER)) {
3879 DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed);
3880 data_blob_clear(&blob);
3881 e.in.buffer = &blob;
3882 e.in.offered = needed;
3884 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_EnumPrinters(p, tctx, &e),
3885 "failed to enum printers");
3888 torture_assert_werr_ok(tctx, e.out.result,
3889 "failed to enum printers");
3891 for (i=0; i < count; i++) {
3893 const char *current = NULL;
3894 const char *p;
3896 switch (level) {
3897 case 1:
3898 current = info[i].info1.name;
3899 break;
3902 if (strequal(current, name)) {
3903 *found = true;
3904 break;
3907 p = strrchr(current, '\\');
3908 if (p) {
3909 if (!e.in.server) {
3910 torture_warning(tctx,
3911 "server returns printername %s incl. servername although we did not set servername", current);
3913 p++;
3914 if (strequal(p, name)) {
3915 *found = true;
3916 break;
3921 return true;
3924 static bool test_AddPrinter_wellknown(struct torture_context *tctx,
3925 struct dcerpc_pipe *p,
3926 const char *printername,
3927 bool ex)
3929 WERROR result;
3930 struct spoolss_AddPrinter r;
3931 struct spoolss_AddPrinterEx rex;
3932 struct spoolss_SetPrinterInfoCtr info_ctr;
3933 struct spoolss_SetPrinterInfo1 info1;
3934 struct spoolss_DevmodeContainer devmode_ctr;
3935 struct sec_desc_buf secdesc_ctr;
3936 struct spoolss_UserLevelCtr userlevel_ctr;
3937 struct policy_handle handle;
3938 bool found = false;
3940 ZERO_STRUCT(devmode_ctr);
3941 ZERO_STRUCT(secdesc_ctr);
3942 ZERO_STRUCT(userlevel_ctr);
3943 ZERO_STRUCT(info1);
3945 torture_comment(tctx, "Testing AddPrinter%s level 1\n", ex ? "Ex":"");
3947 /* try to add printer to wellknown printer list (level 1) */
3949 userlevel_ctr.level = 1;
3951 info_ctr.info.info1 = &info1;
3952 info_ctr.level = 1;
3954 rex.in.server = NULL;
3955 rex.in.info_ctr = &info_ctr;
3956 rex.in.devmode_ctr = &devmode_ctr;
3957 rex.in.secdesc_ctr = &secdesc_ctr;
3958 rex.in.userlevel_ctr = &userlevel_ctr;
3959 rex.out.handle = &handle;
3961 r.in.server = NULL;
3962 r.in.info_ctr = &info_ctr;
3963 r.in.devmode_ctr = &devmode_ctr;
3964 r.in.secdesc_ctr = &secdesc_ctr;
3965 r.out.handle = &handle;
3967 torture_assert_ntstatus_ok(tctx, ex ? dcerpc_spoolss_AddPrinterEx(p, tctx, &rex) :
3968 dcerpc_spoolss_AddPrinter(p, tctx, &r),
3969 "failed to add printer");
3970 result = ex ? rex.out.result : r.out.result;
3971 torture_assert_werr_equal(tctx, result, WERR_INVALID_PRINTER_NAME,
3972 "unexpected result code");
3974 info1.name = printername;
3975 info1.flags = PRINTER_ATTRIBUTE_SHARED;
3977 torture_assert_ntstatus_ok(tctx, ex ? dcerpc_spoolss_AddPrinterEx(p, tctx, &rex) :
3978 dcerpc_spoolss_AddPrinter(p, tctx, &r),
3979 "failed to add printer");
3980 result = ex ? rex.out.result : r.out.result;
3981 torture_assert_werr_equal(tctx, result, WERR_PRINTER_ALREADY_EXISTS,
3982 "unexpected result code");
3984 /* bizarre protocol, WERR_PRINTER_ALREADY_EXISTS means success here,
3985 better do a real check to see the printer is really there */
3987 torture_assert(tctx, test_EnumPrinters_findname(tctx, p,
3988 PRINTER_ENUM_NETWORK, 1,
3989 printername,
3990 &found),
3991 "failed to enum printers");
3993 torture_assert(tctx, found, "failed to find newly added printer");
3995 info1.flags = 0;
3997 torture_assert_ntstatus_ok(tctx, ex ? dcerpc_spoolss_AddPrinterEx(p, tctx, &rex) :
3998 dcerpc_spoolss_AddPrinter(p, tctx, &r),
3999 "failed to add printer");
4000 result = ex ? rex.out.result : r.out.result;
4001 torture_assert_werr_equal(tctx, result, WERR_PRINTER_ALREADY_EXISTS,
4002 "unexpected result code");
4004 /* bizarre protocol, WERR_PRINTER_ALREADY_EXISTS means success here,
4005 better do a real check to see the printer has really been removed
4006 from the well known printer list */
4008 found = false;
4010 torture_assert(tctx, test_EnumPrinters_findname(tctx, p,
4011 PRINTER_ENUM_NETWORK, 1,
4012 printername,
4013 &found),
4014 "failed to enum printers");
4015 #if 0
4016 torture_assert(tctx, !found, "printer still in well known printer list");
4017 #endif
4018 return true;
4021 static bool test_AddPrinter_normal(struct torture_context *tctx,
4022 struct dcerpc_pipe *p,
4023 struct policy_handle *handle_p,
4024 const char *printername,
4025 const char *drivername,
4026 const char *portname,
4027 bool ex)
4029 WERROR result;
4030 struct spoolss_AddPrinter r;
4031 struct spoolss_AddPrinterEx rex;
4032 struct spoolss_SetPrinterInfoCtr info_ctr;
4033 struct spoolss_SetPrinterInfo2 info2;
4034 struct spoolss_DevmodeContainer devmode_ctr;
4035 struct sec_desc_buf secdesc_ctr;
4036 struct spoolss_UserLevelCtr userlevel_ctr;
4037 struct policy_handle handle;
4038 bool found = false;
4039 bool existing_printer_deleted = false;
4041 ZERO_STRUCT(devmode_ctr);
4042 ZERO_STRUCT(secdesc_ctr);
4043 ZERO_STRUCT(userlevel_ctr);
4045 torture_comment(tctx, "Testing AddPrinter%s level 2\n", ex ? "Ex":"");
4047 userlevel_ctr.level = 1;
4049 rex.in.server = NULL;
4050 rex.in.info_ctr = &info_ctr;
4051 rex.in.devmode_ctr = &devmode_ctr;
4052 rex.in.secdesc_ctr = &secdesc_ctr;
4053 rex.in.userlevel_ctr = &userlevel_ctr;
4054 rex.out.handle = &handle;
4056 r.in.server = NULL;
4057 r.in.info_ctr = &info_ctr;
4058 r.in.devmode_ctr = &devmode_ctr;
4059 r.in.secdesc_ctr = &secdesc_ctr;
4060 r.out.handle = &handle;
4062 again:
4064 /* try to add printer to printer list (level 2) */
4066 ZERO_STRUCT(info2);
4068 info_ctr.info.info2 = &info2;
4069 info_ctr.level = 2;
4071 torture_assert_ntstatus_ok(tctx, ex ? dcerpc_spoolss_AddPrinterEx(p, tctx, &rex) :
4072 dcerpc_spoolss_AddPrinter(p, tctx, &r),
4073 "failed to add printer");
4074 result = ex ? rex.out.result : r.out.result;
4075 torture_assert_werr_equal(tctx, result, WERR_INVALID_PRINTER_NAME,
4076 "unexpected result code");
4078 info2.printername = printername;
4080 torture_assert_ntstatus_ok(tctx, ex ? dcerpc_spoolss_AddPrinterEx(p, tctx, &rex) :
4081 dcerpc_spoolss_AddPrinter(p, tctx, &r),
4082 "failed to add printer");
4083 result = ex ? rex.out.result : r.out.result;
4085 if (W_ERROR_EQUAL(result, WERR_PRINTER_ALREADY_EXISTS)) {
4086 struct policy_handle printer_handle;
4088 if (existing_printer_deleted) {
4089 torture_fail(tctx, "already deleted printer still existing?");
4092 torture_assert(tctx, call_OpenPrinterEx(tctx, p, printername, NULL, &printer_handle),
4093 "failed to open printer handle");
4095 torture_assert(tctx, test_DeletePrinter(tctx, p, &printer_handle),
4096 "failed to delete printer");
4098 torture_assert(tctx, test_ClosePrinter(tctx, p, &printer_handle),
4099 "failed to close server handle");
4101 existing_printer_deleted = true;
4103 goto again;
4106 torture_assert_werr_equal(tctx, result, WERR_UNKNOWN_PORT,
4107 "unexpected result code");
4109 info2.portname = portname;
4111 torture_assert_ntstatus_ok(tctx, ex ? dcerpc_spoolss_AddPrinterEx(p, tctx, &rex) :
4112 dcerpc_spoolss_AddPrinter(p, tctx, &r),
4113 "failed to add printer");
4114 result = ex ? rex.out.result : r.out.result;
4115 torture_assert_werr_equal(tctx, result, WERR_UNKNOWN_PRINTER_DRIVER,
4116 "unexpected result code");
4118 info2.drivername = drivername;
4120 torture_assert_ntstatus_ok(tctx, ex ? dcerpc_spoolss_AddPrinterEx(p, tctx, &rex) :
4121 dcerpc_spoolss_AddPrinter(p, tctx, &r),
4122 "failed to add printer");
4123 result = ex ? rex.out.result : r.out.result;
4125 /* w2k8r2 allows to add printer w/o defining printprocessor */
4127 if (!W_ERROR_IS_OK(result)) {
4128 torture_assert_werr_equal(tctx, result, WERR_UNKNOWN_PRINTPROCESSOR,
4129 "unexpected result code");
4131 info2.printprocessor = "winprint";
4133 torture_assert_ntstatus_ok(tctx, ex ? dcerpc_spoolss_AddPrinterEx(p, tctx, &rex) :
4134 dcerpc_spoolss_AddPrinter(p, tctx, &r),
4135 "failed to add printer");
4136 result = ex ? rex.out.result : r.out.result;
4137 torture_assert_werr_ok(tctx, result,
4138 "failed to add printer");
4141 *handle_p = handle;
4143 /* we are paranoid, really check if the printer is there now */
4145 torture_assert(tctx, test_EnumPrinters_findname(tctx, p,
4146 PRINTER_ENUM_LOCAL, 1,
4147 printername,
4148 &found),
4149 "failed to enum printers");
4150 torture_assert(tctx, found, "failed to find newly added printer");
4152 torture_assert_ntstatus_ok(tctx, ex ? dcerpc_spoolss_AddPrinterEx(p, tctx, &rex) :
4153 dcerpc_spoolss_AddPrinter(p, tctx, &r),
4154 "failed to add printer");
4155 result = ex ? rex.out.result : r.out.result;
4156 torture_assert_werr_equal(tctx, result, WERR_PRINTER_ALREADY_EXISTS,
4157 "unexpected result code");
4159 return true;
4162 static bool test_AddPrinterEx(struct torture_context *tctx,
4163 struct dcerpc_pipe *p,
4164 struct policy_handle *handle_p,
4165 const char *printername,
4166 const char *drivername,
4167 const char *portname)
4169 bool ret = true;
4171 if (!torture_setting_bool(tctx, "samba3", false)) {
4172 if (!test_AddPrinter_wellknown(tctx, p, TORTURE_WELLKNOWN_PRINTER_EX, true)) {
4173 torture_comment(tctx, "failed to add printer to well known list\n");
4174 ret = false;
4178 if (!test_AddPrinter_normal(tctx, p, handle_p,
4179 printername, drivername, portname,
4180 true)) {
4181 torture_comment(tctx, "failed to add printer to printer list\n");
4182 ret = false;
4185 return ret;
4188 static bool test_AddPrinter(struct torture_context *tctx,
4189 struct dcerpc_pipe *p,
4190 struct policy_handle *handle_p,
4191 const char *printername,
4192 const char *drivername,
4193 const char *portname)
4195 bool ret = true;
4197 if (!torture_setting_bool(tctx, "samba3", false)) {
4198 if (!test_AddPrinter_wellknown(tctx, p, TORTURE_WELLKNOWN_PRINTER, false)) {
4199 torture_comment(tctx, "failed to add printer to well known list\n");
4200 ret = false;
4204 if (!test_AddPrinter_normal(tctx, p, handle_p,
4205 printername, drivername, portname,
4206 false)) {
4207 torture_comment(tctx, "failed to add printer to printer list\n");
4208 ret = false;
4211 return ret;
4214 static bool test_printer_info(struct torture_context *tctx,
4215 struct dcerpc_pipe *p,
4216 struct policy_handle *handle)
4218 bool ret = true;
4220 if (torture_setting_bool(tctx, "samba3", false)) {
4221 torture_skip(tctx, "skipping printer info cross tests against samba 3");
4224 if (!test_PrinterInfo(tctx, p, handle)) {
4225 ret = false;
4228 if (!test_SetPrinter_errors(tctx, p, handle)) {
4229 ret = false;
4232 return ret;
4235 static bool test_EnumPrinterKey(struct torture_context *tctx,
4236 struct dcerpc_pipe *p,
4237 struct policy_handle *handle,
4238 const char *key_name,
4239 const char ***array)
4241 struct spoolss_EnumPrinterKey r;
4242 uint32_t needed = 0;
4243 union spoolss_KeyNames key_buffer;
4244 int32_t offered[] = { 0, 1, 2, 3, 4, 5, -1, -2, -3, -4, -5, 256, 512, 1024, 2048 };
4245 uint32_t _ndr_size;
4246 int i;
4248 r.in.handle = handle;
4249 r.in.key_name = key_name;
4250 r.out.key_buffer = &key_buffer;
4251 r.out.needed = &needed;
4252 r.out._ndr_size = &_ndr_size;
4254 for (i=0; i < ARRAY_SIZE(offered); i++) {
4256 if (offered[i] < 0 && needed) {
4257 if (needed <= 4) {
4258 continue;
4260 r.in.offered = needed + offered[i];
4261 } else {
4262 r.in.offered = offered[i];
4265 ZERO_STRUCT(key_buffer);
4267 torture_comment(tctx, "Testing EnumPrinterKey(%s) with %d offered\n", r.in.key_name, r.in.offered);
4269 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_EnumPrinterKey(p, tctx, &r),
4270 "failed to call EnumPrinterKey");
4271 if (W_ERROR_EQUAL(r.out.result, WERR_MORE_DATA)) {
4273 torture_assert(tctx, (_ndr_size == r.in.offered/2),
4274 talloc_asprintf(tctx, "EnumPrinterKey size mismatch, _ndr_size %d (expected %d)",
4275 _ndr_size, r.in.offered/2));
4277 r.in.offered = needed;
4278 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_EnumPrinterKey(p, tctx, &r),
4279 "failed to call EnumPrinterKey");
4282 if (offered[i] > 0) {
4283 torture_assert_werr_ok(tctx, r.out.result,
4284 "failed to call EnumPrinterKey");
4287 torture_assert(tctx, (_ndr_size == r.in.offered/2),
4288 talloc_asprintf(tctx, "EnumPrinterKey size mismatch, _ndr_size %d (expected %d)",
4289 _ndr_size, r.in.offered/2));
4291 torture_assert(tctx, (*r.out.needed <= r.in.offered),
4292 talloc_asprintf(tctx, "EnumPrinterKey size mismatch: needed %d is not <= offered %d", *r.out.needed, r.in.offered));
4294 torture_assert(tctx, (*r.out.needed <= _ndr_size * 2),
4295 talloc_asprintf(tctx, "EnumPrinterKey size mismatch: needed %d is not <= _ndr_size %d * 2", *r.out.needed, _ndr_size));
4297 if (key_buffer.string_array) {
4298 uint32_t calc_needed = 0;
4299 int s;
4300 for (s=0; key_buffer.string_array[s]; s++) {
4301 calc_needed += strlen_m_term(key_buffer.string_array[s])*2;
4303 if (!key_buffer.string_array[0]) {
4304 calc_needed += 2;
4306 calc_needed += 2;
4308 torture_assert_int_equal(tctx, *r.out.needed, calc_needed,
4309 "EnumPrinterKey unexpected size");
4313 if (array) {
4314 *array = key_buffer.string_array;
4317 return true;
4320 bool test_printer_keys(struct torture_context *tctx,
4321 struct dcerpc_pipe *p,
4322 struct policy_handle *handle)
4324 const char **key_array = NULL;
4325 int i;
4327 torture_assert(tctx, test_EnumPrinterKey(tctx, p, handle, "", &key_array),
4328 "failed to call test_EnumPrinterKey");
4330 for (i=0; key_array && key_array[i]; i++) {
4331 torture_assert(tctx, test_EnumPrinterKey(tctx, p, handle, key_array[i], NULL),
4332 "failed to call test_EnumPrinterKey");
4334 for (i=0; key_array && key_array[i]; i++) {
4335 torture_assert(tctx, test_EnumPrinterDataEx(tctx, p, handle, key_array[i]),
4336 "failed to call test_EnumPrinterDataEx");
4339 return true;
4342 static bool test_one_printer(struct torture_context *tctx,
4343 struct dcerpc_pipe *p,
4344 struct policy_handle *handle,
4345 const char *name)
4347 bool ret = true;
4349 if (!test_printer_info(tctx, p, handle)) {
4350 ret = false;
4353 if (!test_PrinterInfo_SD(tctx, p, handle)) {
4354 ret = false;
4357 if (!test_PrinterInfo_DevMode(tctx, p, handle, name)) {
4358 ret = false;
4361 if (!test_printer_keys(tctx, p, handle)) {
4362 ret = false;
4365 return ret;
4368 static bool test_printer(struct torture_context *tctx,
4369 struct dcerpc_pipe *p)
4371 bool ret = true;
4372 struct policy_handle handle[2];
4373 bool found = false;
4374 const char *drivername = "Microsoft XPS Document Writer";
4375 const char *portname = "LPT1:";
4377 /* test printer created via AddPrinter */
4379 if (!test_AddPrinter(tctx, p, &handle[0], TORTURE_PRINTER, drivername, portname)) {
4380 return false;
4383 if (!test_one_printer(tctx, p, &handle[0], TORTURE_PRINTER)) {
4384 ret = false;
4387 if (!test_DeletePrinter(tctx, p, &handle[0])) {
4388 ret = false;
4391 if (!test_EnumPrinters_findname(tctx, p, PRINTER_ENUM_LOCAL, 1,
4392 TORTURE_PRINTER, &found)) {
4393 ret = false;
4396 torture_assert(tctx, !found, "deleted printer still there");
4398 /* test printer created via AddPrinterEx */
4400 if (!test_AddPrinterEx(tctx, p, &handle[1], TORTURE_PRINTER_EX, drivername, portname)) {
4401 return false;
4404 if (!test_one_printer(tctx, p, &handle[1], TORTURE_PRINTER_EX)) {
4405 ret = false;
4408 if (!test_DeletePrinter(tctx, p, &handle[1])) {
4409 ret = false;
4412 if (!test_EnumPrinters_findname(tctx, p, PRINTER_ENUM_LOCAL, 1,
4413 TORTURE_PRINTER_EX, &found)) {
4414 ret = false;
4417 torture_assert(tctx, !found, "deleted printer still there");
4419 return ret;
4422 bool torture_rpc_spoolss(struct torture_context *torture)
4424 NTSTATUS status;
4425 struct dcerpc_pipe *p;
4426 bool ret = true;
4427 struct test_spoolss_context *ctx;
4429 status = torture_rpc_connection(torture, &p, &ndr_table_spoolss);
4430 if (!NT_STATUS_IS_OK(status)) {
4431 return false;
4434 ctx = talloc_zero(torture, struct test_spoolss_context);
4436 ret &= test_OpenPrinter_server(torture, p, &ctx->server_handle);
4437 ret &= test_GetPrinterData_list(torture, p, &ctx->server_handle);
4438 ret &= test_EnumForms(torture, p, &ctx->server_handle, true);
4439 ret &= test_AddForm(torture, p, &ctx->server_handle, true);
4440 ret &= test_EnumPorts(torture, p, ctx);
4441 ret &= test_GetPrinterDriverDirectory(torture, p, ctx);
4442 ret &= test_GetPrintProcessorDirectory(torture, p, ctx);
4443 ret &= test_EnumPrinterDrivers(torture, p, ctx, SPOOLSS_ARCHITECTURE_NT_X86);
4444 ret &= test_EnumPrinterDrivers(torture, p, ctx, SPOOLSS_ARCHITECTURE_ALL);
4445 ret &= test_EnumMonitors(torture, p, ctx);
4446 ret &= test_EnumPrintProcessors(torture, p, ctx);
4447 ret &= test_EnumPrintProcDataTypes(torture, p, ctx);
4448 ret &= test_EnumPrinters(torture, p, ctx);
4449 ret &= test_OpenPrinter_badname(torture, p, "__INVALID_PRINTER__");
4450 ret &= test_OpenPrinter_badname(torture, p, "\\\\__INVALID_HOST__");
4451 ret &= test_OpenPrinter_badname(torture, p, "");
4452 ret &= test_OpenPrinter_badname(torture, p, "\\\\\\");
4453 ret &= test_OpenPrinter_badname(torture, p, "\\\\\\__INVALID_PRINTER__");
4454 ret &= test_OpenPrinter_badname(torture, p, talloc_asprintf(torture, "\\\\%s\\", dcerpc_server_name(p)));
4455 ret &= test_OpenPrinter_badname(torture, p,
4456 talloc_asprintf(torture, "\\\\%s\\__INVALID_PRINTER__", dcerpc_server_name(p)));
4459 ret &= test_AddPort(torture, p);
4460 ret &= test_EnumPorts_old(torture, p);
4461 ret &= test_EnumPrinters_old(torture, p);
4462 ret &= test_EnumPrinterDrivers_old(torture, p);
4464 return ret;
4467 struct torture_suite *torture_rpc_spoolss_printer(TALLOC_CTX *mem_ctx)
4469 struct torture_suite *suite = torture_suite_create(mem_ctx, "SPOOLSS-PRINTER");
4471 struct torture_rpc_tcase *tcase = torture_suite_add_rpc_iface_tcase(suite,
4472 "printer", &ndr_table_spoolss);
4474 torture_rpc_tcase_add_test(tcase, "printer", test_printer);
4476 return suite;