s4-smbtorture: test at least three different regtypes in test_SetPrinterDataEx.
[Samba/cd1.git] / source4 / torture / rpc / spoolss.c
blobf652b5b6fe7c37401b626ff5462d534d419f74b9
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,
260 const char *environment)
262 NTSTATUS status;
263 struct spoolss_GetPrintProcessorDirectory r;
264 struct {
265 uint16_t level;
266 const char *server;
267 } levels[] = {{
268 .level = 1,
269 .server = NULL
271 .level = 1,
272 .server = ""
274 .level = 78,
275 .server = ""
277 .level = 1,
278 .server = talloc_asprintf(ctx, "\\\\%s", dcerpc_server_name(p))
280 .level = 1024,
281 .server = talloc_asprintf(ctx, "\\\\%s", dcerpc_server_name(p))
284 int i;
285 uint32_t needed;
287 for (i=0;i<ARRAY_SIZE(levels);i++) {
288 int level = levels[i].level;
289 DATA_BLOB blob;
291 r.in.server = levels[i].server;
292 r.in.environment = environment;
293 r.in.level = level;
294 r.in.buffer = NULL;
295 r.in.offered = 0;
296 r.out.needed = &needed;
298 torture_comment(tctx, "Testing GetPrintProcessorDirectory level %u\n", r.in.level);
300 status = dcerpc_spoolss_GetPrintProcessorDirectory(p, ctx, &r);
301 torture_assert_ntstatus_ok(tctx, status,
302 "dcerpc_spoolss_GetPrintProcessorDirectory failed");
303 torture_assert_werr_equal(tctx, r.out.result, WERR_INSUFFICIENT_BUFFER,
304 "GetPrintProcessorDirectory unexpected return code");
306 blob = data_blob_talloc(ctx, NULL, needed);
307 data_blob_clear(&blob);
308 r.in.buffer = &blob;
309 r.in.offered = needed;
311 status = dcerpc_spoolss_GetPrintProcessorDirectory(p, ctx, &r);
312 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_GetPrintProcessorDirectory failed");
314 torture_assert_werr_ok(tctx, r.out.result, "GetPrintProcessorDirectory failed");
316 CHECK_NEEDED_SIZE_LEVEL(spoolss_PrintProcessorDirectoryInfo, r.out.info, r.in.level, lp_iconv_convenience(tctx->lp_ctx), needed, 2);
319 return true;
323 static bool test_GetPrinterDriverDirectory(struct torture_context *tctx,
324 struct dcerpc_pipe *p,
325 struct test_spoolss_context *ctx,
326 const char *environment)
328 NTSTATUS status;
329 struct spoolss_GetPrinterDriverDirectory r;
330 struct {
331 uint16_t level;
332 const char *server;
333 } levels[] = {{
334 .level = 1,
335 .server = NULL
337 .level = 1,
338 .server = ""
340 .level = 78,
341 .server = ""
343 .level = 1,
344 .server = talloc_asprintf(ctx, "\\\\%s", dcerpc_server_name(p))
346 .level = 1024,
347 .server = talloc_asprintf(ctx, "\\\\%s", dcerpc_server_name(p))
350 int i;
351 uint32_t needed;
353 for (i=0;i<ARRAY_SIZE(levels);i++) {
354 int level = levels[i].level;
355 DATA_BLOB blob;
357 r.in.server = levels[i].server;
358 r.in.environment = environment;
359 r.in.level = level;
360 r.in.buffer = NULL;
361 r.in.offered = 0;
362 r.out.needed = &needed;
364 torture_comment(tctx, "Testing GetPrinterDriverDirectory level %u\n", r.in.level);
366 status = dcerpc_spoolss_GetPrinterDriverDirectory(p, ctx, &r);
367 torture_assert_ntstatus_ok(tctx, status,
368 "dcerpc_spoolss_GetPrinterDriverDirectory failed");
369 torture_assert_werr_equal(tctx, r.out.result, WERR_INSUFFICIENT_BUFFER,
370 "GetPrinterDriverDirectory unexpected return code");
372 blob = data_blob_talloc(ctx, NULL, needed);
373 data_blob_clear(&blob);
374 r.in.buffer = &blob;
375 r.in.offered = needed;
377 status = dcerpc_spoolss_GetPrinterDriverDirectory(p, ctx, &r);
378 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_GetPrinterDriverDirectory failed");
380 torture_assert_werr_ok(tctx, r.out.result, "GetPrinterDriverDirectory failed");
382 CHECK_NEEDED_SIZE_LEVEL(spoolss_DriverDirectoryInfo, r.out.info, r.in.level, lp_iconv_convenience(tctx->lp_ctx), needed, 2);
385 return true;
388 static bool test_EnumPrinterDrivers(struct torture_context *tctx,
389 struct dcerpc_pipe *p,
390 struct test_spoolss_context *ctx,
391 const char *architecture)
393 NTSTATUS status;
394 struct spoolss_EnumPrinterDrivers r;
395 uint16_t levels[] = { 1, 2, 3, 4, 5, 6, 8 };
396 int i, j;
398 for (i=0;i<ARRAY_SIZE(levels);i++) {
399 int level = levels[i];
400 DATA_BLOB blob;
401 uint32_t needed;
402 uint32_t count;
403 union spoolss_DriverInfo *info;
405 /* FIXME: gd, come back and fix "" as server, and handle
406 * priority of returned error codes in torture test and samba 3
407 * server */
409 r.in.server = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
410 r.in.environment = architecture;
411 r.in.level = level;
412 r.in.buffer = NULL;
413 r.in.offered = 0;
414 r.out.needed = &needed;
415 r.out.count = &count;
416 r.out.info = &info;
418 torture_comment(tctx, "Testing EnumPrinterDrivers level %u (%s)\n", r.in.level, r.in.environment);
420 status = dcerpc_spoolss_EnumPrinterDrivers(p, ctx, &r);
421 torture_assert_ntstatus_ok(tctx, status,
422 "dcerpc_spoolss_EnumPrinterDrivers failed");
423 if (W_ERROR_IS_OK(r.out.result)) {
424 /* TODO: do some more checks here */
425 continue;
427 if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
428 blob = data_blob_talloc(ctx, NULL, needed);
429 data_blob_clear(&blob);
430 r.in.buffer = &blob;
431 r.in.offered = needed;
433 status = dcerpc_spoolss_EnumPrinterDrivers(p, ctx, &r);
434 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EnumPrinterDrivers failed");
437 torture_assert_werr_ok(tctx, r.out.result, "EnumPrinterDrivers failed");
439 CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumPrinterDrivers, info, r.in.level, count, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
441 ctx->driver_count[level] = count;
442 ctx->drivers[level] = info;
445 for (i=1;i<ARRAY_SIZE(levels);i++) {
446 int level = levels[i];
447 int old_level = levels[i-1];
449 torture_assert_int_equal(tctx, ctx->driver_count[level], ctx->driver_count[old_level],
450 "EnumPrinterDrivers invalid value");
453 for (i=0;i<ARRAY_SIZE(levels);i++) {
454 int level = levels[i];
456 for (j=0;j<ctx->driver_count[level];j++) {
457 union spoolss_DriverInfo *cur = &ctx->drivers[level][j];
458 union spoolss_DriverInfo *ref = &ctx->drivers[8][j];
460 switch (level) {
461 case 1:
462 COMPARE_STRING(tctx, cur->info1, ref->info8, driver_name);
463 break;
464 case 2:
465 COMPARE_UINT32(tctx, cur->info2, ref->info8, version);
466 COMPARE_STRING(tctx, cur->info2, ref->info8, driver_name);
467 COMPARE_STRING(tctx, cur->info2, ref->info8, architecture);
468 COMPARE_STRING(tctx, cur->info2, ref->info8, driver_path);
469 COMPARE_STRING(tctx, cur->info2, ref->info8, data_file);
470 COMPARE_STRING(tctx, cur->info2, ref->info8, config_file);
471 break;
472 case 3:
473 COMPARE_UINT32(tctx, cur->info3, ref->info8, version);
474 COMPARE_STRING(tctx, cur->info3, ref->info8, driver_name);
475 COMPARE_STRING(tctx, cur->info3, ref->info8, architecture);
476 COMPARE_STRING(tctx, cur->info3, ref->info8, driver_path);
477 COMPARE_STRING(tctx, cur->info3, ref->info8, data_file);
478 COMPARE_STRING(tctx, cur->info3, ref->info8, config_file);
479 COMPARE_STRING(tctx, cur->info3, ref->info8, help_file);
480 COMPARE_STRING_ARRAY(tctx, cur->info3, ref->info8, dependent_files);
481 COMPARE_STRING(tctx, cur->info3, ref->info8, monitor_name);
482 COMPARE_STRING(tctx, cur->info3, ref->info8, default_datatype);
483 break;
484 case 4:
485 COMPARE_UINT32(tctx, cur->info4, ref->info8, version);
486 COMPARE_STRING(tctx, cur->info4, ref->info8, driver_name);
487 COMPARE_STRING(tctx, cur->info4, ref->info8, architecture);
488 COMPARE_STRING(tctx, cur->info4, ref->info8, driver_path);
489 COMPARE_STRING(tctx, cur->info4, ref->info8, data_file);
490 COMPARE_STRING(tctx, cur->info4, ref->info8, config_file);
491 COMPARE_STRING(tctx, cur->info4, ref->info8, help_file);
492 COMPARE_STRING_ARRAY(tctx, cur->info4, ref->info8, dependent_files);
493 COMPARE_STRING(tctx, cur->info4, ref->info8, monitor_name);
494 COMPARE_STRING(tctx, cur->info4, ref->info8, default_datatype);
495 COMPARE_STRING_ARRAY(tctx, cur->info4, ref->info8, previous_names);
496 break;
497 case 5:
498 COMPARE_UINT32(tctx, cur->info5, ref->info8, version);
499 COMPARE_STRING(tctx, cur->info5, ref->info8, driver_name);
500 COMPARE_STRING(tctx, cur->info5, ref->info8, architecture);
501 COMPARE_STRING(tctx, cur->info5, ref->info8, driver_path);
502 COMPARE_STRING(tctx, cur->info5, ref->info8, data_file);
503 COMPARE_STRING(tctx, cur->info5, ref->info8, config_file);
504 /*COMPARE_UINT32(tctx, cur->info5, ref->info8, driver_attributes);*/
505 /*COMPARE_UINT32(tctx, cur->info5, ref->info8, config_version);*/
506 /*TODO: ! COMPARE_UINT32(tctx, cur->info5, ref->info8, driver_version); */
507 break;
508 case 6:
509 COMPARE_UINT32(tctx, cur->info6, ref->info8, version);
510 COMPARE_STRING(tctx, cur->info6, ref->info8, driver_name);
511 COMPARE_STRING(tctx, cur->info6, ref->info8, architecture);
512 COMPARE_STRING(tctx, cur->info6, ref->info8, driver_path);
513 COMPARE_STRING(tctx, cur->info6, ref->info8, data_file);
514 COMPARE_STRING(tctx, cur->info6, ref->info8, config_file);
515 COMPARE_STRING(tctx, cur->info6, ref->info8, help_file);
516 COMPARE_STRING_ARRAY(tctx, cur->info6, ref->info8, dependent_files);
517 COMPARE_STRING(tctx, cur->info6, ref->info8, monitor_name);
518 COMPARE_STRING(tctx, cur->info6, ref->info8, default_datatype);
519 COMPARE_STRING_ARRAY(tctx, cur->info6, ref->info8, previous_names);
520 COMPARE_NTTIME(tctx, cur->info6, ref->info8, driver_date);
521 COMPARE_UINT64(tctx, cur->info6, ref->info8, driver_version);
522 COMPARE_STRING(tctx, cur->info6, ref->info8, manufacturer_name);
523 COMPARE_STRING(tctx, cur->info6, ref->info8, manufacturer_url);
524 COMPARE_STRING(tctx, cur->info6, ref->info8, hardware_id);
525 COMPARE_STRING(tctx, cur->info6, ref->info8, provider);
526 break;
527 case 8:
528 /* level 8 is our reference, and it makes no sense to compare it to itself */
529 break;
534 return true;
537 static bool test_EnumMonitors(struct torture_context *tctx,
538 struct dcerpc_pipe *p,
539 struct test_spoolss_context *ctx)
541 NTSTATUS status;
542 struct spoolss_EnumMonitors r;
543 uint16_t levels[] = { 1, 2 };
544 int i, j;
546 for (i=0;i<ARRAY_SIZE(levels);i++) {
547 int level = levels[i];
548 DATA_BLOB blob;
549 uint32_t needed;
550 uint32_t count;
551 union spoolss_MonitorInfo *info;
553 r.in.servername = "";
554 r.in.level = level;
555 r.in.buffer = NULL;
556 r.in.offered = 0;
557 r.out.needed = &needed;
558 r.out.count = &count;
559 r.out.info = &info;
561 torture_comment(tctx, "Testing EnumMonitors level %u\n", r.in.level);
563 status = dcerpc_spoolss_EnumMonitors(p, ctx, &r);
564 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EnumMonitors failed");
565 if (W_ERROR_IS_OK(r.out.result)) {
566 /* TODO: do some more checks here */
567 continue;
569 torture_assert_werr_equal(tctx, r.out.result, WERR_INSUFFICIENT_BUFFER,
570 "EnumMonitors failed");
572 blob = data_blob_talloc(ctx, NULL, needed);
573 data_blob_clear(&blob);
574 r.in.buffer = &blob;
575 r.in.offered = needed;
577 status = dcerpc_spoolss_EnumMonitors(p, ctx, &r);
578 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EnumMonitors failed");
580 torture_assert_werr_ok(tctx, r.out.result, "EnumMonitors failed");
582 CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumMonitors, info, r.in.level, count, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
584 ctx->monitor_count[level] = count;
585 ctx->monitors[level] = info;
588 for (i=1;i<ARRAY_SIZE(levels);i++) {
589 int level = levels[i];
590 int old_level = levels[i-1];
591 torture_assert_int_equal(tctx, ctx->monitor_count[level], ctx->monitor_count[old_level],
592 "EnumMonitors invalid value");
595 for (i=0;i<ARRAY_SIZE(levels);i++) {
596 int level = levels[i];
597 for (j=0;j<ctx->monitor_count[level];j++) {
598 union spoolss_MonitorInfo *cur = &ctx->monitors[level][j];
599 union spoolss_MonitorInfo *ref = &ctx->monitors[2][j];
600 switch (level) {
601 case 1:
602 COMPARE_STRING(tctx, cur->info1, ref->info2, monitor_name);
603 break;
604 case 2:
605 /* level 2 is our reference, and it makes no sense to compare it to itself */
606 break;
611 return true;
614 static bool test_EnumPrintProcessors(struct torture_context *tctx,
615 struct dcerpc_pipe *p,
616 struct test_spoolss_context *ctx,
617 const char *environment)
619 NTSTATUS status;
620 struct spoolss_EnumPrintProcessors r;
621 uint16_t levels[] = { 1 };
622 int i, j;
624 for (i=0;i<ARRAY_SIZE(levels);i++) {
625 int level = levels[i];
626 DATA_BLOB blob;
627 uint32_t needed;
628 uint32_t count;
629 union spoolss_PrintProcessorInfo *info;
631 r.in.servername = "";
632 r.in.environment = environment;
633 r.in.level = level;
634 r.in.buffer = NULL;
635 r.in.offered = 0;
636 r.out.needed = &needed;
637 r.out.count = &count;
638 r.out.info = &info;
640 torture_comment(tctx, "Testing EnumPrintProcessors level %u\n", r.in.level);
642 status = dcerpc_spoolss_EnumPrintProcessors(p, ctx, &r);
643 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EnumPrintProcessors failed");
644 if (W_ERROR_IS_OK(r.out.result)) {
645 /* TODO: do some more checks here */
646 continue;
648 torture_assert_werr_equal(tctx, r.out.result, WERR_INSUFFICIENT_BUFFER,
649 "EnumPrintProcessors unexpected return code");
651 blob = data_blob_talloc(ctx, NULL, needed);
652 data_blob_clear(&blob);
653 r.in.buffer = &blob;
654 r.in.offered = needed;
656 status = dcerpc_spoolss_EnumPrintProcessors(p, ctx, &r);
657 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EnumPrintProcessors failed");
659 torture_assert_werr_ok(tctx, r.out.result, "EnumPrintProcessors failed");
661 CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumPrintProcessors, info, r.in.level, count, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
663 ctx->print_processor_count[level] = count;
664 ctx->print_processors[level] = info;
667 for (i=1;i<ARRAY_SIZE(levels);i++) {
668 int level = levels[i];
669 int old_level = levels[i-1];
670 torture_assert_int_equal(tctx, ctx->print_processor_count[level], ctx->print_processor_count[old_level],
671 "EnumPrintProcessors failed");
674 for (i=0;i<ARRAY_SIZE(levels);i++) {
675 int level = levels[i];
676 for (j=0;j<ctx->print_processor_count[level];j++) {
677 #if 0
678 union spoolss_PrintProcessorInfo *cur = &ctx->print_processors[level][j];
679 union spoolss_PrintProcessorInfo *ref = &ctx->print_processors[1][j];
680 #endif
681 switch (level) {
682 case 1:
683 /* level 1 is our reference, and it makes no sense to compare it to itself */
684 break;
689 return true;
692 static bool test_EnumPrintProcDataTypes(struct torture_context *tctx,
693 struct dcerpc_pipe *p,
694 struct test_spoolss_context *ctx)
696 NTSTATUS status;
697 struct spoolss_EnumPrintProcDataTypes r;
698 uint16_t levels[] = { 1 };
699 int i;
701 for (i=0;i<ARRAY_SIZE(levels);i++) {
702 int level = levels[i];
703 DATA_BLOB blob;
704 uint32_t needed;
705 uint32_t count;
706 union spoolss_PrintProcDataTypesInfo *info;
708 r.in.servername = "";
709 r.in.print_processor_name = "winprint";
710 r.in.level = level;
711 r.in.buffer = NULL;
712 r.in.offered = 0;
713 r.out.needed = &needed;
714 r.out.count = &count;
715 r.out.info = &info;
717 torture_comment(tctx, "Testing EnumPrintProcDataTypes level %u\n", r.in.level);
719 status = dcerpc_spoolss_EnumPrintProcDataTypes(p, ctx, &r);
720 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EnumPrintProcDataType failed");
721 if (W_ERROR_IS_OK(r.out.result)) {
722 /* TODO: do some more checks here */
723 continue;
725 torture_assert_werr_equal(tctx, r.out.result, WERR_INSUFFICIENT_BUFFER,
726 "EnumPrintProcDataTypes unexpected return code");
728 blob = data_blob_talloc(ctx, NULL, needed);
729 data_blob_clear(&blob);
730 r.in.buffer = &blob;
731 r.in.offered = needed;
733 status = dcerpc_spoolss_EnumPrintProcDataTypes(p, ctx, &r);
734 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EnumPrintProcDataTypes failed");
736 torture_assert_werr_ok(tctx, r.out.result, "EnumPrintProcDataTypes failed");
738 CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumPrintProcDataTypes, info, r.in.level, count, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
742 return true;
746 static bool test_EnumPrinters(struct torture_context *tctx,
747 struct dcerpc_pipe *p,
748 struct test_spoolss_context *ctx)
750 struct spoolss_EnumPrinters r;
751 NTSTATUS status;
752 uint16_t levels[] = { 0, 1, 2, 4, 5 };
753 int i, j;
755 for (i=0;i<ARRAY_SIZE(levels);i++) {
756 int level = levels[i];
757 DATA_BLOB blob;
758 uint32_t needed;
759 uint32_t count;
760 union spoolss_PrinterInfo *info;
762 r.in.flags = PRINTER_ENUM_LOCAL;
763 r.in.server = "";
764 r.in.level = level;
765 r.in.buffer = NULL;
766 r.in.offered = 0;
767 r.out.needed = &needed;
768 r.out.count = &count;
769 r.out.info = &info;
771 torture_comment(tctx, "Testing EnumPrinters level %u\n", r.in.level);
773 status = dcerpc_spoolss_EnumPrinters(p, ctx, &r);
774 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EnumPrinters failed");
775 if (W_ERROR_IS_OK(r.out.result)) {
776 /* TODO: do some more checks here */
777 continue;
779 torture_assert_werr_equal(tctx, r.out.result, WERR_INSUFFICIENT_BUFFER,
780 "EnumPrinters unexpected return code");
782 blob = data_blob_talloc(ctx, NULL, needed);
783 data_blob_clear(&blob);
784 r.in.buffer = &blob;
785 r.in.offered = needed;
787 status = dcerpc_spoolss_EnumPrinters(p, ctx, &r);
788 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EnumPrinters failed");
790 torture_assert_werr_ok(tctx, r.out.result, "EnumPrinters failed");
792 CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumPrinters, info, r.in.level, count, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
794 ctx->printer_count[level] = count;
795 ctx->printers[level] = info;
798 for (i=1;i<ARRAY_SIZE(levels);i++) {
799 int level = levels[i];
800 int old_level = levels[i-1];
801 torture_assert_int_equal(tctx, ctx->printer_count[level], ctx->printer_count[old_level],
802 "EnumPrinters invalid value");
805 for (i=0;i<ARRAY_SIZE(levels);i++) {
806 int level = levels[i];
807 for (j=0;j<ctx->printer_count[level];j++) {
808 union spoolss_PrinterInfo *cur = &ctx->printers[level][j];
809 union spoolss_PrinterInfo *ref = &ctx->printers[2][j];
810 switch (level) {
811 case 0:
812 COMPARE_STRING(tctx, cur->info0, ref->info2, printername);
813 COMPARE_STRING(tctx, cur->info0, ref->info2, servername);
814 COMPARE_UINT32(tctx, cur->info0, ref->info2, cjobs);
815 /*COMPARE_UINT32(tctx, cur->info0, ref->info2, total_jobs);
816 COMPARE_UINT32(tctx, cur->info0, ref->info2, total_bytes);
817 COMPARE_SPOOLSS_TIME(cur->info0, ref->info2, spoolss_Time time);
818 COMPARE_UINT32(tctx, cur->info0, ref->info2, global_counter);
819 COMPARE_UINT32(tctx, cur->info0, ref->info2, total_pages);
820 COMPARE_UINT32(tctx, cur->info0, ref->info2, version);
821 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown10);
822 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown11);
823 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown12);
824 COMPARE_UINT32(tctx, cur->info0, ref->info2, session_counter);
825 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown14);
826 COMPARE_UINT32(tctx, cur->info0, ref->info2, printer_errors);
827 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown16);
828 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown17);
829 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown18);
830 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown19);
831 COMPARE_UINT32(tctx, cur->info0, ref->info2, change_id);
832 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown21);*/
833 COMPARE_UINT32(tctx, cur->info0, ref->info2, status);
834 /*COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown23);
835 COMPARE_UINT32(tctx, cur->info0, ref->info2, c_setprinter);
836 COMPARE_UINT16(cur->info0, ref->info2, unknown25);
837 COMPARE_UINT16(cur->info0, ref->info2, unknown26);
838 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown27);
839 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown28);
840 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown29);*/
841 break;
842 case 1:
843 /*COMPARE_UINT32(tctx, cur->info1, ref->info2, flags);*/
844 /*COMPARE_STRING(tctx, cur->info1, ref->info2, name);*/
845 /*COMPARE_STRING(tctx, cur->info1, ref->info2, description);*/
846 COMPARE_STRING(tctx, cur->info1, ref->info2, comment);
847 break;
848 case 2:
849 /* level 2 is our reference, and it makes no sense to compare it to itself */
850 break;
851 case 4:
852 COMPARE_STRING(tctx, cur->info4, ref->info2, printername);
853 COMPARE_STRING(tctx, cur->info4, ref->info2, servername);
854 COMPARE_UINT32(tctx, cur->info4, ref->info2, attributes);
855 break;
856 case 5:
857 COMPARE_STRING(tctx, cur->info5, ref->info2, printername);
858 COMPARE_STRING(tctx, cur->info5, ref->info2, portname);
859 COMPARE_UINT32(tctx, cur->info5, ref->info2, attributes);
860 /*COMPARE_UINT32(tctx, cur->info5, ref->info2, device_not_selected_timeout);
861 COMPARE_UINT32(tctx, cur->info5, ref->info2, transmission_retry_timeout);*/
862 break;
867 /* TODO:
868 * - verify that the port of a printer was in the list returned by EnumPorts
871 return true;
874 static bool test_GetPrinterDriver2(struct torture_context *tctx,
875 struct dcerpc_pipe *p,
876 struct policy_handle *handle,
877 const char *driver_name,
878 const char *environment);
880 bool test_GetPrinter_level(struct torture_context *tctx,
881 struct dcerpc_pipe *p,
882 struct policy_handle *handle,
883 uint32_t level,
884 union spoolss_PrinterInfo *info)
886 struct spoolss_GetPrinter r;
887 uint32_t needed;
889 r.in.handle = handle;
890 r.in.level = level;
891 r.in.buffer = NULL;
892 r.in.offered = 0;
893 r.out.needed = &needed;
895 torture_comment(tctx, "Testing GetPrinter level %u\n", r.in.level);
897 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_GetPrinter(p, tctx, &r),
898 "GetPrinter failed");
900 if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
901 DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed);
902 data_blob_clear(&blob);
903 r.in.buffer = &blob;
904 r.in.offered = needed;
906 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_GetPrinter(p, tctx, &r),
907 "GetPrinter failed");
910 torture_assert_werr_ok(tctx, r.out.result, "GetPrinter failed");
912 CHECK_NEEDED_SIZE_LEVEL(spoolss_PrinterInfo, r.out.info, r.in.level, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
914 if (info && r.out.info) {
915 *info = *r.out.info;
918 return true;
922 static bool test_GetPrinter(struct torture_context *tctx,
923 struct dcerpc_pipe *p,
924 struct policy_handle *handle,
925 const char *environment)
927 uint32_t levels[] = {0, 1, 2, 3, 4, 5, 6, 7, 8};
928 int i;
930 for (i=0;i<ARRAY_SIZE(levels);i++) {
932 union spoolss_PrinterInfo info;
934 ZERO_STRUCT(info);
936 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, levels[i], &info),
937 "failed to call GetPrinter");
939 if ((levels[i] == 2) && info.info2.drivername && strlen(info.info2.drivername)) {
940 torture_assert(tctx,
941 test_GetPrinterDriver2(tctx, p, handle, info.info2.drivername, environment),
942 "failed to call test_GetPrinterDriver2");
946 return true;
949 static bool test_SetPrinter(struct torture_context *tctx,
950 struct dcerpc_pipe *p,
951 struct policy_handle *handle,
952 struct spoolss_SetPrinterInfoCtr *info_ctr,
953 struct spoolss_DevmodeContainer *devmode_ctr,
954 struct sec_desc_buf *secdesc_ctr,
955 enum spoolss_PrinterControl command)
957 struct spoolss_SetPrinter r;
959 r.in.handle = handle;
960 r.in.info_ctr = info_ctr;
961 r.in.devmode_ctr = devmode_ctr;
962 r.in.secdesc_ctr = secdesc_ctr;
963 r.in.command = command;
965 torture_comment(tctx, "Testing SetPrinter level %d\n", r.in.info_ctr->level);
967 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_SetPrinter(p, tctx, &r),
968 "failed to call SetPrinter");
969 torture_assert_werr_ok(tctx, r.out.result,
970 "failed to call SetPrinter");
972 return true;
975 static bool test_SetPrinter_errors(struct torture_context *tctx,
976 struct dcerpc_pipe *p,
977 struct policy_handle *handle)
979 struct spoolss_SetPrinter r;
980 uint16_t levels[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
981 int i;
983 struct spoolss_SetPrinterInfoCtr info_ctr;
984 struct spoolss_DevmodeContainer devmode_ctr;
985 struct sec_desc_buf secdesc_ctr;
987 info_ctr.level = 0;
988 info_ctr.info.info0 = NULL;
990 ZERO_STRUCT(devmode_ctr);
991 ZERO_STRUCT(secdesc_ctr);
993 r.in.handle = handle;
994 r.in.info_ctr = &info_ctr;
995 r.in.devmode_ctr = &devmode_ctr;
996 r.in.secdesc_ctr = &secdesc_ctr;
997 r.in.command = 0;
999 torture_comment(tctx, "Testing SetPrinter all zero\n");
1001 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_SetPrinter(p, tctx, &r),
1002 "failed to call SetPrinter");
1003 torture_assert_werr_equal(tctx, r.out.result, WERR_INVALID_PARAM,
1004 "failed to call SetPrinter");
1006 again:
1007 for (i=0; i < ARRAY_SIZE(levels); i++) {
1009 struct spoolss_SetPrinterInfo0 info0;
1010 struct spoolss_SetPrinterInfo1 info1;
1011 struct spoolss_SetPrinterInfo2 info2;
1012 struct spoolss_SetPrinterInfo3 info3;
1013 struct spoolss_SetPrinterInfo4 info4;
1014 struct spoolss_SetPrinterInfo5 info5;
1015 struct spoolss_SetPrinterInfo6 info6;
1016 struct spoolss_SetPrinterInfo7 info7;
1017 struct spoolss_SetPrinterInfo8 info8;
1018 struct spoolss_SetPrinterInfo9 info9;
1021 info_ctr.level = levels[i];
1022 switch (levels[i]) {
1023 case 0:
1024 ZERO_STRUCT(info0);
1025 info_ctr.info.info0 = &info0;
1026 break;
1027 case 1:
1028 ZERO_STRUCT(info1);
1029 info_ctr.info.info1 = &info1;
1030 break;
1031 case 2:
1032 ZERO_STRUCT(info2);
1033 info_ctr.info.info2 = &info2;
1034 break;
1035 case 3:
1036 ZERO_STRUCT(info3);
1037 info_ctr.info.info3 = &info3;
1038 break;
1039 case 4:
1040 ZERO_STRUCT(info4);
1041 info_ctr.info.info4 = &info4;
1042 break;
1043 case 5:
1044 ZERO_STRUCT(info5);
1045 info_ctr.info.info5 = &info5;
1046 break;
1047 case 6:
1048 ZERO_STRUCT(info6);
1049 info_ctr.info.info6 = &info6;
1050 break;
1051 case 7:
1052 ZERO_STRUCT(info7);
1053 info_ctr.info.info7 = &info7;
1054 break;
1055 case 8:
1056 ZERO_STRUCT(info8);
1057 info_ctr.info.info8 = &info8;
1058 break;
1059 case 9:
1060 ZERO_STRUCT(info9);
1061 info_ctr.info.info9 = &info9;
1062 break;
1065 torture_comment(tctx, "Testing SetPrinter level %d, command %d\n",
1066 info_ctr.level, r.in.command);
1068 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_SetPrinter(p, tctx, &r),
1069 "failed to call SetPrinter");
1071 switch (r.in.command) {
1072 case SPOOLSS_PRINTER_CONTROL_UNPAUSE: /* 0 */
1073 /* is ignored for all levels other then 0 */
1074 if (info_ctr.level > 0) {
1075 /* ignored then */
1076 break;
1078 case SPOOLSS_PRINTER_CONTROL_PAUSE: /* 1 */
1079 case SPOOLSS_PRINTER_CONTROL_RESUME: /* 2 */
1080 case SPOOLSS_PRINTER_CONTROL_PURGE: /* 3 */
1081 if (info_ctr.level > 0) {
1082 /* is invalid for all levels other then 0 */
1083 torture_assert_werr_equal(tctx, r.out.result, WERR_INVALID_PRINTER_COMMAND,
1084 "unexpected error code returned");
1085 continue;
1086 } else {
1087 torture_assert_werr_ok(tctx, r.out.result,
1088 "failed to call SetPrinter with non 0 command");
1089 continue;
1091 break;
1093 case SPOOLSS_PRINTER_CONTROL_SET_STATUS: /* 4 */
1094 /* FIXME: gd needs further investigation */
1095 default:
1096 torture_assert_werr_equal(tctx, r.out.result, WERR_INVALID_PRINTER_COMMAND,
1097 "unexpected error code returned");
1098 continue;
1101 switch (info_ctr.level) {
1102 case 1:
1103 torture_assert_werr_equal(tctx, r.out.result, WERR_UNKNOWN_LEVEL,
1104 "unexpected error code returned");
1105 break;
1106 case 2:
1107 torture_assert_werr_equal(tctx, r.out.result, WERR_UNKNOWN_PRINTER_DRIVER,
1108 "unexpected error code returned");
1109 break;
1110 case 3:
1111 case 4:
1112 case 5:
1113 case 7:
1114 torture_assert_werr_equal(tctx, r.out.result, WERR_INVALID_PARAM,
1115 "unexpected error code returned");
1116 break;
1117 case 9:
1118 torture_assert_werr_equal(tctx, r.out.result, WERR_NOT_SUPPORTED,
1119 "unexpected error code returned");
1120 break;
1121 default:
1122 torture_assert_werr_ok(tctx, r.out.result,
1123 "failed to call SetPrinter");
1124 break;
1128 if (r.in.command < 5) {
1129 r.in.command++;
1130 goto again;
1133 return true;
1136 static void clear_info2(struct spoolss_SetPrinterInfoCtr *r)
1138 if ((r->level == 2) && (r->info.info2)) {
1139 r->info.info2->secdesc_ptr = 0;
1140 r->info.info2->devmode_ptr = 0;
1144 static bool test_PrinterInfo(struct torture_context *tctx,
1145 struct dcerpc_pipe *p,
1146 struct policy_handle *handle)
1148 NTSTATUS status;
1149 struct spoolss_SetPrinter s;
1150 struct spoolss_GetPrinter q;
1151 struct spoolss_GetPrinter q0;
1152 struct spoolss_SetPrinterInfoCtr info_ctr;
1153 union spoolss_PrinterInfo info;
1154 struct spoolss_DevmodeContainer devmode_ctr;
1155 struct sec_desc_buf secdesc_ctr;
1156 uint32_t needed;
1157 bool ret = true;
1158 int i;
1160 uint32_t status_list[] = {
1161 /* these do not stick
1162 PRINTER_STATUS_PAUSED,
1163 PRINTER_STATUS_ERROR,
1164 PRINTER_STATUS_PENDING_DELETION, */
1165 PRINTER_STATUS_PAPER_JAM,
1166 PRINTER_STATUS_PAPER_OUT,
1167 PRINTER_STATUS_MANUAL_FEED,
1168 PRINTER_STATUS_PAPER_PROBLEM,
1169 PRINTER_STATUS_OFFLINE,
1170 PRINTER_STATUS_IO_ACTIVE,
1171 PRINTER_STATUS_BUSY,
1172 PRINTER_STATUS_PRINTING,
1173 PRINTER_STATUS_OUTPUT_BIN_FULL,
1174 PRINTER_STATUS_NOT_AVAILABLE,
1175 PRINTER_STATUS_WAITING,
1176 PRINTER_STATUS_PROCESSING,
1177 PRINTER_STATUS_INITIALIZING,
1178 PRINTER_STATUS_WARMING_UP,
1179 PRINTER_STATUS_TONER_LOW,
1180 PRINTER_STATUS_NO_TONER,
1181 PRINTER_STATUS_PAGE_PUNT,
1182 PRINTER_STATUS_USER_INTERVENTION,
1183 PRINTER_STATUS_OUT_OF_MEMORY,
1184 PRINTER_STATUS_DOOR_OPEN,
1185 PRINTER_STATUS_SERVER_UNKNOWN,
1186 PRINTER_STATUS_POWER_SAVE,
1187 /* these do not stick
1188 0x02000000,
1189 0x04000000,
1190 0x08000000,
1191 0x10000000,
1192 0x20000000,
1193 0x40000000,
1194 0x80000000 */
1196 uint32_t default_attribute = PRINTER_ATTRIBUTE_LOCAL;
1197 uint32_t attribute_list[] = {
1198 PRINTER_ATTRIBUTE_QUEUED,
1199 /* fails with WERR_INVALID_DATATYPE:
1200 PRINTER_ATTRIBUTE_DIRECT, */
1201 /* does not stick
1202 PRINTER_ATTRIBUTE_DEFAULT, */
1203 PRINTER_ATTRIBUTE_SHARED,
1204 /* does not stick
1205 PRINTER_ATTRIBUTE_NETWORK, */
1206 PRINTER_ATTRIBUTE_HIDDEN,
1207 PRINTER_ATTRIBUTE_LOCAL,
1208 PRINTER_ATTRIBUTE_ENABLE_DEVQ,
1209 PRINTER_ATTRIBUTE_KEEPPRINTEDJOBS,
1210 PRINTER_ATTRIBUTE_DO_COMPLETE_FIRST,
1211 PRINTER_ATTRIBUTE_WORK_OFFLINE,
1212 /* does not stick
1213 PRINTER_ATTRIBUTE_ENABLE_BIDI, */
1214 /* fails with WERR_INVALID_DATATYPE:
1215 PRINTER_ATTRIBUTE_RAW_ONLY, */
1216 /* these do not stick
1217 PRINTER_ATTRIBUTE_PUBLISHED,
1218 PRINTER_ATTRIBUTE_FAX,
1219 PRINTER_ATTRIBUTE_TS,
1220 0x00010000,
1221 0x00020000,
1222 0x00040000,
1223 0x00080000,
1224 0x00100000,
1225 0x00200000,
1226 0x00400000,
1227 0x00800000,
1228 0x01000000,
1229 0x02000000,
1230 0x04000000,
1231 0x08000000,
1232 0x10000000,
1233 0x20000000,
1234 0x40000000,
1235 0x80000000 */
1238 ZERO_STRUCT(devmode_ctr);
1239 ZERO_STRUCT(secdesc_ctr);
1241 s.in.handle = handle;
1242 s.in.command = 0;
1243 s.in.info_ctr = &info_ctr;
1244 s.in.devmode_ctr = &devmode_ctr;
1245 s.in.secdesc_ctr = &secdesc_ctr;
1247 q.in.handle = handle;
1248 q.out.info = &info;
1249 q0 = q;
1251 #define TESTGETCALL(call, r) \
1252 r.in.buffer = NULL; \
1253 r.in.offered = 0;\
1254 r.out.needed = &needed; \
1255 status = dcerpc_spoolss_ ##call(p, tctx, &r); \
1256 if (!NT_STATUS_IS_OK(status)) { \
1257 torture_comment(tctx, #call " level %u failed - %s (%s)\n", \
1258 r.in.level, nt_errstr(status), __location__); \
1259 ret = false; \
1260 break; \
1262 if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {\
1263 DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed); \
1264 data_blob_clear(&blob); \
1265 r.in.buffer = &blob; \
1266 r.in.offered = needed; \
1268 status = dcerpc_spoolss_ ##call(p, tctx, &r); \
1269 if (!NT_STATUS_IS_OK(status)) { \
1270 torture_comment(tctx, #call " level %u failed - %s (%s)\n", \
1271 r.in.level, nt_errstr(status), __location__); \
1272 ret = false; \
1273 break; \
1275 if (!W_ERROR_IS_OK(r.out.result)) { \
1276 torture_comment(tctx, #call " level %u failed - %s (%s)\n", \
1277 r.in.level, win_errstr(r.out.result), __location__); \
1278 ret = false; \
1279 break; \
1283 #define TESTSETCALL_EXP(call, r, err) \
1284 clear_info2(&info_ctr);\
1285 status = dcerpc_spoolss_ ##call(p, tctx, &r); \
1286 if (!NT_STATUS_IS_OK(status)) { \
1287 torture_comment(tctx, #call " level %u failed - %s (%s)\n", \
1288 r.in.info_ctr->level, nt_errstr(status), __location__); \
1289 ret = false; \
1290 break; \
1292 if (!W_ERROR_IS_OK(err)) { \
1293 if (!W_ERROR_EQUAL(err, r.out.result)) { \
1294 torture_comment(tctx, #call " level %u failed - %s, expected %s (%s)\n", \
1295 r.in.info_ctr->level, win_errstr(r.out.result), win_errstr(err), __location__); \
1296 ret = false; \
1298 break; \
1300 if (!W_ERROR_IS_OK(r.out.result)) { \
1301 torture_comment(tctx, #call " level %u failed - %s (%s)\n", \
1302 r.in.info_ctr->level, win_errstr(r.out.result), __location__); \
1303 ret = false; \
1304 break; \
1307 #define TESTSETCALL(call, r) \
1308 TESTSETCALL_EXP(call, r, WERR_OK)
1310 #define STRING_EQUAL(s1, s2, field) \
1311 if ((s1 && !s2) || (s2 && !s1) || strcmp(s1, s2)) { \
1312 torture_comment(tctx, "Failed to set %s to '%s' (%s)\n", \
1313 #field, s2, __location__); \
1314 ret = false; \
1315 break; \
1318 #define MEM_EQUAL(s1, s2, length, field) \
1319 if ((s1 && !s2) || (s2 && !s1) || memcmp(s1, s2, length)) { \
1320 torture_comment(tctx, "Failed to set %s to '%s' (%s)\n", \
1321 #field, (const char *)s2, __location__); \
1322 ret = false; \
1323 break; \
1326 #define INT_EQUAL(i1, i2, field) \
1327 if (i1 != i2) { \
1328 torture_comment(tctx, "Failed to set %s to 0x%llx - got 0x%llx (%s)\n", \
1329 #field, (unsigned long long)i2, (unsigned long long)i1, __location__); \
1330 ret = false; \
1331 break; \
1334 #define SD_EQUAL(sd1, sd2, field) \
1335 if (!security_descriptor_equal(sd1, sd2)) { \
1336 torture_comment(tctx, "Failed to set %s (%s)\n", \
1337 #field, __location__); \
1338 ret = false; \
1339 break; \
1342 #define TEST_PRINTERINFO_STRING_EXP_ERR(lvl1, field1, lvl2, field2, value, err) do { \
1343 torture_comment(tctx, "field test %d/%s vs %d/%s\n", lvl1, #field1, lvl2, #field2); \
1344 q.in.level = lvl1; \
1345 TESTGETCALL(GetPrinter, q) \
1346 info_ctr.level = lvl1; \
1347 info_ctr.info.info ## lvl1 = (struct spoolss_SetPrinterInfo ## lvl1 *)&q.out.info->info ## lvl1; \
1348 info_ctr.info.info ## lvl1->field1 = value;\
1349 TESTSETCALL_EXP(SetPrinter, s, err) \
1350 info_ctr.info.info ## lvl1->field1 = ""; \
1351 TESTGETCALL(GetPrinter, q) \
1352 info_ctr.info.info ## lvl1->field1 = value; \
1353 STRING_EQUAL(info_ctr.info.info ## lvl1->field1, value, field1); \
1354 q.in.level = lvl2; \
1355 TESTGETCALL(GetPrinter, q) \
1356 info_ctr.info.info ## lvl2 = (struct spoolss_SetPrinterInfo ## lvl2 *)&q.out.info->info ## lvl2; \
1357 STRING_EQUAL(info_ctr.info.info ## lvl2->field2, value, field2); \
1358 } while (0)
1360 #define TEST_PRINTERINFO_STRING(lvl1, field1, lvl2, field2, value) do { \
1361 TEST_PRINTERINFO_STRING_EXP_ERR(lvl1, field1, lvl2, field2, value, WERR_OK); \
1362 } while (0);
1364 #define TEST_PRINTERINFO_INT_EXP(lvl1, field1, lvl2, field2, value, exp_value) do { \
1365 torture_comment(tctx, "field test %d/%s vs %d/%s\n", lvl1, #field1, lvl2, #field2); \
1366 q.in.level = lvl1; \
1367 TESTGETCALL(GetPrinter, q) \
1368 info_ctr.level = lvl1; \
1369 info_ctr.info.info ## lvl1 = (struct spoolss_SetPrinterInfo ## lvl1 *)&q.out.info->info ## lvl1; \
1370 info_ctr.info.info ## lvl1->field1 = value; \
1371 TESTSETCALL(SetPrinter, s) \
1372 info_ctr.info.info ## lvl1->field1 = 0; \
1373 TESTGETCALL(GetPrinter, q) \
1374 info_ctr.info.info ## lvl1 = (struct spoolss_SetPrinterInfo ## lvl1 *)&q.out.info->info ## lvl1; \
1375 INT_EQUAL(info_ctr.info.info ## lvl1->field1, exp_value, field1); \
1376 q.in.level = lvl2; \
1377 TESTGETCALL(GetPrinter, q) \
1378 info_ctr.info.info ## lvl2 = (struct spoolss_SetPrinterInfo ## lvl2 *)&q.out.info->info ## lvl2; \
1379 INT_EQUAL(info_ctr.info.info ## lvl2->field2, exp_value, field1); \
1380 } while (0)
1382 #define TEST_PRINTERINFO_INT(lvl1, field1, lvl2, field2, value) do { \
1383 TEST_PRINTERINFO_INT_EXP(lvl1, field1, lvl2, field2, value, value); \
1384 } while (0)
1386 q0.in.level = 0;
1387 do { TESTGETCALL(GetPrinter, q0) } while (0);
1389 TEST_PRINTERINFO_STRING(2, comment, 1, comment, "xx2-1 comment");
1390 TEST_PRINTERINFO_STRING(2, comment, 2, comment, "xx2-2 comment");
1392 /* level 0 printername does not stick */
1393 /* TEST_PRINTERINFO_STRING(2, printername, 0, printername, "xx2-0 printer"); */
1394 TEST_PRINTERINFO_STRING(2, printername, 1, name, "xx2-1 printer");
1395 TEST_PRINTERINFO_STRING(2, printername, 2, printername, "xx2-2 printer");
1396 TEST_PRINTERINFO_STRING(2, printername, 4, printername, "xx2-4 printer");
1397 TEST_PRINTERINFO_STRING(2, printername, 5, printername, "xx2-5 printer");
1398 /* TEST_PRINTERINFO_STRING(4, printername, 0, printername, "xx4-0 printer"); */
1399 TEST_PRINTERINFO_STRING(4, printername, 1, name, "xx4-1 printer");
1400 TEST_PRINTERINFO_STRING(4, printername, 2, printername, "xx4-2 printer");
1401 TEST_PRINTERINFO_STRING(4, printername, 4, printername, "xx4-4 printer");
1402 TEST_PRINTERINFO_STRING(4, printername, 5, printername, "xx4-5 printer");
1403 /* TEST_PRINTERINFO_STRING(5, printername, 0, printername, "xx5-0 printer"); */
1404 TEST_PRINTERINFO_STRING(5, printername, 1, name, "xx5-1 printer");
1405 TEST_PRINTERINFO_STRING(5, printername, 2, printername, "xx5-2 printer");
1406 TEST_PRINTERINFO_STRING(5, printername, 4, printername, "xx5-4 printer");
1407 TEST_PRINTERINFO_STRING(5, printername, 5, printername, "xx5-5 printer");
1409 /* servername can be set but does not stick
1410 TEST_PRINTERINFO_STRING(2, servername, 0, servername, "xx2-0 servername");
1411 TEST_PRINTERINFO_STRING(2, servername, 2, servername, "xx2-2 servername");
1412 TEST_PRINTERINFO_STRING(2, servername, 4, servername, "xx2-4 servername");
1415 /* passing an invalid port will result in WERR_UNKNOWN_PORT */
1416 TEST_PRINTERINFO_STRING_EXP_ERR(2, portname, 2, portname, "xx2-2 portname", WERR_UNKNOWN_PORT);
1417 TEST_PRINTERINFO_STRING_EXP_ERR(2, portname, 5, portname, "xx2-5 portname", WERR_UNKNOWN_PORT);
1418 TEST_PRINTERINFO_STRING_EXP_ERR(5, portname, 2, portname, "xx5-2 portname", WERR_UNKNOWN_PORT);
1419 TEST_PRINTERINFO_STRING_EXP_ERR(5, portname, 5, portname, "xx5-5 portname", WERR_UNKNOWN_PORT);
1421 TEST_PRINTERINFO_STRING(2, sharename, 2, sharename, "xx2-2 sharename");
1422 /* passing an invalid driver will result in WERR_UNKNOWN_PRINTER_DRIVER */
1423 TEST_PRINTERINFO_STRING_EXP_ERR(2, drivername, 2, drivername, "xx2-2 drivername", WERR_UNKNOWN_PRINTER_DRIVER);
1424 TEST_PRINTERINFO_STRING(2, location, 2, location, "xx2-2 location");
1425 /* passing an invalid sepfile will result in WERR_INVALID_SEPARATOR_FILE */
1426 TEST_PRINTERINFO_STRING_EXP_ERR(2, sepfile, 2, sepfile, "xx2-2 sepfile", WERR_INVALID_SEPARATOR_FILE);
1427 /* passing an invalid printprocessor will result in WERR_UNKNOWN_PRINTPROCESSOR */
1428 TEST_PRINTERINFO_STRING_EXP_ERR(2, printprocessor, 2, printprocessor, "xx2-2 printprocessor", WERR_UNKNOWN_PRINTPROCESSOR);
1429 TEST_PRINTERINFO_STRING(2, datatype, 2, datatype, "xx2-2 datatype");
1430 TEST_PRINTERINFO_STRING(2, parameters, 2, parameters, "xx2-2 parameters");
1432 for (i=0; i < ARRAY_SIZE(attribute_list); i++) {
1433 /* TEST_PRINTERINFO_INT_EXP(2, attributes, 1, flags,
1434 attribute_list[i],
1435 (attribute_list[i] | default_attribute)
1436 ); */
1437 TEST_PRINTERINFO_INT_EXP(2, attributes, 2, attributes,
1438 attribute_list[i],
1439 (attribute_list[i] | default_attribute)
1441 TEST_PRINTERINFO_INT_EXP(2, attributes, 4, attributes,
1442 attribute_list[i],
1443 (attribute_list[i] | default_attribute)
1445 TEST_PRINTERINFO_INT_EXP(2, attributes, 5, attributes,
1446 attribute_list[i],
1447 (attribute_list[i] | default_attribute)
1449 /* TEST_PRINTERINFO_INT_EXP(4, attributes, 1, flags,
1450 attribute_list[i],
1451 (attribute_list[i] | default_attribute)
1452 ); */
1453 TEST_PRINTERINFO_INT_EXP(4, attributes, 2, attributes,
1454 attribute_list[i],
1455 (attribute_list[i] | default_attribute)
1457 TEST_PRINTERINFO_INT_EXP(4, attributes, 4, attributes,
1458 attribute_list[i],
1459 (attribute_list[i] | default_attribute)
1461 TEST_PRINTERINFO_INT_EXP(4, attributes, 5, attributes,
1462 attribute_list[i],
1463 (attribute_list[i] | default_attribute)
1465 /* TEST_PRINTERINFO_INT_EXP(5, attributes, 1, flags,
1466 attribute_list[i],
1467 (attribute_list[i] | default_attribute)
1468 ); */
1469 TEST_PRINTERINFO_INT_EXP(5, attributes, 2, attributes,
1470 attribute_list[i],
1471 (attribute_list[i] | default_attribute)
1473 TEST_PRINTERINFO_INT_EXP(5, attributes, 4, attributes,
1474 attribute_list[i],
1475 (attribute_list[i] | default_attribute)
1477 TEST_PRINTERINFO_INT_EXP(5, attributes, 5, attributes,
1478 attribute_list[i],
1479 (attribute_list[i] | default_attribute)
1483 for (i=0; i < ARRAY_SIZE(status_list); i++) {
1484 /* level 2 sets do not stick
1485 TEST_PRINTERINFO_INT(2, status, 0, status, status_list[i]);
1486 TEST_PRINTERINFO_INT(2, status, 2, status, status_list[i]);
1487 TEST_PRINTERINFO_INT(2, status, 6, status, status_list[i]); */
1488 TEST_PRINTERINFO_INT(6, status, 0, status, status_list[i]);
1489 TEST_PRINTERINFO_INT(6, status, 2, status, status_list[i]);
1490 TEST_PRINTERINFO_INT(6, status, 6, status, status_list[i]);
1493 /* priorities need to be between 0 and 99
1494 passing an invalid priority will result in WERR_INVALID_PRIORITY */
1495 TEST_PRINTERINFO_INT(2, priority, 2, priority, 0);
1496 TEST_PRINTERINFO_INT(2, priority, 2, priority, 1);
1497 TEST_PRINTERINFO_INT(2, priority, 2, priority, 99);
1498 /* TEST_PRINTERINFO_INT(2, priority, 2, priority, 100); */
1499 TEST_PRINTERINFO_INT(2, defaultpriority,2, defaultpriority, 0);
1500 TEST_PRINTERINFO_INT(2, defaultpriority,2, defaultpriority, 1);
1501 TEST_PRINTERINFO_INT(2, defaultpriority,2, defaultpriority, 99);
1502 /* TEST_PRINTERINFO_INT(2, defaultpriority,2, defaultpriority, 100); */
1504 TEST_PRINTERINFO_INT(2, starttime, 2, starttime, __LINE__);
1505 TEST_PRINTERINFO_INT(2, untiltime, 2, untiltime, __LINE__);
1507 /* does not stick
1508 TEST_PRINTERINFO_INT(2, cjobs, 2, cjobs, __LINE__);
1509 TEST_PRINTERINFO_INT(2, averageppm, 2, averageppm, __LINE__); */
1511 /* does not stick
1512 TEST_PRINTERINFO_INT(5, device_not_selected_timeout, 5, device_not_selected_timeout, __LINE__);
1513 TEST_PRINTERINFO_INT(5, transmission_retry_timeout, 5, transmission_retry_timeout, __LINE__); */
1515 /* FIXME: gd also test devmode and secdesc behavior */
1518 /* verify composition of level 1 description field */
1519 const char *description;
1520 const char *tmp;
1522 q0.in.level = 1;
1523 do { TESTGETCALL(GetPrinter, q0) } while (0);
1525 description = talloc_strdup(tctx, q0.out.info->info1.description);
1527 q0.in.level = 2;
1528 do { TESTGETCALL(GetPrinter, q0) } while (0);
1530 tmp = talloc_asprintf(tctx, "%s,%s,%s",
1531 q0.out.info->info2.printername,
1532 q0.out.info->info2.drivername,
1533 q0.out.info->info2.location);
1535 do { STRING_EQUAL(description, tmp, "description")} while (0);
1538 return ret;
1541 #define torture_assert_sid_equal(torture_ctx,got,expected,cmt)\
1542 do { struct dom_sid *__got = (got), *__expected = (expected); \
1543 if (!dom_sid_equal(__got, __expected)) { \
1544 torture_result(torture_ctx, TORTURE_FAIL, \
1545 __location__": "#got" was %s, expected %s: %s", \
1546 dom_sid_string(torture_ctx, __got), dom_sid_string(torture_ctx, __expected), cmt); \
1547 return false; \
1549 } while(0)
1551 static bool test_security_descriptor_equal(struct torture_context *tctx,
1552 const struct security_descriptor *sd1,
1553 const struct security_descriptor *sd2)
1555 if (sd1 == sd2) {
1556 return true;
1559 if (!sd1 || !sd2) {
1560 torture_comment(tctx, "%s\n", __location__);
1561 return false;
1564 torture_assert_int_equal(tctx, sd1->revision, sd2->revision, "revision mismatch");
1565 torture_assert_int_equal(tctx, sd1->type, sd2->type, "type mismatch");
1567 torture_assert_sid_equal(tctx, sd1->owner_sid, sd2->owner_sid, "owner mismatch");
1568 torture_assert_sid_equal(tctx, sd1->group_sid, sd2->group_sid, "group mismatch");
1570 if (!security_acl_equal(sd1->sacl, sd2->sacl)) {
1571 torture_comment(tctx, "%s: sacl mismatch\n", __location__);
1572 NDR_PRINT_DEBUG(security_acl, sd1->sacl);
1573 NDR_PRINT_DEBUG(security_acl, sd2->sacl);
1574 return false;
1576 if (!security_acl_equal(sd1->dacl, sd2->dacl)) {
1577 torture_comment(tctx, "%s: dacl mismatch\n", __location__);
1578 NDR_PRINT_DEBUG(security_acl, sd1->dacl);
1579 NDR_PRINT_DEBUG(security_acl, sd2->dacl);
1580 return false;
1583 return true;
1586 static bool test_sd_set_level(struct torture_context *tctx,
1587 struct dcerpc_pipe *p,
1588 struct policy_handle *handle,
1589 uint32_t level,
1590 struct security_descriptor *sd)
1592 struct spoolss_SetPrinterInfoCtr info_ctr;
1593 struct spoolss_DevmodeContainer devmode_ctr;
1594 struct sec_desc_buf secdesc_ctr;
1596 ZERO_STRUCT(devmode_ctr);
1597 ZERO_STRUCT(secdesc_ctr);
1599 switch (level) {
1600 case 2: {
1601 union spoolss_PrinterInfo info;
1602 struct spoolss_SetPrinterInfo2 info2;
1603 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 2, &info), "");
1605 info2.servername = info.info2.servername;
1606 info2.printername = info.info2.printername;
1607 info2.sharename = info.info2.sharename;
1608 info2.portname = info.info2.portname;
1609 info2.drivername = info.info2.drivername;
1610 info2.comment = info.info2.comment;
1611 info2.location = info.info2.location;
1612 info2.devmode_ptr = 0;
1613 info2.sepfile = info.info2.sepfile;
1614 info2.printprocessor = info.info2.printprocessor;
1615 info2.datatype = info.info2.datatype;
1616 info2.parameters = info.info2.parameters;
1617 info2.secdesc_ptr = 0;
1618 info2.attributes = info.info2.attributes;
1619 info2.priority = info.info2.priority;
1620 info2.defaultpriority = info.info2.defaultpriority;
1621 info2.starttime = info.info2.starttime;
1622 info2.untiltime = info.info2.untiltime;
1623 info2.status = info.info2.status;
1624 info2.cjobs = info.info2.cjobs;
1625 info2.averageppm = info.info2.averageppm;
1627 info_ctr.level = 2;
1628 info_ctr.info.info2 = &info2;
1630 break;
1632 case 3: {
1633 struct spoolss_SetPrinterInfo3 info3;
1635 info3.sec_desc_ptr = 0;
1637 info_ctr.level = 3;
1638 info_ctr.info.info3 = &info3;
1640 break;
1642 default:
1643 return false;
1646 secdesc_ctr.sd = sd;
1648 torture_assert(tctx,
1649 test_SetPrinter(tctx, p, handle, &info_ctr, &devmode_ctr, &secdesc_ctr, 0), "");
1651 return true;
1654 static bool test_PrinterInfo_SDs(struct torture_context *tctx,
1655 struct dcerpc_pipe *p,
1656 struct policy_handle *handle)
1658 union spoolss_PrinterInfo info;
1659 struct security_descriptor *sd1, *sd2;
1660 int i;
1662 /* just compare level 2 and level 3 */
1664 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 2, &info), "");
1666 sd1 = info.info2.secdesc;
1668 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 3, &info), "");
1670 sd2 = info.info3.secdesc;
1672 torture_assert(tctx, test_security_descriptor_equal(tctx, sd1, sd2),
1673 "SD level 2 != SD level 3");
1676 /* query level 2, set level 2, query level 2 */
1678 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 2, &info), "");
1680 sd1 = info.info2.secdesc;
1682 torture_assert(tctx, test_sd_set_level(tctx, p, handle, 2, sd1), "");
1684 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 2, &info), "");
1686 sd2 = info.info2.secdesc;
1687 if (sd1->type & SEC_DESC_DACL_DEFAULTED) {
1688 torture_comment(tctx, "removing SEC_DESC_DACL_DEFAULTED\n");
1689 sd1->type &= ~SEC_DESC_DACL_DEFAULTED;
1692 torture_assert(tctx, test_security_descriptor_equal(tctx, sd1, sd2),
1693 "SD level 2 != SD level 2 after SD has been set via level 2");
1696 /* query level 2, set level 3, query level 2 */
1698 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 2, &info), "");
1700 sd1 = info.info2.secdesc;
1702 torture_assert(tctx, test_sd_set_level(tctx, p, handle, 3, sd1), "");
1704 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 2, &info), "");
1706 sd2 = info.info2.secdesc;
1708 torture_assert(tctx, test_security_descriptor_equal(tctx, sd1, sd2),
1709 "SD level 2 != SD level 2 after SD has been set via level 3");
1711 /* set modified sd level 3, query level 2 */
1713 for (i=0; i < 93; i++) {
1714 struct security_ace a;
1715 const char *sid_string = talloc_asprintf(tctx, "S-1-5-32-9999%i", i);
1716 a.type = SEC_ACE_TYPE_ACCESS_ALLOWED;
1717 a.flags = 0;
1718 a.size = 0; /* autogenerated */
1719 a.access_mask = 0;
1720 a.trustee = *dom_sid_parse_talloc(tctx, sid_string);
1721 torture_assert_ntstatus_ok(tctx, security_descriptor_dacl_add(sd1, &a), "");
1724 torture_assert(tctx, test_sd_set_level(tctx, p, handle, 3, sd1), "");
1726 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 2, &info), "");
1727 sd2 = info.info2.secdesc;
1729 if (sd1->type & SEC_DESC_DACL_DEFAULTED) {
1730 torture_comment(tctx, "removing SEC_DESC_DACL_DEFAULTED\n");
1731 sd1->type &= ~SEC_DESC_DACL_DEFAULTED;
1734 torture_assert(tctx, test_security_descriptor_equal(tctx, sd1, sd2),
1735 "modified SD level 2 != SD level 2 after SD has been set via level 3");
1738 return true;
1742 * wrapper call that saves original sd, runs tests, and restores sd
1745 static bool test_PrinterInfo_SD(struct torture_context *tctx,
1746 struct dcerpc_pipe *p,
1747 struct policy_handle *handle)
1749 union spoolss_PrinterInfo info;
1750 struct security_descriptor *sd;
1751 bool ret = true;
1753 torture_comment(tctx, "\nTesting Printer Security Descriptors\n");
1755 /* save original sd */
1757 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 2, &info),
1758 "failed to get initial security descriptor");
1760 sd = security_descriptor_copy(tctx, info.info2.secdesc);
1762 /* run tests */
1764 ret = test_PrinterInfo_SDs(tctx, p, handle);
1766 /* restore original sd */
1768 torture_assert(tctx, test_sd_set_level(tctx, p, handle, 3, sd),
1769 "failed to restore initial security descriptor");
1771 torture_comment(tctx, "Printer Security Descriptors test %s\n",
1772 ret ? "succeeded" : "failed");
1775 return ret;
1778 static bool test_devmode_set_level(struct torture_context *tctx,
1779 struct dcerpc_pipe *p,
1780 struct policy_handle *handle,
1781 uint32_t level,
1782 struct spoolss_DeviceMode *devmode)
1784 struct spoolss_SetPrinterInfoCtr info_ctr;
1785 struct spoolss_DevmodeContainer devmode_ctr;
1786 struct sec_desc_buf secdesc_ctr;
1788 ZERO_STRUCT(devmode_ctr);
1789 ZERO_STRUCT(secdesc_ctr);
1791 switch (level) {
1792 case 2: {
1793 union spoolss_PrinterInfo info;
1794 struct spoolss_SetPrinterInfo2 info2;
1795 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 2, &info), "");
1797 info2.servername = info.info2.servername;
1798 info2.printername = info.info2.printername;
1799 info2.sharename = info.info2.sharename;
1800 info2.portname = info.info2.portname;
1801 info2.drivername = info.info2.drivername;
1802 info2.comment = info.info2.comment;
1803 info2.location = info.info2.location;
1804 info2.devmode_ptr = 0;
1805 info2.sepfile = info.info2.sepfile;
1806 info2.printprocessor = info.info2.printprocessor;
1807 info2.datatype = info.info2.datatype;
1808 info2.parameters = info.info2.parameters;
1809 info2.secdesc_ptr = 0;
1810 info2.attributes = info.info2.attributes;
1811 info2.priority = info.info2.priority;
1812 info2.defaultpriority = info.info2.defaultpriority;
1813 info2.starttime = info.info2.starttime;
1814 info2.untiltime = info.info2.untiltime;
1815 info2.status = info.info2.status;
1816 info2.cjobs = info.info2.cjobs;
1817 info2.averageppm = info.info2.averageppm;
1819 info_ctr.level = 2;
1820 info_ctr.info.info2 = &info2;
1822 break;
1824 case 8: {
1825 struct spoolss_SetPrinterInfo8 info8;
1827 info8.devmode_ptr = 0;
1829 info_ctr.level = 8;
1830 info_ctr.info.info8 = &info8;
1832 break;
1834 default:
1835 return false;
1838 devmode_ctr.devmode = devmode;
1840 torture_assert(tctx,
1841 test_SetPrinter(tctx, p, handle, &info_ctr, &devmode_ctr, &secdesc_ctr, 0), "");
1843 return true;
1847 static bool test_devicemode_equal(struct torture_context *tctx,
1848 const struct spoolss_DeviceMode *d1,
1849 const struct spoolss_DeviceMode *d2)
1851 if (d1 == d2) {
1852 return true;
1855 if (!d1 || !d2) {
1856 torture_comment(tctx, "%s\n", __location__);
1857 return false;
1859 torture_assert_str_equal(tctx, d1->devicename, d2->devicename, "devicename mismatch");
1860 torture_assert_int_equal(tctx, d1->specversion, d2->specversion, "specversion mismatch");
1861 torture_assert_int_equal(tctx, d1->driverversion, d2->driverversion, "driverversion mismatch");
1862 torture_assert_int_equal(tctx, d1->size, d2->size, "size mismatch");
1863 torture_assert_int_equal(tctx, d1->__driverextra_length, d2->__driverextra_length, "__driverextra_length mismatch");
1864 torture_assert_int_equal(tctx, d1->fields, d2->fields, "fields mismatch");
1865 torture_assert_int_equal(tctx, d1->orientation, d2->orientation, "orientation mismatch");
1866 torture_assert_int_equal(tctx, d1->papersize, d2->papersize, "papersize mismatch");
1867 torture_assert_int_equal(tctx, d1->paperlength, d2->paperlength, "paperlength mismatch");
1868 torture_assert_int_equal(tctx, d1->paperwidth, d2->paperwidth, "paperwidth mismatch");
1869 torture_assert_int_equal(tctx, d1->scale, d2->scale, "scale mismatch");
1870 torture_assert_int_equal(tctx, d1->copies, d2->copies, "copies mismatch");
1871 torture_assert_int_equal(tctx, d1->defaultsource, d2->defaultsource, "defaultsource mismatch");
1872 torture_assert_int_equal(tctx, d1->printquality, d2->printquality, "printquality mismatch");
1873 torture_assert_int_equal(tctx, d1->color, d2->color, "color mismatch");
1874 torture_assert_int_equal(tctx, d1->duplex, d2->duplex, "duplex mismatch");
1875 torture_assert_int_equal(tctx, d1->yresolution, d2->yresolution, "yresolution mismatch");
1876 torture_assert_int_equal(tctx, d1->ttoption, d2->ttoption, "ttoption mismatch");
1877 torture_assert_int_equal(tctx, d1->collate, d2->collate, "collate mismatch");
1878 torture_assert_str_equal(tctx, d1->formname, d2->formname, "formname mismatch");
1879 torture_assert_int_equal(tctx, d1->logpixels, d2->logpixels, "logpixels mismatch");
1880 torture_assert_int_equal(tctx, d1->bitsperpel, d2->bitsperpel, "bitsperpel mismatch");
1881 torture_assert_int_equal(tctx, d1->pelswidth, d2->pelswidth, "pelswidth mismatch");
1882 torture_assert_int_equal(tctx, d1->pelsheight, d2->pelsheight, "pelsheight mismatch");
1883 torture_assert_int_equal(tctx, d1->displayflags, d2->displayflags, "displayflags mismatch");
1884 torture_assert_int_equal(tctx, d1->displayfrequency, d2->displayfrequency, "displayfrequency mismatch");
1885 torture_assert_int_equal(tctx, d1->icmmethod, d2->icmmethod, "icmmethod mismatch");
1886 torture_assert_int_equal(tctx, d1->icmintent, d2->icmintent, "icmintent mismatch");
1887 torture_assert_int_equal(tctx, d1->mediatype, d2->mediatype, "mediatype mismatch");
1888 torture_assert_int_equal(tctx, d1->dithertype, d2->dithertype, "dithertype mismatch");
1889 torture_assert_int_equal(tctx, d1->reserved1, d2->reserved1, "reserved1 mismatch");
1890 torture_assert_int_equal(tctx, d1->reserved2, d2->reserved2, "reserved2 mismatch");
1891 torture_assert_int_equal(tctx, d1->panningwidth, d2->panningwidth, "panningwidth mismatch");
1892 torture_assert_int_equal(tctx, d1->panningheight, d2->panningheight, "panningheight mismatch");
1893 torture_assert_data_blob_equal(tctx, d1->driverextra_data, d2->driverextra_data, "driverextra_data mismatch");
1895 return true;
1898 static bool test_devicemode_full(struct torture_context *tctx,
1899 struct dcerpc_pipe *p,
1900 struct policy_handle *handle)
1902 struct spoolss_SetPrinter s;
1903 struct spoolss_GetPrinter q;
1904 struct spoolss_GetPrinter q0;
1905 struct spoolss_SetPrinterInfoCtr info_ctr;
1906 struct spoolss_SetPrinterInfo8 info8;
1907 union spoolss_PrinterInfo info;
1908 struct spoolss_DevmodeContainer devmode_ctr;
1909 struct sec_desc_buf secdesc_ctr;
1910 uint32_t needed;
1911 bool ret = true;
1912 NTSTATUS status;
1914 #define TEST_DEVMODE_INT_EXP(lvl1, field1, lvl2, field2, value, exp_value) do { \
1915 torture_comment(tctx, "field test %d/%s vs %d/%s\n", lvl1, #field1, lvl2, #field2); \
1916 q.in.level = lvl1; \
1917 TESTGETCALL(GetPrinter, q) \
1918 info_ctr.level = lvl1; \
1919 if (lvl1 == 2) {\
1920 info_ctr.info.info ## lvl1 = (struct spoolss_SetPrinterInfo ## lvl1 *)&q.out.info->info ## lvl1; \
1921 } else if (lvl1 == 8) {\
1922 info_ctr.info.info ## lvl1 = &info8; \
1924 devmode_ctr.devmode = q.out.info->info ## lvl1.devmode; \
1925 devmode_ctr.devmode->field1 = value; \
1926 TESTSETCALL(SetPrinter, s) \
1927 TESTGETCALL(GetPrinter, q) \
1928 INT_EQUAL(q.out.info->info ## lvl1.devmode->field1, exp_value, field1); \
1929 q.in.level = lvl2; \
1930 TESTGETCALL(GetPrinter, q) \
1931 INT_EQUAL(q.out.info->info ## lvl2.devmode->field2, exp_value, field1); \
1932 } while (0)
1934 #define TEST_DEVMODE_INT(lvl1, field1, lvl2, field2, value) do { \
1935 TEST_DEVMODE_INT_EXP(lvl1, field1, lvl2, field2, value, value); \
1936 } while (0)
1938 ZERO_STRUCT(devmode_ctr);
1939 ZERO_STRUCT(secdesc_ctr);
1940 ZERO_STRUCT(info8);
1942 s.in.handle = handle;
1943 s.in.command = 0;
1944 s.in.info_ctr = &info_ctr;
1945 s.in.devmode_ctr = &devmode_ctr;
1946 s.in.secdesc_ctr = &secdesc_ctr;
1948 q.in.handle = handle;
1949 q.out.info = &info;
1950 q0 = q;
1952 #if 0
1953 const char *devicename;/* [charset(UTF16)] */
1954 enum spoolss_DeviceModeSpecVersion specversion;
1955 uint16_t driverversion;
1956 uint16_t size;
1957 uint16_t __driverextra_length;/* [value(r->driverextra_data.length)] */
1958 uint32_t fields;
1959 #endif
1961 TEST_DEVMODE_INT(8, orientation, 8, orientation, __LINE__);
1962 TEST_DEVMODE_INT(8, papersize, 8, papersize, __LINE__);
1963 TEST_DEVMODE_INT(8, paperlength, 8, paperlength, __LINE__);
1964 TEST_DEVMODE_INT(8, paperwidth, 8, paperwidth, __LINE__);
1965 TEST_DEVMODE_INT(8, scale, 8, scale, __LINE__);
1966 TEST_DEVMODE_INT(8, copies, 8, copies, __LINE__);
1967 TEST_DEVMODE_INT(8, defaultsource, 8, defaultsource, __LINE__);
1968 TEST_DEVMODE_INT(8, printquality, 8, printquality, __LINE__);
1969 TEST_DEVMODE_INT(8, color, 8, color, __LINE__);
1970 TEST_DEVMODE_INT(8, duplex, 8, duplex, __LINE__);
1971 TEST_DEVMODE_INT(8, yresolution, 8, yresolution, __LINE__);
1972 TEST_DEVMODE_INT(8, ttoption, 8, ttoption, __LINE__);
1973 TEST_DEVMODE_INT(8, collate, 8, collate, __LINE__);
1974 #if 0
1975 const char *formname;/* [charset(UTF16)] */
1976 #endif
1977 TEST_DEVMODE_INT(8, logpixels, 8, logpixels, __LINE__);
1978 TEST_DEVMODE_INT(8, bitsperpel, 8, bitsperpel, __LINE__);
1979 TEST_DEVMODE_INT(8, pelswidth, 8, pelswidth, __LINE__);
1980 TEST_DEVMODE_INT(8, pelsheight, 8, pelsheight, __LINE__);
1981 TEST_DEVMODE_INT(8, displayflags, 8, displayflags, __LINE__);
1982 TEST_DEVMODE_INT(8, displayfrequency, 8, displayfrequency, __LINE__);
1983 TEST_DEVMODE_INT(8, icmmethod, 8, icmmethod, __LINE__);
1984 TEST_DEVMODE_INT(8, icmintent, 8, icmintent, __LINE__);
1985 TEST_DEVMODE_INT(8, mediatype, 8, mediatype, __LINE__);
1986 TEST_DEVMODE_INT(8, dithertype, 8, dithertype, __LINE__);
1987 TEST_DEVMODE_INT(8, reserved1, 8, reserved1, __LINE__);
1988 TEST_DEVMODE_INT(8, reserved2, 8, reserved2, __LINE__);
1989 TEST_DEVMODE_INT(8, panningwidth, 8, panningwidth, __LINE__);
1990 TEST_DEVMODE_INT(8, panningheight, 8, panningheight, __LINE__);
1992 return ret;
1995 static bool call_OpenPrinterEx(struct torture_context *tctx,
1996 struct dcerpc_pipe *p,
1997 const char *name,
1998 struct spoolss_DeviceMode *devmode,
1999 struct policy_handle *handle);
2001 static bool test_ClosePrinter(struct torture_context *tctx,
2002 struct dcerpc_pipe *p,
2003 struct policy_handle *handle);
2005 static bool test_PrinterInfo_DevModes(struct torture_context *tctx,
2006 struct dcerpc_pipe *p,
2007 struct policy_handle *handle,
2008 const char *name)
2010 union spoolss_PrinterInfo info;
2011 struct spoolss_DeviceMode *devmode;
2012 struct spoolss_DeviceMode *devmode2;
2013 struct policy_handle handle_devmode;
2015 /* simply compare level8 and level2 devmode */
2017 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 8, &info), "");
2019 devmode = info.info8.devmode;
2021 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 2, &info), "");
2023 devmode2 = info.info2.devmode;
2025 torture_assert(tctx, test_devicemode_equal(tctx, devmode, devmode2),
2026 "DM level 8 != DM level 2");
2029 /* set devicemode level 8 and see if it persists */
2031 devmode->copies = 93;
2032 devmode->formname = talloc_strdup(tctx, "Legal");
2034 torture_assert(tctx, test_devmode_set_level(tctx, p, handle, 8, devmode), "");
2036 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 8, &info), "");
2038 devmode2 = info.info8.devmode;
2040 torture_assert(tctx, test_devicemode_equal(tctx, devmode, devmode2),
2041 "modified DM level 8 != DM level 8 after DM has been set via level 8");
2043 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 2, &info), "");
2045 devmode2 = info.info2.devmode;
2047 torture_assert(tctx, test_devicemode_equal(tctx, devmode, devmode2),
2048 "modified DM level 8 != DM level 2");
2051 /* set devicemode level 2 and see if it persists */
2053 devmode->copies = 39;
2054 devmode->formname = talloc_strdup(tctx, "Executive");
2056 torture_assert(tctx, test_devmode_set_level(tctx, p, handle, 2, devmode), "");
2058 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 8, &info), "");
2060 devmode2 = info.info8.devmode;
2062 torture_assert(tctx, test_devicemode_equal(tctx, devmode, devmode2),
2063 "modified DM level 8 != DM level 8 after DM has been set via level 2");
2065 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 2, &info), "");
2067 devmode2 = info.info2.devmode;
2069 torture_assert(tctx, test_devicemode_equal(tctx, devmode, devmode2),
2070 "modified DM level 8 != DM level 2");
2073 /* check every single bit in public part of devicemode */
2075 torture_assert(tctx, test_devicemode_full(tctx, p, handle),
2076 "failed to set every single devicemode component");
2079 /* change formname upon open and see if it persists in getprinter calls */
2081 devmode->formname = talloc_strdup(tctx, "A4");
2082 devmode->copies = 42;
2084 torture_assert(tctx, call_OpenPrinterEx(tctx, p, name, devmode, &handle_devmode),
2085 "failed to open printer handle");
2087 torture_assert(tctx, test_GetPrinter_level(tctx, p, &handle_devmode, 8, &info), "");
2089 devmode2 = info.info8.devmode;
2091 if (strequal(devmode->devicename, devmode2->devicename)) {
2092 torture_comment(tctx, "devicenames are the same\n");
2093 } else {
2094 torture_comment(tctx, "devicename passed in for open: %s\n", devmode->devicename);
2095 torture_comment(tctx, "devicename after level 8 get: %s\n", devmode2->devicename);
2098 if (strequal(devmode->formname, devmode2->formname)) {
2099 torture_warning(tctx, "formname are the same\n");
2100 } else {
2101 torture_comment(tctx, "formname passed in for open: %s\n", devmode->formname);
2102 torture_comment(tctx, "formname after level 8 get: %s\n", devmode2->formname);
2105 if (devmode->copies == devmode2->copies) {
2106 torture_warning(tctx, "copies are the same\n");
2107 } else {
2108 torture_comment(tctx, "copies passed in for open: %d\n", devmode->copies);
2109 torture_comment(tctx, "copies after level 8 get: %d\n", devmode2->copies);
2112 torture_assert(tctx, test_GetPrinter_level(tctx, p, &handle_devmode, 2, &info), "");
2114 devmode2 = info.info2.devmode;
2116 if (strequal(devmode->devicename, devmode2->devicename)) {
2117 torture_comment(tctx, "devicenames are the same\n");
2118 } else {
2119 torture_comment(tctx, "devicename passed in for open: %s\n", devmode->devicename);
2120 torture_comment(tctx, "devicename after level 2 get: %s\n", devmode2->devicename);
2123 if (strequal(devmode->formname, devmode2->formname)) {
2124 torture_warning(tctx, "formname is the same\n");
2125 } else {
2126 torture_comment(tctx, "formname passed in for open: %s\n", devmode->formname);
2127 torture_comment(tctx, "formname after level 2 get: %s\n", devmode2->formname);
2130 if (devmode->copies == devmode2->copies) {
2131 torture_warning(tctx, "copies are the same\n");
2132 } else {
2133 torture_comment(tctx, "copies passed in for open: %d\n", devmode->copies);
2134 torture_comment(tctx, "copies after level 2 get: %d\n", devmode2->copies);
2137 test_ClosePrinter(tctx, p, &handle_devmode);
2139 return true;
2143 * wrapper call that saves original devmode, runs tests, and restores devmode
2146 static bool test_PrinterInfo_DevMode(struct torture_context *tctx,
2147 struct dcerpc_pipe *p,
2148 struct policy_handle *handle,
2149 const char *name)
2151 union spoolss_PrinterInfo info;
2152 struct spoolss_DeviceMode *devmode;
2153 bool ret = true;
2155 torture_comment(tctx, "\nTesting Printer Devicemodes\n");
2157 /* save original devmode */
2159 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 8, &info),
2160 "failed to get initial global devicemode");
2162 devmode = info.info8.devmode;
2164 /* run tests */
2166 ret = test_PrinterInfo_DevModes(tctx, p, handle, name);
2168 /* restore original devmode */
2170 torture_assert(tctx, test_devmode_set_level(tctx, p, handle, 8, devmode),
2171 "failed to restore initial global device mode");
2173 torture_comment(tctx, "Printer Devicemodes test %s\n",
2174 ret ? "succeeded" : "failed");
2177 return ret;
2180 static bool test_ClosePrinter(struct torture_context *tctx,
2181 struct dcerpc_pipe *p,
2182 struct policy_handle *handle)
2184 NTSTATUS status;
2185 struct spoolss_ClosePrinter r;
2187 r.in.handle = handle;
2188 r.out.handle = handle;
2190 torture_comment(tctx, "Testing ClosePrinter\n");
2192 status = dcerpc_spoolss_ClosePrinter(p, tctx, &r);
2193 torture_assert_ntstatus_ok(tctx, status, "ClosePrinter failed");
2194 torture_assert_werr_ok(tctx, r.out.result, "ClosePrinter failed");
2196 return true;
2199 static bool test_GetForm(struct torture_context *tctx,
2200 struct dcerpc_pipe *p,
2201 struct policy_handle *handle,
2202 const char *form_name,
2203 uint32_t level)
2205 NTSTATUS status;
2206 struct spoolss_GetForm r;
2207 uint32_t needed;
2209 r.in.handle = handle;
2210 r.in.form_name = form_name;
2211 r.in.level = level;
2212 r.in.buffer = NULL;
2213 r.in.offered = 0;
2214 r.out.needed = &needed;
2216 torture_comment(tctx, "Testing GetForm level %d\n", r.in.level);
2218 status = dcerpc_spoolss_GetForm(p, tctx, &r);
2219 torture_assert_ntstatus_ok(tctx, status, "GetForm failed");
2221 if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
2222 DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed);
2223 data_blob_clear(&blob);
2224 r.in.buffer = &blob;
2225 r.in.offered = needed;
2226 status = dcerpc_spoolss_GetForm(p, tctx, &r);
2227 torture_assert_ntstatus_ok(tctx, status, "GetForm failed");
2229 torture_assert_werr_ok(tctx, r.out.result, "GetForm failed");
2231 torture_assert(tctx, r.out.info, "No form info returned");
2234 torture_assert_werr_ok(tctx, r.out.result, "GetForm failed");
2236 CHECK_NEEDED_SIZE_LEVEL(spoolss_FormInfo, r.out.info, r.in.level, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
2238 return true;
2241 static bool test_EnumForms(struct torture_context *tctx,
2242 struct dcerpc_pipe *p,
2243 struct policy_handle *handle, bool print_server)
2245 NTSTATUS status;
2246 struct spoolss_EnumForms r;
2247 bool ret = true;
2248 uint32_t needed;
2249 uint32_t count;
2250 uint32_t levels[] = { 1, 2 };
2251 int i;
2253 for (i=0; i<ARRAY_SIZE(levels); i++) {
2255 union spoolss_FormInfo *info;
2257 r.in.handle = handle;
2258 r.in.level = levels[i];
2259 r.in.buffer = NULL;
2260 r.in.offered = 0;
2261 r.out.needed = &needed;
2262 r.out.count = &count;
2263 r.out.info = &info;
2265 torture_comment(tctx, "Testing EnumForms level %d\n", levels[i]);
2267 status = dcerpc_spoolss_EnumForms(p, tctx, &r);
2268 torture_assert_ntstatus_ok(tctx, status, "EnumForms failed");
2270 if ((r.in.level == 2) && (W_ERROR_EQUAL(r.out.result, WERR_UNKNOWN_LEVEL))) {
2271 break;
2274 if (print_server && W_ERROR_EQUAL(r.out.result, WERR_BADFID))
2275 torture_fail(tctx, "EnumForms on the PrintServer isn't supported by test server (NT4)");
2277 if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
2278 int j;
2279 DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed);
2280 data_blob_clear(&blob);
2281 r.in.buffer = &blob;
2282 r.in.offered = needed;
2284 status = dcerpc_spoolss_EnumForms(p, tctx, &r);
2286 torture_assert(tctx, info, "No forms returned");
2288 for (j = 0; j < count; j++) {
2289 if (!print_server)
2290 ret &= test_GetForm(tctx, p, handle, info[j].info1.form_name, levels[i]);
2294 torture_assert_ntstatus_ok(tctx, status, "EnumForms failed");
2296 torture_assert_werr_ok(tctx, r.out.result, "EnumForms failed");
2298 CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumForms, info, r.in.level, count, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
2301 return true;
2304 static bool test_DeleteForm(struct torture_context *tctx,
2305 struct dcerpc_pipe *p,
2306 struct policy_handle *handle,
2307 const char *form_name)
2309 NTSTATUS status;
2310 struct spoolss_DeleteForm r;
2312 r.in.handle = handle;
2313 r.in.form_name = form_name;
2315 status = dcerpc_spoolss_DeleteForm(p, tctx, &r);
2317 torture_assert_ntstatus_ok(tctx, status, "DeleteForm failed");
2319 torture_assert_werr_ok(tctx, r.out.result, "DeleteForm failed");
2321 return true;
2324 static bool test_AddForm(struct torture_context *tctx,
2325 struct dcerpc_pipe *p,
2326 struct policy_handle *handle, bool print_server)
2328 struct spoolss_AddForm r;
2329 struct spoolss_AddFormInfo1 addform;
2330 const char *form_name = "testform3";
2331 NTSTATUS status;
2332 bool ret = true;
2334 r.in.handle = handle;
2335 r.in.level = 1;
2336 r.in.info.info1 = &addform;
2337 addform.flags = SPOOLSS_FORM_USER;
2338 addform.form_name = form_name;
2339 addform.size.width = 50;
2340 addform.size.height = 25;
2341 addform.area.left = 5;
2342 addform.area.top = 10;
2343 addform.area.right = 45;
2344 addform.area.bottom = 15;
2346 status = dcerpc_spoolss_AddForm(p, tctx, &r);
2348 torture_assert_ntstatus_ok(tctx, status, "AddForm failed");
2350 torture_assert_werr_ok(tctx, r.out.result, "AddForm failed");
2352 if (!print_server) ret &= test_GetForm(tctx, p, handle, form_name, 1);
2355 struct spoolss_SetForm sf;
2356 struct spoolss_AddFormInfo1 setform;
2358 sf.in.handle = handle;
2359 sf.in.form_name = form_name;
2360 sf.in.level = 1;
2361 sf.in.info.info1= &setform;
2362 setform.flags = addform.flags;
2363 setform.form_name = addform.form_name;
2364 setform.size = addform.size;
2365 setform.area = addform.area;
2367 setform.size.width = 1234;
2369 status = dcerpc_spoolss_SetForm(p, tctx, &sf);
2371 torture_assert_ntstatus_ok(tctx, status, "SetForm failed");
2373 torture_assert_werr_ok(tctx, r.out.result, "SetForm failed");
2376 if (!print_server) ret &= test_GetForm(tctx, p, handle, form_name, 1);
2379 struct spoolss_EnumForms e;
2380 union spoolss_FormInfo *info;
2381 uint32_t needed;
2382 uint32_t count;
2383 bool found = false;
2385 e.in.handle = handle;
2386 e.in.level = 1;
2387 e.in.buffer = NULL;
2388 e.in.offered = 0;
2389 e.out.needed = &needed;
2390 e.out.count = &count;
2391 e.out.info = &info;
2393 torture_comment(tctx, "Testing EnumForms level 1\n");
2395 status = dcerpc_spoolss_EnumForms(p, tctx, &e);
2396 torture_assert_ntstatus_ok(tctx, status, "EnumForms failed");
2398 if (print_server && W_ERROR_EQUAL(e.out.result, WERR_BADFID))
2399 torture_fail(tctx, "EnumForms on the PrintServer isn't supported by test server (NT4)");
2401 if (W_ERROR_EQUAL(e.out.result, WERR_INSUFFICIENT_BUFFER)) {
2402 int j;
2403 DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed);
2404 data_blob_clear(&blob);
2405 e.in.buffer = &blob;
2406 e.in.offered = needed;
2408 status = dcerpc_spoolss_EnumForms(p, tctx, &e);
2410 torture_assert(tctx, info, "No forms returned");
2412 for (j = 0; j < count; j++) {
2413 if (strequal(form_name, info[j].info1.form_name)) {
2414 found = true;
2415 break;
2419 torture_assert(tctx, found, "Newly added form not found in enum call");
2422 if (!test_DeleteForm(tctx, p, handle, form_name)) {
2423 ret = false;
2426 return ret;
2429 static bool test_EnumPorts_old(struct torture_context *tctx,
2430 struct dcerpc_pipe *p)
2432 NTSTATUS status;
2433 struct spoolss_EnumPorts r;
2434 uint32_t needed;
2435 uint32_t count;
2436 union spoolss_PortInfo *info;
2438 r.in.servername = talloc_asprintf(tctx, "\\\\%s",
2439 dcerpc_server_name(p));
2440 r.in.level = 2;
2441 r.in.buffer = NULL;
2442 r.in.offered = 0;
2443 r.out.needed = &needed;
2444 r.out.count = &count;
2445 r.out.info = &info;
2447 torture_comment(tctx, "Testing EnumPorts\n");
2449 status = dcerpc_spoolss_EnumPorts(p, tctx, &r);
2451 torture_assert_ntstatus_ok(tctx, status, "EnumPorts failed");
2453 if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
2454 DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed);
2455 data_blob_clear(&blob);
2456 r.in.buffer = &blob;
2457 r.in.offered = needed;
2459 status = dcerpc_spoolss_EnumPorts(p, tctx, &r);
2460 torture_assert_ntstatus_ok(tctx, status, "EnumPorts failed");
2461 torture_assert_werr_ok(tctx, r.out.result, "EnumPorts failed");
2463 torture_assert(tctx, info, "No ports returned");
2466 torture_assert_werr_ok(tctx, r.out.result, "EnumPorts failed");
2468 CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumPorts, info, 2, count, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
2470 return true;
2473 static bool test_AddPort(struct torture_context *tctx,
2474 struct dcerpc_pipe *p)
2476 NTSTATUS status;
2477 struct spoolss_AddPort r;
2479 r.in.server_name = talloc_asprintf(tctx, "\\\\%s",
2480 dcerpc_server_name(p));
2481 r.in.unknown = 0;
2482 r.in.monitor_name = "foo";
2484 torture_comment(tctx, "Testing AddPort\n");
2486 status = dcerpc_spoolss_AddPort(p, tctx, &r);
2488 torture_assert_ntstatus_ok(tctx, status, "AddPort failed");
2490 /* win2k3 returns WERR_NOT_SUPPORTED */
2492 #if 0
2494 if (!W_ERROR_IS_OK(r.out.result)) {
2495 printf("AddPort failed - %s\n", win_errstr(r.out.result));
2496 return false;
2499 #endif
2501 return true;
2504 static bool test_GetJob(struct torture_context *tctx,
2505 struct dcerpc_pipe *p,
2506 struct policy_handle *handle, uint32_t job_id)
2508 NTSTATUS status;
2509 struct spoolss_GetJob r;
2510 union spoolss_JobInfo info;
2511 uint32_t needed;
2512 uint32_t levels[] = {1, 2 /* 3, 4 */};
2513 uint32_t i;
2515 r.in.handle = handle;
2516 r.in.job_id = job_id;
2517 r.in.level = 0;
2518 r.in.buffer = NULL;
2519 r.in.offered = 0;
2520 r.out.needed = &needed;
2521 r.out.info = &info;
2523 torture_comment(tctx, "Testing GetJob level %d\n", r.in.level);
2525 status = dcerpc_spoolss_GetJob(p, tctx, &r);
2526 torture_assert_werr_equal(tctx, r.out.result, WERR_UNKNOWN_LEVEL, "Unexpected return code");
2528 for (i = 0; i < ARRAY_SIZE(levels); i++) {
2530 torture_comment(tctx, "Testing GetJob level %d\n", r.in.level);
2532 needed = 0;
2534 r.in.level = levels[i];
2535 r.in.offered = 0;
2536 r.in.buffer = NULL;
2538 status = dcerpc_spoolss_GetJob(p, tctx, &r);
2539 torture_assert_ntstatus_ok(tctx, status, "GetJob failed");
2541 if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
2542 DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed);
2543 data_blob_clear(&blob);
2544 r.in.buffer = &blob;
2545 r.in.offered = needed;
2547 status = dcerpc_spoolss_GetJob(p, tctx, &r);
2548 torture_assert_ntstatus_ok(tctx, status, "GetJob failed");
2551 torture_assert(tctx, r.out.info, "No job info returned");
2552 torture_assert_werr_ok(tctx, r.out.result, "GetJob failed");
2554 CHECK_NEEDED_SIZE_LEVEL(spoolss_JobInfo, r.out.info, r.in.level, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
2557 return true;
2560 static bool test_SetJob(struct torture_context *tctx,
2561 struct dcerpc_pipe *p,
2562 struct policy_handle *handle, uint32_t job_id,
2563 enum spoolss_JobControl command)
2565 NTSTATUS status;
2566 struct spoolss_SetJob r;
2568 r.in.handle = handle;
2569 r.in.job_id = job_id;
2570 r.in.ctr = NULL;
2571 r.in.command = command;
2573 switch (command) {
2574 case SPOOLSS_JOB_CONTROL_PAUSE:
2575 torture_comment(tctx, "Testing SetJob: SPOOLSS_JOB_CONTROL_PAUSE\n");
2576 break;
2577 case SPOOLSS_JOB_CONTROL_RESUME:
2578 torture_comment(tctx, "Testing SetJob: SPOOLSS_JOB_CONTROL_RESUME\n");
2579 break;
2580 case SPOOLSS_JOB_CONTROL_CANCEL:
2581 torture_comment(tctx, "Testing SetJob: SPOOLSS_JOB_CONTROL_CANCEL\n");
2582 break;
2583 case SPOOLSS_JOB_CONTROL_RESTART:
2584 torture_comment(tctx, "Testing SetJob: SPOOLSS_JOB_CONTROL_RESTART\n");
2585 break;
2586 case SPOOLSS_JOB_CONTROL_DELETE:
2587 torture_comment(tctx, "Testing SetJob: SPOOLSS_JOB_CONTROL_DELETE\n");
2588 break;
2589 case SPOOLSS_JOB_CONTROL_SEND_TO_PRINTER:
2590 torture_comment(tctx, "Testing SetJob: SPOOLSS_JOB_CONTROL_SEND_TO_PRINTER\n");
2591 break;
2592 case SPOOLSS_JOB_CONTROL_LAST_PAGE_EJECTED:
2593 torture_comment(tctx, "Testing SetJob: SPOOLSS_JOB_CONTROL_LAST_PAGE_EJECTED\n");
2594 break;
2595 case SPOOLSS_JOB_CONTROL_RETAIN:
2596 torture_comment(tctx, "Testing SetJob: SPOOLSS_JOB_CONTROL_RETAIN\n");
2597 break;
2598 case SPOOLSS_JOB_CONTROL_RELEASE:
2599 torture_comment(tctx, "Testing SetJob: SPOOLSS_JOB_CONTROL_RELEASE\n");
2600 break;
2601 default:
2602 torture_comment(tctx, "Testing SetJob\n");
2603 break;
2606 status = dcerpc_spoolss_SetJob(p, tctx, &r);
2607 torture_assert_ntstatus_ok(tctx, status, "SetJob failed");
2608 torture_assert_werr_ok(tctx, r.out.result, "SetJob failed");
2610 return true;
2613 static bool test_AddJob(struct torture_context *tctx,
2614 struct dcerpc_pipe *p,
2615 struct policy_handle *handle)
2617 NTSTATUS status;
2618 struct spoolss_AddJob r;
2619 uint32_t needed;
2621 r.in.level = 0;
2622 r.in.handle = handle;
2623 r.in.offered = 0;
2624 r.out.needed = &needed;
2625 r.in.buffer = r.out.buffer = NULL;
2627 torture_comment(tctx, "Testing AddJob\n");
2629 status = dcerpc_spoolss_AddJob(p, tctx, &r);
2630 torture_assert_werr_equal(tctx, r.out.result, WERR_UNKNOWN_LEVEL, "AddJob failed");
2632 r.in.level = 1;
2634 status = dcerpc_spoolss_AddJob(p, tctx, &r);
2635 torture_assert_werr_equal(tctx, r.out.result, WERR_INVALID_PARAM, "AddJob failed");
2637 return true;
2641 static bool test_EnumJobs(struct torture_context *tctx,
2642 struct dcerpc_pipe *p,
2643 struct policy_handle *handle)
2645 NTSTATUS status;
2646 struct spoolss_EnumJobs r;
2647 uint32_t needed;
2648 uint32_t count;
2649 union spoolss_JobInfo *info;
2651 r.in.handle = handle;
2652 r.in.firstjob = 0;
2653 r.in.numjobs = 0xffffffff;
2654 r.in.level = 1;
2655 r.in.buffer = NULL;
2656 r.in.offered = 0;
2657 r.out.needed = &needed;
2658 r.out.count = &count;
2659 r.out.info = &info;
2661 torture_comment(tctx, "Testing EnumJobs\n");
2663 status = dcerpc_spoolss_EnumJobs(p, tctx, &r);
2665 torture_assert_ntstatus_ok(tctx, status, "EnumJobs failed");
2667 if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
2668 int j;
2669 DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed);
2670 data_blob_clear(&blob);
2671 r.in.buffer = &blob;
2672 r.in.offered = needed;
2674 status = dcerpc_spoolss_EnumJobs(p, tctx, &r);
2676 torture_assert_ntstatus_ok(tctx, status, "EnumJobs failed");
2677 torture_assert_werr_ok(tctx, r.out.result, "EnumJobs failed");
2678 torture_assert(tctx, info, "No jobs returned");
2680 CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumJobs, *r.out.info, r.in.level, count, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
2682 for (j = 0; j < count; j++) {
2684 torture_assert(tctx, test_GetJob(tctx, p, handle, info[j].info1.job_id),
2685 "failed to call test_GetJob");
2687 /* FIXME - gd */
2688 if (!torture_setting_bool(tctx, "samba3", false)) {
2689 test_SetJob(tctx, p, handle, info[j].info1.job_id, SPOOLSS_JOB_CONTROL_PAUSE);
2690 test_SetJob(tctx, p, handle, info[j].info1.job_id, SPOOLSS_JOB_CONTROL_RESUME);
2694 } else {
2695 torture_assert_werr_ok(tctx, r.out.result, "EnumJobs failed");
2698 return true;
2701 static bool test_DoPrintTest(struct torture_context *tctx,
2702 struct dcerpc_pipe *p,
2703 struct policy_handle *handle)
2705 bool ret = true;
2706 NTSTATUS status;
2707 struct spoolss_StartDocPrinter s;
2708 struct spoolss_DocumentInfo1 info1;
2709 struct spoolss_StartPagePrinter sp;
2710 struct spoolss_WritePrinter w;
2711 struct spoolss_EndPagePrinter ep;
2712 struct spoolss_EndDocPrinter e;
2713 int i;
2714 uint32_t job_id;
2715 uint32_t num_written;
2717 torture_comment(tctx, "Testing StartDocPrinter\n");
2719 s.in.handle = handle;
2720 s.in.level = 1;
2721 s.in.info.info1 = &info1;
2722 s.out.job_id = &job_id;
2723 info1.document_name = "TorturePrintJob";
2724 info1.output_file = NULL;
2725 info1.datatype = "RAW";
2727 status = dcerpc_spoolss_StartDocPrinter(p, tctx, &s);
2728 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_StartDocPrinter failed");
2729 torture_assert_werr_ok(tctx, s.out.result, "StartDocPrinter failed");
2731 for (i=1; i < 4; i++) {
2732 torture_comment(tctx, "Testing StartPagePrinter: Page[%d]\n", i);
2734 sp.in.handle = handle;
2736 status = dcerpc_spoolss_StartPagePrinter(p, tctx, &sp);
2737 torture_assert_ntstatus_ok(tctx, status,
2738 "dcerpc_spoolss_StartPagePrinter failed");
2739 torture_assert_werr_ok(tctx, sp.out.result, "StartPagePrinter failed");
2741 torture_comment(tctx, "Testing WritePrinter: Page[%d]\n", i);
2743 w.in.handle = handle;
2744 w.in.data = data_blob_string_const(talloc_asprintf(tctx,"TortureTestPage: %d\nData\n",i));
2745 w.out.num_written = &num_written;
2747 status = dcerpc_spoolss_WritePrinter(p, tctx, &w);
2748 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_WritePrinter failed");
2749 torture_assert_werr_ok(tctx, w.out.result, "WritePrinter failed");
2751 torture_comment(tctx, "Testing EndPagePrinter: Page[%d]\n", i);
2753 ep.in.handle = handle;
2755 status = dcerpc_spoolss_EndPagePrinter(p, tctx, &ep);
2756 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EndPagePrinter failed");
2757 torture_assert_werr_ok(tctx, ep.out.result, "EndPagePrinter failed");
2760 torture_comment(tctx, "Testing EndDocPrinter\n");
2762 e.in.handle = handle;
2764 status = dcerpc_spoolss_EndDocPrinter(p, tctx, &e);
2765 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EndDocPrinter failed");
2766 torture_assert_werr_ok(tctx, e.out.result, "EndDocPrinter failed");
2768 ret &= test_AddJob(tctx, p, handle);
2769 ret &= test_EnumJobs(tctx, p, handle);
2771 ret &= test_SetJob(tctx, p, handle, job_id, SPOOLSS_JOB_CONTROL_DELETE);
2773 return ret;
2776 static bool test_PausePrinter(struct torture_context *tctx,
2777 struct dcerpc_pipe *p,
2778 struct policy_handle *handle)
2780 NTSTATUS status;
2781 struct spoolss_SetPrinter r;
2782 struct spoolss_SetPrinterInfoCtr info_ctr;
2783 struct spoolss_DevmodeContainer devmode_ctr;
2784 struct sec_desc_buf secdesc_ctr;
2786 info_ctr.level = 0;
2787 info_ctr.info.info0 = NULL;
2789 ZERO_STRUCT(devmode_ctr);
2790 ZERO_STRUCT(secdesc_ctr);
2792 r.in.handle = handle;
2793 r.in.info_ctr = &info_ctr;
2794 r.in.devmode_ctr = &devmode_ctr;
2795 r.in.secdesc_ctr = &secdesc_ctr;
2796 r.in.command = SPOOLSS_PRINTER_CONTROL_PAUSE;
2798 torture_comment(tctx, "Testing SetPrinter: SPOOLSS_PRINTER_CONTROL_PAUSE\n");
2800 status = dcerpc_spoolss_SetPrinter(p, tctx, &r);
2802 torture_assert_ntstatus_ok(tctx, status, "SetPrinter failed");
2804 torture_assert_werr_ok(tctx, r.out.result, "SetPrinter failed");
2806 return true;
2809 static bool test_ResumePrinter(struct torture_context *tctx,
2810 struct dcerpc_pipe *p,
2811 struct policy_handle *handle)
2813 NTSTATUS status;
2814 struct spoolss_SetPrinter r;
2815 struct spoolss_SetPrinterInfoCtr info_ctr;
2816 struct spoolss_DevmodeContainer devmode_ctr;
2817 struct sec_desc_buf secdesc_ctr;
2819 info_ctr.level = 0;
2820 info_ctr.info.info0 = NULL;
2822 ZERO_STRUCT(devmode_ctr);
2823 ZERO_STRUCT(secdesc_ctr);
2825 r.in.handle = handle;
2826 r.in.info_ctr = &info_ctr;
2827 r.in.devmode_ctr = &devmode_ctr;
2828 r.in.secdesc_ctr = &secdesc_ctr;
2829 r.in.command = SPOOLSS_PRINTER_CONTROL_RESUME;
2831 torture_comment(tctx, "Testing SetPrinter: SPOOLSS_PRINTER_CONTROL_RESUME\n");
2833 status = dcerpc_spoolss_SetPrinter(p, tctx, &r);
2835 torture_assert_ntstatus_ok(tctx, status, "SetPrinter failed");
2837 torture_assert_werr_ok(tctx, r.out.result, "SetPrinter failed");
2839 return true;
2842 static bool test_GetPrinterData(struct torture_context *tctx,
2843 struct dcerpc_pipe *p,
2844 struct policy_handle *handle,
2845 const char *value_name,
2846 enum winreg_Type *type_p,
2847 union spoolss_PrinterData *data_p)
2849 NTSTATUS status;
2850 struct spoolss_GetPrinterData r;
2851 uint32_t needed;
2852 enum winreg_Type type;
2853 union spoolss_PrinterData data;
2855 r.in.handle = handle;
2856 r.in.value_name = value_name;
2857 r.in.offered = 0;
2858 r.out.needed = &needed;
2859 r.out.type = &type;
2860 r.out.data = &data;
2862 torture_comment(tctx, "Testing GetPrinterData(%s)\n", r.in.value_name);
2864 status = dcerpc_spoolss_GetPrinterData(p, tctx, &r);
2865 torture_assert_ntstatus_ok(tctx, status, "GetPrinterData failed");
2867 if (W_ERROR_EQUAL(r.out.result, WERR_MORE_DATA)) {
2868 r.in.offered = needed;
2870 status = dcerpc_spoolss_GetPrinterData(p, tctx, &r);
2871 torture_assert_ntstatus_ok(tctx, status, "GetPrinterData failed");
2874 torture_assert_werr_ok(tctx, r.out.result,
2875 talloc_asprintf(tctx, "GetPrinterData(%s) failed", r.in.value_name));
2877 CHECK_NEEDED_SIZE_LEVEL(spoolss_PrinterData, &data, type, lp_iconv_convenience(tctx->lp_ctx), needed, 1);
2879 if (type_p) {
2880 *type_p = type;
2883 if (data_p) {
2884 *data_p = data;
2887 return true;
2890 static bool test_GetPrinterDataEx(struct torture_context *tctx,
2891 struct dcerpc_pipe *p,
2892 struct policy_handle *handle,
2893 const char *key_name,
2894 const char *value_name,
2895 enum winreg_Type *type_p,
2896 union spoolss_PrinterData *data_p)
2898 NTSTATUS status;
2899 struct spoolss_GetPrinterDataEx r;
2900 enum winreg_Type type;
2901 uint32_t needed;
2902 union spoolss_PrinterData data;
2904 r.in.handle = handle;
2905 r.in.key_name = key_name;
2906 r.in.value_name = value_name;
2907 r.in.offered = 0;
2908 r.out.type = &type;
2909 r.out.needed = &needed;
2910 r.out.data = &data;
2912 torture_comment(tctx, "Testing GetPrinterDataEx(%s - %s)\n",
2913 r.in.key_name, r.in.value_name);
2915 status = dcerpc_spoolss_GetPrinterDataEx(p, tctx, &r);
2916 if (!NT_STATUS_IS_OK(status)) {
2917 if (NT_STATUS_EQUAL(status,NT_STATUS_NET_WRITE_FAULT) &&
2918 p->last_fault_code == DCERPC_FAULT_OP_RNG_ERROR) {
2919 torture_skip(tctx, "GetPrinterDataEx not supported by server\n");
2921 torture_assert_ntstatus_ok(tctx, status, "GetPrinterDataEx failed");
2924 if (W_ERROR_EQUAL(r.out.result, WERR_MORE_DATA)) {
2925 r.in.offered = needed;
2926 status = dcerpc_spoolss_GetPrinterDataEx(p, tctx, &r);
2927 torture_assert_ntstatus_ok(tctx, status, "GetPrinterDataEx failed");
2930 torture_assert_werr_ok(tctx, r.out.result,
2931 talloc_asprintf(tctx, "GetPrinterDataEx(%s - %s) failed", r.in.key_name, r.in.value_name));
2933 CHECK_NEEDED_SIZE_LEVEL(spoolss_PrinterData, &data, type, lp_iconv_convenience(tctx->lp_ctx), needed, 1);
2935 if (type_p) {
2936 *type_p = type;
2939 if (data_p) {
2940 *data_p = data;
2943 return true;
2946 static bool test_GetPrinterData_list(struct torture_context *tctx,
2947 struct dcerpc_pipe *p,
2948 struct policy_handle *handle)
2950 const char *list[] = {
2951 "W3SvcInstalled",
2952 "BeepEnabled",
2953 "EventLog",
2954 /* "NetPopup", not on w2k8 */
2955 /* "NetPopupToComputer", not on w2k8 */
2956 "MajorVersion",
2957 "MinorVersion",
2958 "DefaultSpoolDirectory",
2959 "Architecture",
2960 "DsPresent",
2961 "OSVersion",
2962 /* "OSVersionEx", not on s3 */
2963 "DNSMachineName"
2965 int i;
2967 for (i=0; i < ARRAY_SIZE(list); i++) {
2968 enum winreg_Type type, type_ex;
2969 union spoolss_PrinterData data, data_ex;
2971 torture_assert(tctx, test_GetPrinterData(tctx, p, handle, list[i], &type, &data),
2972 talloc_asprintf(tctx, "GetPrinterData failed on %s\n", list[i]));
2973 torture_assert(tctx, test_GetPrinterDataEx(tctx, p, handle, "random_string", list[i], &type_ex, &data_ex),
2974 talloc_asprintf(tctx, "GetPrinterDataEx failed on %s\n", list[i]));
2975 torture_assert_int_equal(tctx, type, type_ex, "type mismatch");
2976 switch (type) {
2977 case REG_SZ:
2978 torture_assert_str_equal(tctx, data.string, data_ex.string, "REG_SZ mismatch");
2979 break;
2980 case REG_DWORD:
2981 torture_assert_int_equal(tctx, data.value, data_ex.value, "REG_DWORD mismatch");
2982 break;
2983 case REG_BINARY:
2984 torture_assert_data_blob_equal(tctx, data.binary, data_ex.binary, "REG_BINARY mismatch");
2985 break;
2986 default:
2987 break;
2991 return true;
2994 static bool test_EnumPrinterData(struct torture_context *tctx, struct dcerpc_pipe *p,
2995 struct policy_handle *handle)
2997 NTSTATUS status;
2998 struct spoolss_EnumPrinterData r;
3000 ZERO_STRUCT(r);
3001 r.in.handle = handle;
3002 r.in.enum_index = 0;
3004 do {
3005 uint32_t value_size = 0;
3006 uint32_t data_size = 0;
3007 enum winreg_Type type = 0;
3009 r.in.value_offered = value_size;
3010 r.out.value_needed = &value_size;
3011 r.in.data_offered = data_size;
3012 r.out.data_needed = &data_size;
3014 r.out.type = &type;
3015 r.out.data = talloc_zero_array(tctx, uint8_t, 0);
3017 torture_comment(tctx, "Testing EnumPrinterData\n");
3019 status = dcerpc_spoolss_EnumPrinterData(p, tctx, &r);
3021 torture_assert_ntstatus_ok(tctx, status, "EnumPrinterData failed");
3022 if (W_ERROR_EQUAL(r.out.result, WERR_NO_MORE_ITEMS)) {
3023 break;
3025 torture_assert_werr_ok(tctx, r.out.result, "EnumPrinterData");
3027 r.in.value_offered = value_size;
3028 r.out.value_name = talloc_zero_array(tctx, const char, value_size);
3029 r.in.data_offered = data_size;
3030 r.out.data = talloc_zero_array(tctx, uint8_t, data_size);
3032 status = dcerpc_spoolss_EnumPrinterData(p, tctx, &r);
3034 torture_assert_ntstatus_ok(tctx, status, "EnumPrinterData failed");
3035 if (W_ERROR_EQUAL(r.out.result, WERR_NO_MORE_ITEMS)) {
3036 break;
3039 torture_assert_werr_ok(tctx, r.out.result, "EnumPrinterData failed");
3041 torture_assert(tctx, test_GetPrinterData(tctx, p, handle, r.out.value_name, NULL, NULL),
3042 talloc_asprintf(tctx, "failed to call GetPrinterData for %s\n", r.out.value_name));
3044 torture_assert(tctx, test_GetPrinterDataEx(tctx, p, handle, "PrinterDriverData", r.out.value_name, NULL, NULL),
3045 talloc_asprintf(tctx, "failed to call GetPrinterDataEx on PrinterDriverData for %s\n", r.out.value_name));
3047 r.in.enum_index++;
3049 } while (W_ERROR_IS_OK(r.out.result));
3051 return true;
3054 static bool test_EnumPrinterDataEx(struct torture_context *tctx,
3055 struct dcerpc_pipe *p,
3056 struct policy_handle *handle,
3057 const char *key_name)
3059 struct spoolss_EnumPrinterDataEx r;
3060 struct spoolss_PrinterEnumValues *info;
3061 uint32_t needed;
3062 uint32_t count;
3064 r.in.handle = handle;
3065 r.in.key_name = key_name;
3066 r.in.offered = 0;
3067 r.out.needed = &needed;
3068 r.out.count = &count;
3069 r.out.info = &info;
3071 torture_comment(tctx, "Testing EnumPrinterDataEx(%s)\n", key_name);
3073 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_EnumPrinterDataEx(p, tctx, &r),
3074 "EnumPrinterDataEx failed");
3075 if (W_ERROR_EQUAL(r.out.result, WERR_MORE_DATA)) {
3076 r.in.offered = needed;
3077 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_EnumPrinterDataEx(p, tctx, &r),
3078 "EnumPrinterDataEx failed");
3081 torture_assert_werr_ok(tctx, r.out.result, "EnumPrinterDataEx failed");
3083 CHECK_NEEDED_SIZE_ENUM(spoolss_EnumPrinterDataEx, info, count, lp_iconv_convenience(tctx->lp_ctx), needed, 1);
3085 return true;
3089 static bool test_DeletePrinterData(struct torture_context *tctx,
3090 struct dcerpc_pipe *p,
3091 struct policy_handle *handle,
3092 const char *value_name)
3094 NTSTATUS status;
3095 struct spoolss_DeletePrinterData r;
3097 r.in.handle = handle;
3098 r.in.value_name = value_name;
3100 torture_comment(tctx, "Testing DeletePrinterData(%s)\n",
3101 r.in.value_name);
3103 status = dcerpc_spoolss_DeletePrinterData(p, tctx, &r);
3105 torture_assert_ntstatus_ok(tctx, status, "DeletePrinterData failed");
3106 torture_assert_werr_ok(tctx, r.out.result, "DeletePrinterData failed");
3108 return true;
3111 static bool test_DeletePrinterDataEx(struct torture_context *tctx,
3112 struct dcerpc_pipe *p,
3113 struct policy_handle *handle,
3114 const char *key_name,
3115 const char *value_name)
3117 struct spoolss_DeletePrinterDataEx r;
3119 r.in.handle = handle;
3120 r.in.key_name = key_name;
3121 r.in.value_name = value_name;
3123 torture_comment(tctx, "Testing DeletePrinterDataEx(%s - %s)\n",
3124 r.in.key_name, r.in.value_name);
3126 torture_assert_ntstatus_ok(tctx,
3127 dcerpc_spoolss_DeletePrinterDataEx(p, tctx, &r),
3128 "DeletePrinterDataEx failed");
3129 torture_assert_werr_ok(tctx, r.out.result,
3130 "DeletePrinterDataEx failed");
3132 return true;
3135 static bool test_DeletePrinterKey(struct torture_context *tctx,
3136 struct dcerpc_pipe *p,
3137 struct policy_handle *handle,
3138 const char *key_name)
3140 struct spoolss_DeletePrinterKey r;
3142 r.in.handle = handle;
3143 r.in.key_name = key_name;
3145 torture_comment(tctx, "Testing DeletePrinterKey(%s)\n", r.in.key_name);
3147 if (strequal(key_name, "") && !torture_setting_bool(tctx, "dangerous", false)) {
3148 torture_skip(tctx, "not wiping out printer registry - enable dangerous tests to use\n");
3149 return true;
3152 torture_assert_ntstatus_ok(tctx,
3153 dcerpc_spoolss_DeletePrinterKey(p, tctx, &r),
3154 "DeletePrinterKey failed");
3155 torture_assert_werr_ok(tctx, r.out.result,
3156 "DeletePrinterKey failed");
3158 return true;
3161 static bool test_SetPrinterData(struct torture_context *tctx,
3162 struct dcerpc_pipe *p,
3163 struct policy_handle *handle)
3165 NTSTATUS status;
3166 struct spoolss_SetPrinterData r;
3167 const char *values[] = {
3168 "spootyfoot",
3169 "spooty\\foot",
3170 #if 0
3171 /* FIXME: not working with s3 atm. */
3172 "spooty,foot",
3173 "spooty,fo,ot",
3174 #endif
3175 "spooty foot",
3176 #if 0
3177 /* FIXME: not working with s3 atm. */
3178 "spooty\\fo,ot",
3179 "spooty,fo\\ot"
3180 #endif
3182 int i;
3184 for (i=0; i < ARRAY_SIZE(values); i++) {
3186 enum winreg_Type type;
3187 union spoolss_PrinterData data;
3189 r.in.handle = handle;
3190 r.in.value_name = values[i];
3191 r.in.type = REG_SZ;
3192 r.in.data.string = "dog";
3194 torture_comment(tctx, "Testing SetPrinterData(%s)\n",
3195 r.in.value_name);
3197 status = dcerpc_spoolss_SetPrinterData(p, tctx, &r);
3199 torture_assert_ntstatus_ok(tctx, status, "SetPrinterData failed");
3200 torture_assert_werr_ok(tctx, r.out.result, "SetPrinterData failed");
3202 if (!test_GetPrinterData(tctx, p, handle, r.in.value_name, &type, &data)) {
3203 return false;
3206 torture_assert_int_equal(tctx, r.in.type, type, "type mismatch");
3207 torture_assert_str_equal(tctx, r.in.data.string, data.string, "data mismatch");
3209 if (!test_DeletePrinterData(tctx, p, handle, r.in.value_name)) {
3210 return false;
3214 return true;
3217 static bool test_EnumPrinterKey(struct torture_context *tctx,
3218 struct dcerpc_pipe *p,
3219 struct policy_handle *handle,
3220 const char *key_name,
3221 const char ***array);
3223 static bool test_SetPrinterDataEx(struct torture_context *tctx,
3224 struct dcerpc_pipe *p,
3225 struct policy_handle *handle)
3227 NTSTATUS status;
3228 struct spoolss_SetPrinterDataEx r;
3229 const char *value_name = "dog";
3230 const char *keys[] = {
3231 "torturedataex",
3232 "torture data ex",
3233 #if 0
3234 /* FIXME: not working with s3 atm. */
3235 "torturedataex_with_subkey\\subkey",
3236 "torturedataex_with_subkey\\subkey:0",
3237 "torturedataex_with_subkey\\subkey:1",
3238 "torturedataex_with_subkey\\subkey\\subsubkey",
3239 "torturedataex_with_subkey\\subkey\\subsubkey:0",
3240 "torturedataex_with_subkey\\subkey\\subsubkey:1",
3241 #endif
3242 "torture,data",
3243 #if 0
3244 /* FIXME: not working with s3 atm. */
3246 "torture,data,ex",
3247 "torture,data\\ex",
3248 "torture\\data,ex"
3249 #endif
3251 enum winreg_Type types[] = {
3252 REG_SZ,
3253 REG_DWORD,
3254 REG_BINARY
3256 int i, t;
3259 for (i=0; i < ARRAY_SIZE(keys); i++) {
3260 for (t=0; t < ARRAY_SIZE(types); t++) {
3262 char *c;
3263 const char *key;
3264 enum winreg_Type type;
3265 const char *string = "I have no idea";
3266 DATA_BLOB blob = data_blob_string_const("catfoobar");
3267 uint32_t value = 12345678;
3268 const char **subkeys;
3269 union spoolss_PrinterData data;
3271 r.in.handle = handle;
3272 r.in.key_name = keys[i];
3273 r.in.value_name = value_name;
3274 r.in.type = types[t];
3276 switch (types[t]) {
3277 case REG_BINARY:
3278 r.in.data.binary = blob;
3279 break;
3280 case REG_DWORD:
3281 r.in.data.value = value;
3282 break;
3283 case REG_SZ:
3284 r.in.data.string = string;
3285 break;
3286 default:
3287 torture_fail(tctx, talloc_asprintf(tctx, "type %d untested\n", types[t]));
3290 torture_comment(tctx, "Testing SetPrinterDataEx(%s - %s) type %d\n", r.in.key_name, value_name, types[t]);
3292 status = dcerpc_spoolss_SetPrinterDataEx(p, tctx, &r);
3294 torture_assert_ntstatus_ok(tctx, status, "SetPrinterDataEx failed");
3295 torture_assert_werr_ok(tctx, r.out.result, "SetPrinterDataEx failed");
3297 key = talloc_strdup(tctx, r.in.key_name);
3299 if (!test_GetPrinterDataEx(tctx, p, handle, r.in.key_name, value_name, &type, &data)) {
3300 return false;
3303 torture_assert_int_equal(tctx, r.in.type, type, "type mismatch");
3305 switch (type) {
3306 case REG_BINARY:
3307 torture_assert_data_blob_equal(tctx, blob, data.binary, "data mismatch");
3308 break;
3309 case REG_DWORD:
3310 torture_assert_int_equal(tctx, value, data.value, "data mismatch");
3311 break;
3312 case REG_SZ:
3313 torture_assert_str_equal(tctx, string, data.string, "data mismatch");
3314 break;
3315 default:
3316 torture_fail(tctx, talloc_asprintf(tctx, "type %d untested\n", type));
3319 if (!test_EnumPrinterDataEx(tctx, p, handle, r.in.key_name)) {
3320 return false;
3323 if (!test_DeletePrinterDataEx(tctx, p, handle, r.in.key_name, value_name)) {
3324 return false;
3327 c = strchr(key, '\\');
3328 if (c) {
3329 int i;
3331 /* we have subkeys */
3333 *c = 0;
3335 if (!test_EnumPrinterKey(tctx, p, handle, key, &subkeys)) {
3336 return false;
3339 for (i=0; subkeys && subkeys[i]; i++) {
3341 const char *current_key = talloc_asprintf(tctx, "%s\\%s", key, subkeys[i]);
3343 if (!test_DeletePrinterKey(tctx, p, handle, current_key)) {
3344 return false;
3348 if (!test_DeletePrinterKey(tctx, p, handle, key)) {
3349 return false;
3352 } else {
3353 if (!test_DeletePrinterKey(tctx, p, handle, key)) {
3354 return false;
3360 return true;
3363 static bool test_GetChangeID_PrinterData(struct torture_context *tctx,
3364 struct dcerpc_pipe *p,
3365 struct policy_handle *handle,
3366 uint32_t *change_id)
3368 enum winreg_Type type;
3369 union spoolss_PrinterData data;
3371 torture_assert(tctx,
3372 test_GetPrinterData(tctx, p, handle, "ChangeID", &type, &data),
3373 "failed to call GetPrinterData");
3375 torture_assert(tctx, type == REG_DWORD, "unexpected type");
3377 *change_id = data.value;
3379 return true;
3382 static bool test_GetChangeID_PrinterDataEx(struct torture_context *tctx,
3383 struct dcerpc_pipe *p,
3384 struct policy_handle *handle,
3385 uint32_t *change_id)
3387 enum winreg_Type type;
3388 union spoolss_PrinterData data;
3390 torture_assert(tctx,
3391 test_GetPrinterDataEx(tctx, p, handle, "PrinterDriverData", "ChangeID", &type, &data),
3392 "failed to call GetPrinterData");
3394 torture_assert(tctx, type == REG_DWORD, "unexpected type");
3396 *change_id = data.value;
3398 return true;
3401 static bool test_GetChangeID_PrinterInfo(struct torture_context *tctx,
3402 struct dcerpc_pipe *p,
3403 struct policy_handle *handle,
3404 uint32_t *change_id)
3406 union spoolss_PrinterInfo info;
3408 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 0, &info),
3409 "failed to query Printer level 0");
3411 *change_id = info.info0.change_id;
3413 return true;
3416 static bool test_ChangeID(struct torture_context *tctx,
3417 struct dcerpc_pipe *p,
3418 struct policy_handle *handle)
3420 uint32_t change_id, change_id_ex, change_id_info;
3421 uint32_t change_id2, change_id_ex2, change_id_info2;
3422 union spoolss_PrinterInfo info;
3423 const char *comment;
3426 torture_comment(tctx, "Testing ChangeID: id change test #1\n");
3428 torture_assert(tctx, test_GetChangeID_PrinterData(tctx, p, handle, &change_id),
3429 "failed to query for ChangeID");
3430 torture_assert(tctx, test_GetChangeID_PrinterDataEx(tctx, p, handle, &change_id_ex),
3431 "failed to query for ChangeID");
3432 torture_assert(tctx, test_GetChangeID_PrinterInfo(tctx, p, handle, &change_id_info),
3433 "failed to query for ChangeID");
3435 torture_assert_int_equal(tctx, change_id, change_id_ex,
3436 "change_ids should all be equal");
3437 torture_assert_int_equal(tctx, change_id_ex, change_id_info,
3438 "change_ids should all be equal");
3441 torture_comment(tctx, "Testing ChangeID: id change test #2\n");
3443 torture_assert(tctx, test_GetChangeID_PrinterData(tctx, p, handle, &change_id),
3444 "failed to query for ChangeID");
3445 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 2, &info),
3446 "failed to query Printer level 2");
3447 torture_assert(tctx, test_GetChangeID_PrinterDataEx(tctx, p, handle, &change_id_ex),
3448 "failed to query for ChangeID");
3449 torture_assert(tctx, test_GetChangeID_PrinterInfo(tctx, p, handle, &change_id_info),
3450 "failed to query for ChangeID");
3451 torture_assert_int_equal(tctx, change_id, change_id_ex,
3452 "change_id should not have changed");
3453 torture_assert_int_equal(tctx, change_id_ex, change_id_info,
3454 "change_id should not have changed");
3457 torture_comment(tctx, "Testing ChangeID: id change test #3\n");
3459 torture_assert(tctx, test_GetChangeID_PrinterData(tctx, p, handle, &change_id),
3460 "failed to query for ChangeID");
3461 torture_assert(tctx, test_GetChangeID_PrinterDataEx(tctx, p, handle, &change_id_ex),
3462 "failed to query for ChangeID");
3463 torture_assert(tctx, test_GetChangeID_PrinterInfo(tctx, p, handle, &change_id_info),
3464 "failed to query for ChangeID");
3465 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 2, &info),
3466 "failed to query Printer level 2");
3467 comment = talloc_strdup(tctx, info.info2.comment);
3470 struct spoolss_SetPrinterInfoCtr info_ctr;
3471 struct spoolss_DevmodeContainer devmode_ctr;
3472 struct sec_desc_buf secdesc_ctr;
3473 struct spoolss_SetPrinterInfo2 info2;
3475 ZERO_STRUCT(info_ctr);
3476 ZERO_STRUCT(devmode_ctr);
3477 ZERO_STRUCT(secdesc_ctr);
3479 info2.servername = info.info2.servername;
3480 info2.printername = info.info2.printername;
3481 info2.sharename = info.info2.sharename;
3482 info2.portname = info.info2.portname;
3483 info2.drivername = info.info2.drivername;
3484 info2.comment = "torture_comment";
3485 info2.location = info.info2.location;
3486 info2.devmode_ptr = 0;
3487 info2.sepfile = info.info2.sepfile;
3488 info2.printprocessor = info.info2.printprocessor;
3489 info2.datatype = info.info2.datatype;
3490 info2.parameters = info.info2.parameters;
3491 info2.secdesc_ptr = 0;
3492 info2.attributes = info.info2.attributes;
3493 info2.priority = info.info2.priority;
3494 info2.defaultpriority = info.info2.defaultpriority;
3495 info2.starttime = info.info2.starttime;
3496 info2.untiltime = info.info2.untiltime;
3497 info2.status = info.info2.status;
3498 info2.cjobs = info.info2.cjobs;
3499 info2.averageppm = info.info2.averageppm;
3501 info_ctr.level = 2;
3502 info_ctr.info.info2 = &info2;
3504 torture_assert(tctx, test_SetPrinter(tctx, p, handle, &info_ctr, &devmode_ctr, &secdesc_ctr, 0),
3505 "failed to call SetPrinter");
3507 info2.comment = comment;
3509 torture_assert(tctx, test_SetPrinter(tctx, p, handle, &info_ctr, &devmode_ctr, &secdesc_ctr, 0),
3510 "failed to call SetPrinter");
3514 torture_assert(tctx, test_GetChangeID_PrinterData(tctx, p, handle, &change_id2),
3515 "failed to query for ChangeID");
3516 torture_assert(tctx, test_GetChangeID_PrinterDataEx(tctx, p, handle, &change_id_ex2),
3517 "failed to query for ChangeID");
3518 torture_assert(tctx, test_GetChangeID_PrinterInfo(tctx, p, handle, &change_id_info2),
3519 "failed to query for ChangeID");
3521 torture_assert_int_equal(tctx, change_id2, change_id_ex2,
3522 "change_ids should all be equal");
3523 torture_assert_int_equal(tctx, change_id_ex2, change_id_info2,
3524 "change_ids should all be equal");
3526 torture_assert(tctx, (change_id < change_id2),
3527 talloc_asprintf(tctx, "change_id %d needs to be larger than change_id %d",
3528 change_id2, change_id));
3529 torture_assert(tctx, (change_id_ex < change_id_ex2),
3530 talloc_asprintf(tctx, "change_id %d needs to be larger than change_id %d",
3531 change_id_ex2, change_id_ex));
3532 torture_assert(tctx, (change_id_info < change_id_info2),
3533 talloc_asprintf(tctx, "change_id %d needs to be larger than change_id %d",
3534 change_id_info2, change_id_info));
3536 return true;
3539 static bool test_SecondaryClosePrinter(struct torture_context *tctx,
3540 struct dcerpc_pipe *p,
3541 struct policy_handle *handle)
3543 NTSTATUS status;
3544 struct dcerpc_binding *b;
3545 struct dcerpc_pipe *p2;
3546 struct spoolss_ClosePrinter cp;
3548 /* only makes sense on SMB */
3549 if (p->conn->transport.transport != NCACN_NP) {
3550 return true;
3553 torture_comment(tctx, "testing close on secondary pipe\n");
3555 status = dcerpc_parse_binding(tctx, p->conn->binding_string, &b);
3556 torture_assert_ntstatus_ok(tctx, status, "Failed to parse dcerpc binding");
3558 status = dcerpc_secondary_connection(p, &p2, b);
3559 torture_assert_ntstatus_ok(tctx, status, "Failed to create secondary connection");
3561 status = dcerpc_bind_auth_none(p2, &ndr_table_spoolss);
3562 torture_assert_ntstatus_ok(tctx, status, "Failed to create bind on secondary connection");
3564 cp.in.handle = handle;
3565 cp.out.handle = handle;
3567 status = dcerpc_spoolss_ClosePrinter(p2, tctx, &cp);
3568 torture_assert_ntstatus_equal(tctx, status, NT_STATUS_NET_WRITE_FAULT,
3569 "ERROR: Allowed close on secondary connection");
3571 torture_assert_int_equal(tctx, p2->last_fault_code, DCERPC_FAULT_CONTEXT_MISMATCH,
3572 "Unexpected fault code");
3574 talloc_free(p2);
3576 return true;
3579 static bool test_OpenPrinter_badname(struct torture_context *tctx,
3580 struct dcerpc_pipe *p, const char *name)
3582 NTSTATUS status;
3583 struct spoolss_OpenPrinter op;
3584 struct spoolss_OpenPrinterEx opEx;
3585 struct policy_handle handle;
3586 bool ret = true;
3588 op.in.printername = name;
3589 op.in.datatype = NULL;
3590 op.in.devmode_ctr.devmode= NULL;
3591 op.in.access_mask = 0;
3592 op.out.handle = &handle;
3594 torture_comment(tctx, "\nTesting OpenPrinter(%s) with bad name\n", op.in.printername);
3596 status = dcerpc_spoolss_OpenPrinter(p, tctx, &op);
3597 torture_assert_ntstatus_ok(tctx, status, "OpenPrinter failed");
3598 if (!W_ERROR_EQUAL(WERR_INVALID_PRINTER_NAME,op.out.result)) {
3599 torture_comment(tctx, "OpenPrinter(%s) unexpected result[%s] should be WERR_INVALID_PRINTER_NAME\n",
3600 name, win_errstr(op.out.result));
3603 if (W_ERROR_IS_OK(op.out.result)) {
3604 ret &=test_ClosePrinter(tctx, p, &handle);
3607 opEx.in.printername = name;
3608 opEx.in.datatype = NULL;
3609 opEx.in.devmode_ctr.devmode = NULL;
3610 opEx.in.access_mask = 0;
3611 opEx.in.level = 1;
3612 opEx.in.userlevel.level1 = NULL;
3613 opEx.out.handle = &handle;
3615 torture_comment(tctx, "Testing OpenPrinterEx(%s) with bad name\n", opEx.in.printername);
3617 status = dcerpc_spoolss_OpenPrinterEx(p, tctx, &opEx);
3618 torture_assert_ntstatus_ok(tctx, status, "OpenPrinterEx failed");
3619 if (!W_ERROR_EQUAL(WERR_INVALID_PARAM,opEx.out.result)) {
3620 torture_comment(tctx, "OpenPrinterEx(%s) unexpected result[%s] should be WERR_INVALID_PARAM\n",
3621 name, win_errstr(opEx.out.result));
3624 if (W_ERROR_IS_OK(opEx.out.result)) {
3625 ret &=test_ClosePrinter(tctx, p, &handle);
3628 return ret;
3631 static bool test_OpenPrinter(struct torture_context *tctx,
3632 struct dcerpc_pipe *p,
3633 const char *name,
3634 const char *environment)
3636 NTSTATUS status;
3637 struct spoolss_OpenPrinter r;
3638 struct policy_handle handle;
3639 bool ret = true;
3641 r.in.printername = talloc_asprintf(tctx, "\\\\%s\\%s", dcerpc_server_name(p), name);
3642 r.in.datatype = NULL;
3643 r.in.devmode_ctr.devmode= NULL;
3644 r.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
3645 r.out.handle = &handle;
3647 torture_comment(tctx, "Testing OpenPrinter(%s)\n", r.in.printername);
3649 status = dcerpc_spoolss_OpenPrinter(p, tctx, &r);
3651 torture_assert_ntstatus_ok(tctx, status, "OpenPrinter failed");
3653 torture_assert_werr_ok(tctx, r.out.result, "OpenPrinter failed");
3655 if (!test_GetPrinter(tctx, p, &handle, environment)) {
3656 ret = false;
3659 if (!torture_setting_bool(tctx, "samba3", false)) {
3660 if (!test_SecondaryClosePrinter(tctx, p, &handle)) {
3661 ret = false;
3665 if (!test_ClosePrinter(tctx, p, &handle)) {
3666 ret = false;
3669 return ret;
3672 static bool call_OpenPrinterEx(struct torture_context *tctx,
3673 struct dcerpc_pipe *p,
3674 const char *name,
3675 struct spoolss_DeviceMode *devmode,
3676 struct policy_handle *handle)
3678 struct spoolss_OpenPrinterEx r;
3679 struct spoolss_UserLevel1 userlevel1;
3680 NTSTATUS status;
3682 if (name && name[0]) {
3683 r.in.printername = talloc_asprintf(tctx, "\\\\%s\\%s",
3684 dcerpc_server_name(p), name);
3685 } else {
3686 r.in.printername = talloc_asprintf(tctx, "\\\\%s",
3687 dcerpc_server_name(p));
3690 r.in.datatype = NULL;
3691 r.in.devmode_ctr.devmode= devmode;
3692 r.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
3693 r.in.level = 1;
3694 r.in.userlevel.level1 = &userlevel1;
3695 r.out.handle = handle;
3697 userlevel1.size = 1234;
3698 userlevel1.client = "hello";
3699 userlevel1.user = "spottyfoot!";
3700 userlevel1.build = 1;
3701 userlevel1.major = 2;
3702 userlevel1.minor = 3;
3703 userlevel1.processor = 4;
3705 torture_comment(tctx, "Testing OpenPrinterEx(%s)\n", r.in.printername);
3707 status = dcerpc_spoolss_OpenPrinterEx(p, tctx, &r);
3709 torture_assert_ntstatus_ok(tctx, status, "OpenPrinterEx failed");
3711 torture_assert_werr_ok(tctx, r.out.result, "OpenPrinterEx failed");
3713 return true;
3716 static bool test_OpenPrinterEx(struct torture_context *tctx,
3717 struct dcerpc_pipe *p,
3718 const char *name,
3719 const char *environment)
3721 struct policy_handle handle;
3722 bool ret = true;
3724 if (!call_OpenPrinterEx(tctx, p, name, NULL, &handle)) {
3725 return false;
3728 if (!test_PrinterInfo_SD(tctx, p, &handle)) {
3729 ret = false;
3732 if (!test_GetPrinter(tctx, p, &handle, environment)) {
3733 ret = false;
3736 if (!test_EnumForms(tctx, p, &handle, false)) {
3737 ret = false;
3740 if (!test_AddForm(tctx, p, &handle, false)) {
3741 ret = false;
3744 if (!test_EnumPrinterData(tctx, p, &handle)) {
3745 ret = false;
3748 if (!test_EnumPrinterDataEx(tctx, p, &handle, "PrinterDriverData")) {
3749 ret = false;
3752 if (!test_printer_keys(tctx, p, &handle)) {
3753 ret = false;
3756 if (!test_PausePrinter(tctx, p, &handle)) {
3757 ret = false;
3760 if (!test_DoPrintTest(tctx, p, &handle)) {
3761 ret = false;
3764 if (!test_ResumePrinter(tctx, p, &handle)) {
3765 ret = false;
3768 if (!test_SetPrinterData(tctx, p, &handle)) {
3769 ret = false;
3772 if (!test_SetPrinterDataEx(tctx, p, &handle)) {
3773 ret = false;
3776 if (!torture_setting_bool(tctx, "samba3", false)) {
3777 if (!test_SecondaryClosePrinter(tctx, p, &handle)) {
3778 ret = false;
3782 if (!test_ClosePrinter(tctx, p, &handle)) {
3783 ret = false;
3786 return ret;
3789 static bool test_EnumPrinters_old(struct torture_context *tctx,
3790 struct dcerpc_pipe *p,
3791 const char *environment)
3793 struct spoolss_EnumPrinters r;
3794 NTSTATUS status;
3795 uint16_t levels[] = {1, 2, 4, 5};
3796 int i;
3797 bool ret = true;
3799 for (i=0;i<ARRAY_SIZE(levels);i++) {
3800 union spoolss_PrinterInfo *info;
3801 int j;
3802 uint32_t needed;
3803 uint32_t count;
3805 r.in.flags = PRINTER_ENUM_LOCAL;
3806 r.in.server = "";
3807 r.in.level = levels[i];
3808 r.in.buffer = NULL;
3809 r.in.offered = 0;
3810 r.out.needed = &needed;
3811 r.out.count = &count;
3812 r.out.info = &info;
3814 torture_comment(tctx, "Testing EnumPrinters level %u\n", r.in.level);
3816 status = dcerpc_spoolss_EnumPrinters(p, tctx, &r);
3817 torture_assert_ntstatus_ok(tctx, status, "EnumPrinters failed");
3819 if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
3820 DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed);
3821 data_blob_clear(&blob);
3822 r.in.buffer = &blob;
3823 r.in.offered = needed;
3824 status = dcerpc_spoolss_EnumPrinters(p, tctx, &r);
3827 torture_assert_ntstatus_ok(tctx, status, "EnumPrinters failed");
3829 torture_assert_werr_ok(tctx, r.out.result, "EnumPrinters failed");
3831 CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumPrinters, info, r.in.level, count, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
3833 if (!info) {
3834 torture_comment(tctx, "No printers returned\n");
3835 return true;
3838 for (j=0;j<count;j++) {
3839 if (r.in.level == 1) {
3840 char *unc = talloc_strdup(tctx, info[j].info1.name);
3841 char *slash, *name;
3842 name = unc;
3843 if (unc[0] == '\\' && unc[1] == '\\') {
3844 unc +=2;
3846 slash = strchr(unc, '\\');
3847 if (slash) {
3848 slash++;
3849 name = slash;
3851 if (!test_OpenPrinter(tctx, p, name, environment)) {
3852 ret = false;
3854 if (!test_OpenPrinterEx(tctx, p, name, environment)) {
3855 ret = false;
3861 return ret;
3864 static bool test_GetPrinterDriver(struct torture_context *tctx,
3865 struct dcerpc_pipe *p,
3866 struct policy_handle *handle,
3867 const char *driver_name)
3869 struct spoolss_GetPrinterDriver r;
3870 uint32_t needed;
3872 r.in.handle = handle;
3873 r.in.architecture = "W32X86";
3874 r.in.level = 1;
3875 r.in.buffer = NULL;
3876 r.in.offered = 0;
3877 r.out.needed = &needed;
3879 torture_comment(tctx, "Testing GetPrinterDriver level %d\n", r.in.level);
3881 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_GetPrinterDriver(p, tctx, &r),
3882 "failed to call GetPrinterDriver");
3883 if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
3884 DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed);
3885 data_blob_clear(&blob);
3886 r.in.buffer = &blob;
3887 r.in.offered = needed;
3888 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_GetPrinterDriver(p, tctx, &r),
3889 "failed to call GetPrinterDriver");
3892 torture_assert_werr_ok(tctx, r.out.result,
3893 "failed to call GetPrinterDriver");
3895 CHECK_NEEDED_SIZE_LEVEL(spoolss_DriverInfo, r.out.info, r.in.level, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
3897 return true;
3900 static bool test_GetPrinterDriver2(struct torture_context *tctx,
3901 struct dcerpc_pipe *p,
3902 struct policy_handle *handle,
3903 const char *driver_name,
3904 const char *architecture)
3906 struct spoolss_GetPrinterDriver2 r;
3907 uint16_t levels[] = {1, 2, 3, 4, 5, 6, 8, 101 };
3908 uint32_t needed;
3909 uint32_t server_major_version;
3910 uint32_t server_minor_version;
3911 int i;
3913 r.in.handle = handle;
3914 r.in.architecture = architecture;
3915 r.in.client_major_version = 3;
3916 r.in.client_minor_version = 0;
3917 r.out.needed = &needed;
3918 r.out.server_major_version = &server_major_version;
3919 r.out.server_minor_version = &server_minor_version;
3921 for (i=0;i<ARRAY_SIZE(levels);i++) {
3923 r.in.buffer = NULL;
3924 r.in.offered = 0;
3925 r.in.level = levels[i];
3927 torture_comment(tctx, "Testing GetPrinterDriver2(%s) level %d\n",
3928 driver_name, r.in.level);
3930 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_GetPrinterDriver2(p, tctx, &r),
3931 "failed to call GetPrinterDriver2");
3932 if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
3933 DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed);
3934 data_blob_clear(&blob);
3935 r.in.buffer = &blob;
3936 r.in.offered = needed;
3937 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_GetPrinterDriver2(p, tctx, &r),
3938 "failed to call GetPrinterDriver2");
3941 if (W_ERROR_EQUAL(r.out.result, WERR_INVALID_LEVEL)) {
3942 switch (r.in.level) {
3943 case 101:
3944 case 8:
3945 continue;
3946 default:
3947 break;
3951 torture_assert_werr_ok(tctx, r.out.result,
3952 "failed to call GetPrinterDriver2");
3954 CHECK_NEEDED_SIZE_LEVEL(spoolss_DriverInfo, r.out.info, r.in.level, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
3957 return true;
3960 static bool test_EnumPrinterDrivers_old(struct torture_context *tctx,
3961 struct dcerpc_pipe *p,
3962 const char *environment)
3964 struct spoolss_EnumPrinterDrivers r;
3965 NTSTATUS status;
3966 uint16_t levels[] = {1, 2, 3, 4, 5, 6};
3967 int i;
3969 for (i=0;i<ARRAY_SIZE(levels);i++) {
3971 uint32_t needed;
3972 uint32_t count;
3973 union spoolss_DriverInfo *info;
3975 r.in.server = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
3976 r.in.environment = environment;
3977 r.in.level = levels[i];
3978 r.in.buffer = NULL;
3979 r.in.offered = 0;
3980 r.out.needed = &needed;
3981 r.out.count = &count;
3982 r.out.info = &info;
3984 torture_comment(tctx, "Testing EnumPrinterDrivers level %u\n", r.in.level);
3986 status = dcerpc_spoolss_EnumPrinterDrivers(p, tctx, &r);
3988 torture_assert_ntstatus_ok(tctx, status, "EnumPrinterDrivers failed");
3990 if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
3991 DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed);
3992 data_blob_clear(&blob);
3993 r.in.buffer = &blob;
3994 r.in.offered = needed;
3995 status = dcerpc_spoolss_EnumPrinterDrivers(p, tctx, &r);
3998 torture_assert_ntstatus_ok(tctx, status, "EnumPrinterDrivers failed");
4000 torture_assert_werr_ok(tctx, r.out.result, "EnumPrinterDrivers failed");
4002 if (!info) {
4003 torture_comment(tctx, "No printer drivers returned\n");
4004 break;
4007 CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumPrinterDrivers, info, r.in.level, count, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
4010 return true;
4013 static bool test_DeletePrinter(struct torture_context *tctx,
4014 struct dcerpc_pipe *p,
4015 struct policy_handle *handle)
4017 struct spoolss_DeletePrinter r;
4019 torture_comment(tctx, "Testing DeletePrinter\n");
4021 r.in.handle = handle;
4023 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_DeletePrinter(p, tctx, &r),
4024 "failed to delete printer");
4025 torture_assert_werr_ok(tctx, r.out.result,
4026 "failed to delete printer");
4028 return true;
4031 static bool test_EnumPrinters_findname(struct torture_context *tctx,
4032 struct dcerpc_pipe *p,
4033 uint32_t flags,
4034 uint32_t level,
4035 const char *name,
4036 bool *found)
4038 struct spoolss_EnumPrinters e;
4039 uint32_t count;
4040 union spoolss_PrinterInfo *info;
4041 uint32_t needed;
4042 int i;
4044 *found = false;
4046 e.in.flags = flags;
4047 e.in.server = NULL;
4048 e.in.level = level;
4049 e.in.buffer = NULL;
4050 e.in.offered = 0;
4051 e.out.count = &count;
4052 e.out.info = &info;
4053 e.out.needed = &needed;
4055 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_EnumPrinters(p, tctx, &e),
4056 "failed to enum printers");
4058 if (W_ERROR_EQUAL(e.out.result, WERR_INSUFFICIENT_BUFFER)) {
4059 DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed);
4060 data_blob_clear(&blob);
4061 e.in.buffer = &blob;
4062 e.in.offered = needed;
4064 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_EnumPrinters(p, tctx, &e),
4065 "failed to enum printers");
4068 torture_assert_werr_ok(tctx, e.out.result,
4069 "failed to enum printers");
4071 for (i=0; i < count; i++) {
4073 const char *current = NULL;
4074 const char *p;
4076 switch (level) {
4077 case 1:
4078 current = info[i].info1.name;
4079 break;
4082 if (strequal(current, name)) {
4083 *found = true;
4084 break;
4087 p = strrchr(current, '\\');
4088 if (p) {
4089 if (!e.in.server) {
4090 torture_warning(tctx,
4091 "server returns printername %s incl. servername although we did not set servername", current);
4093 p++;
4094 if (strequal(p, name)) {
4095 *found = true;
4096 break;
4101 return true;
4104 static bool test_AddPrinter_wellknown(struct torture_context *tctx,
4105 struct dcerpc_pipe *p,
4106 const char *printername,
4107 bool ex)
4109 WERROR result;
4110 struct spoolss_AddPrinter r;
4111 struct spoolss_AddPrinterEx rex;
4112 struct spoolss_SetPrinterInfoCtr info_ctr;
4113 struct spoolss_SetPrinterInfo1 info1;
4114 struct spoolss_DevmodeContainer devmode_ctr;
4115 struct sec_desc_buf secdesc_ctr;
4116 struct spoolss_UserLevelCtr userlevel_ctr;
4117 struct policy_handle handle;
4118 bool found = false;
4120 ZERO_STRUCT(devmode_ctr);
4121 ZERO_STRUCT(secdesc_ctr);
4122 ZERO_STRUCT(userlevel_ctr);
4123 ZERO_STRUCT(info1);
4125 torture_comment(tctx, "Testing AddPrinter%s level 1\n", ex ? "Ex":"");
4127 /* try to add printer to wellknown printer list (level 1) */
4129 userlevel_ctr.level = 1;
4131 info_ctr.info.info1 = &info1;
4132 info_ctr.level = 1;
4134 rex.in.server = NULL;
4135 rex.in.info_ctr = &info_ctr;
4136 rex.in.devmode_ctr = &devmode_ctr;
4137 rex.in.secdesc_ctr = &secdesc_ctr;
4138 rex.in.userlevel_ctr = &userlevel_ctr;
4139 rex.out.handle = &handle;
4141 r.in.server = NULL;
4142 r.in.info_ctr = &info_ctr;
4143 r.in.devmode_ctr = &devmode_ctr;
4144 r.in.secdesc_ctr = &secdesc_ctr;
4145 r.out.handle = &handle;
4147 torture_assert_ntstatus_ok(tctx, ex ? dcerpc_spoolss_AddPrinterEx(p, tctx, &rex) :
4148 dcerpc_spoolss_AddPrinter(p, tctx, &r),
4149 "failed to add printer");
4150 result = ex ? rex.out.result : r.out.result;
4151 torture_assert_werr_equal(tctx, result, WERR_INVALID_PRINTER_NAME,
4152 "unexpected result code");
4154 info1.name = printername;
4155 info1.flags = PRINTER_ATTRIBUTE_SHARED;
4157 torture_assert_ntstatus_ok(tctx, ex ? dcerpc_spoolss_AddPrinterEx(p, tctx, &rex) :
4158 dcerpc_spoolss_AddPrinter(p, tctx, &r),
4159 "failed to add printer");
4160 result = ex ? rex.out.result : r.out.result;
4161 torture_assert_werr_equal(tctx, result, WERR_PRINTER_ALREADY_EXISTS,
4162 "unexpected result code");
4164 /* bizarre protocol, WERR_PRINTER_ALREADY_EXISTS means success here,
4165 better do a real check to see the printer is really there */
4167 torture_assert(tctx, test_EnumPrinters_findname(tctx, p,
4168 PRINTER_ENUM_NETWORK, 1,
4169 printername,
4170 &found),
4171 "failed to enum printers");
4173 torture_assert(tctx, found, "failed to find newly added printer");
4175 info1.flags = 0;
4177 torture_assert_ntstatus_ok(tctx, ex ? dcerpc_spoolss_AddPrinterEx(p, tctx, &rex) :
4178 dcerpc_spoolss_AddPrinter(p, tctx, &r),
4179 "failed to add printer");
4180 result = ex ? rex.out.result : r.out.result;
4181 torture_assert_werr_equal(tctx, result, WERR_PRINTER_ALREADY_EXISTS,
4182 "unexpected result code");
4184 /* bizarre protocol, WERR_PRINTER_ALREADY_EXISTS means success here,
4185 better do a real check to see the printer has really been removed
4186 from the well known printer list */
4188 found = false;
4190 torture_assert(tctx, test_EnumPrinters_findname(tctx, p,
4191 PRINTER_ENUM_NETWORK, 1,
4192 printername,
4193 &found),
4194 "failed to enum printers");
4195 #if 0
4196 torture_assert(tctx, !found, "printer still in well known printer list");
4197 #endif
4198 return true;
4201 static bool test_AddPrinter_normal(struct torture_context *tctx,
4202 struct dcerpc_pipe *p,
4203 struct policy_handle *handle_p,
4204 const char *printername,
4205 const char *drivername,
4206 const char *portname,
4207 bool ex)
4209 WERROR result;
4210 struct spoolss_AddPrinter r;
4211 struct spoolss_AddPrinterEx rex;
4212 struct spoolss_SetPrinterInfoCtr info_ctr;
4213 struct spoolss_SetPrinterInfo2 info2;
4214 struct spoolss_DevmodeContainer devmode_ctr;
4215 struct sec_desc_buf secdesc_ctr;
4216 struct spoolss_UserLevelCtr userlevel_ctr;
4217 struct policy_handle handle;
4218 bool found = false;
4219 bool existing_printer_deleted = false;
4221 ZERO_STRUCT(devmode_ctr);
4222 ZERO_STRUCT(secdesc_ctr);
4223 ZERO_STRUCT(userlevel_ctr);
4225 torture_comment(tctx, "Testing AddPrinter%s level 2\n", ex ? "Ex":"");
4227 userlevel_ctr.level = 1;
4229 rex.in.server = NULL;
4230 rex.in.info_ctr = &info_ctr;
4231 rex.in.devmode_ctr = &devmode_ctr;
4232 rex.in.secdesc_ctr = &secdesc_ctr;
4233 rex.in.userlevel_ctr = &userlevel_ctr;
4234 rex.out.handle = &handle;
4236 r.in.server = NULL;
4237 r.in.info_ctr = &info_ctr;
4238 r.in.devmode_ctr = &devmode_ctr;
4239 r.in.secdesc_ctr = &secdesc_ctr;
4240 r.out.handle = &handle;
4242 again:
4244 /* try to add printer to printer list (level 2) */
4246 ZERO_STRUCT(info2);
4248 info_ctr.info.info2 = &info2;
4249 info_ctr.level = 2;
4251 torture_assert_ntstatus_ok(tctx, ex ? dcerpc_spoolss_AddPrinterEx(p, tctx, &rex) :
4252 dcerpc_spoolss_AddPrinter(p, tctx, &r),
4253 "failed to add printer");
4254 result = ex ? rex.out.result : r.out.result;
4255 torture_assert_werr_equal(tctx, result, WERR_INVALID_PRINTER_NAME,
4256 "unexpected result code");
4258 info2.printername = printername;
4260 torture_assert_ntstatus_ok(tctx, ex ? dcerpc_spoolss_AddPrinterEx(p, tctx, &rex) :
4261 dcerpc_spoolss_AddPrinter(p, tctx, &r),
4262 "failed to add printer");
4263 result = ex ? rex.out.result : r.out.result;
4265 if (W_ERROR_EQUAL(result, WERR_PRINTER_ALREADY_EXISTS)) {
4266 struct policy_handle printer_handle;
4268 if (existing_printer_deleted) {
4269 torture_fail(tctx, "already deleted printer still existing?");
4272 torture_assert(tctx, call_OpenPrinterEx(tctx, p, printername, NULL, &printer_handle),
4273 "failed to open printer handle");
4275 torture_assert(tctx, test_DeletePrinter(tctx, p, &printer_handle),
4276 "failed to delete printer");
4278 torture_assert(tctx, test_ClosePrinter(tctx, p, &printer_handle),
4279 "failed to close server handle");
4281 existing_printer_deleted = true;
4283 goto again;
4286 torture_assert_werr_equal(tctx, result, WERR_UNKNOWN_PORT,
4287 "unexpected result code");
4289 info2.portname = portname;
4291 torture_assert_ntstatus_ok(tctx, ex ? dcerpc_spoolss_AddPrinterEx(p, tctx, &rex) :
4292 dcerpc_spoolss_AddPrinter(p, tctx, &r),
4293 "failed to add printer");
4294 result = ex ? rex.out.result : r.out.result;
4295 torture_assert_werr_equal(tctx, result, WERR_UNKNOWN_PRINTER_DRIVER,
4296 "unexpected result code");
4298 info2.drivername = drivername;
4300 torture_assert_ntstatus_ok(tctx, ex ? dcerpc_spoolss_AddPrinterEx(p, tctx, &rex) :
4301 dcerpc_spoolss_AddPrinter(p, tctx, &r),
4302 "failed to add printer");
4303 result = ex ? rex.out.result : r.out.result;
4305 /* w2k8r2 allows to add printer w/o defining printprocessor */
4307 if (!W_ERROR_IS_OK(result)) {
4308 torture_assert_werr_equal(tctx, result, WERR_UNKNOWN_PRINTPROCESSOR,
4309 "unexpected result code");
4311 info2.printprocessor = "winprint";
4313 torture_assert_ntstatus_ok(tctx, ex ? dcerpc_spoolss_AddPrinterEx(p, tctx, &rex) :
4314 dcerpc_spoolss_AddPrinter(p, tctx, &r),
4315 "failed to add printer");
4316 result = ex ? rex.out.result : r.out.result;
4317 torture_assert_werr_ok(tctx, result,
4318 "failed to add printer");
4321 *handle_p = handle;
4323 /* we are paranoid, really check if the printer is there now */
4325 torture_assert(tctx, test_EnumPrinters_findname(tctx, p,
4326 PRINTER_ENUM_LOCAL, 1,
4327 printername,
4328 &found),
4329 "failed to enum printers");
4330 torture_assert(tctx, found, "failed to find newly added printer");
4332 torture_assert_ntstatus_ok(tctx, ex ? dcerpc_spoolss_AddPrinterEx(p, tctx, &rex) :
4333 dcerpc_spoolss_AddPrinter(p, tctx, &r),
4334 "failed to add printer");
4335 result = ex ? rex.out.result : r.out.result;
4336 torture_assert_werr_equal(tctx, result, WERR_PRINTER_ALREADY_EXISTS,
4337 "unexpected result code");
4339 return true;
4342 static bool test_AddPrinterEx(struct torture_context *tctx,
4343 struct dcerpc_pipe *p,
4344 struct policy_handle *handle_p,
4345 const char *printername,
4346 const char *drivername,
4347 const char *portname)
4349 bool ret = true;
4351 if (!torture_setting_bool(tctx, "samba3", false)) {
4352 if (!test_AddPrinter_wellknown(tctx, p, TORTURE_WELLKNOWN_PRINTER_EX, true)) {
4353 torture_comment(tctx, "failed to add printer to well known list\n");
4354 ret = false;
4358 if (!test_AddPrinter_normal(tctx, p, handle_p,
4359 printername, drivername, portname,
4360 true)) {
4361 torture_comment(tctx, "failed to add printer to printer list\n");
4362 ret = false;
4365 return ret;
4368 static bool test_AddPrinter(struct torture_context *tctx,
4369 struct dcerpc_pipe *p,
4370 struct policy_handle *handle_p,
4371 const char *printername,
4372 const char *drivername,
4373 const char *portname)
4375 bool ret = true;
4377 if (!torture_setting_bool(tctx, "samba3", false)) {
4378 if (!test_AddPrinter_wellknown(tctx, p, TORTURE_WELLKNOWN_PRINTER, false)) {
4379 torture_comment(tctx, "failed to add printer to well known list\n");
4380 ret = false;
4384 if (!test_AddPrinter_normal(tctx, p, handle_p,
4385 printername, drivername, portname,
4386 false)) {
4387 torture_comment(tctx, "failed to add printer to printer list\n");
4388 ret = false;
4391 return ret;
4394 static bool test_printer_info(struct torture_context *tctx,
4395 struct dcerpc_pipe *p,
4396 struct policy_handle *handle)
4398 bool ret = true;
4400 if (torture_setting_bool(tctx, "samba3", false)) {
4401 torture_skip(tctx, "skipping printer info cross tests against samba 3");
4404 if (!test_PrinterInfo(tctx, p, handle)) {
4405 ret = false;
4408 if (!test_SetPrinter_errors(tctx, p, handle)) {
4409 ret = false;
4412 return ret;
4415 static bool test_EnumPrinterKey(struct torture_context *tctx,
4416 struct dcerpc_pipe *p,
4417 struct policy_handle *handle,
4418 const char *key_name,
4419 const char ***array)
4421 struct spoolss_EnumPrinterKey r;
4422 uint32_t needed = 0;
4423 union spoolss_KeyNames key_buffer;
4424 int32_t offered[] = { 0, 1, 2, 3, 4, 5, -1, -2, -3, -4, -5, 256, 512, 1024, 2048 };
4425 uint32_t _ndr_size;
4426 int i;
4428 r.in.handle = handle;
4429 r.in.key_name = key_name;
4430 r.out.key_buffer = &key_buffer;
4431 r.out.needed = &needed;
4432 r.out._ndr_size = &_ndr_size;
4434 for (i=0; i < ARRAY_SIZE(offered); i++) {
4436 if (offered[i] < 0 && needed) {
4437 if (needed <= 4) {
4438 continue;
4440 r.in.offered = needed + offered[i];
4441 } else {
4442 r.in.offered = offered[i];
4445 ZERO_STRUCT(key_buffer);
4447 torture_comment(tctx, "Testing EnumPrinterKey(%s) with %d offered\n", r.in.key_name, r.in.offered);
4449 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_EnumPrinterKey(p, tctx, &r),
4450 "failed to call EnumPrinterKey");
4451 if (W_ERROR_EQUAL(r.out.result, WERR_MORE_DATA)) {
4453 torture_assert(tctx, (_ndr_size == r.in.offered/2),
4454 talloc_asprintf(tctx, "EnumPrinterKey size mismatch, _ndr_size %d (expected %d)",
4455 _ndr_size, r.in.offered/2));
4457 r.in.offered = needed;
4458 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_EnumPrinterKey(p, tctx, &r),
4459 "failed to call EnumPrinterKey");
4462 if (offered[i] > 0) {
4463 torture_assert_werr_ok(tctx, r.out.result,
4464 "failed to call EnumPrinterKey");
4467 torture_assert(tctx, (_ndr_size == r.in.offered/2),
4468 talloc_asprintf(tctx, "EnumPrinterKey size mismatch, _ndr_size %d (expected %d)",
4469 _ndr_size, r.in.offered/2));
4471 torture_assert(tctx, (*r.out.needed <= r.in.offered),
4472 talloc_asprintf(tctx, "EnumPrinterKey size mismatch: needed %d is not <= offered %d", *r.out.needed, r.in.offered));
4474 torture_assert(tctx, (*r.out.needed <= _ndr_size * 2),
4475 talloc_asprintf(tctx, "EnumPrinterKey size mismatch: needed %d is not <= _ndr_size %d * 2", *r.out.needed, _ndr_size));
4477 if (key_buffer.string_array) {
4478 uint32_t calc_needed = 0;
4479 int s;
4480 for (s=0; key_buffer.string_array[s]; s++) {
4481 calc_needed += strlen_m_term(key_buffer.string_array[s])*2;
4483 if (!key_buffer.string_array[0]) {
4484 calc_needed += 2;
4486 calc_needed += 2;
4488 torture_assert_int_equal(tctx, *r.out.needed, calc_needed,
4489 "EnumPrinterKey unexpected size");
4493 if (array) {
4494 *array = key_buffer.string_array;
4497 return true;
4500 bool test_printer_keys(struct torture_context *tctx,
4501 struct dcerpc_pipe *p,
4502 struct policy_handle *handle)
4504 const char **key_array = NULL;
4505 int i;
4507 torture_comment(tctx, "\nTesting Printer Keys\n");
4509 torture_assert(tctx, test_EnumPrinterKey(tctx, p, handle, "", &key_array),
4510 "failed to call test_EnumPrinterKey");
4512 for (i=0; key_array && key_array[i]; i++) {
4513 torture_assert(tctx, test_EnumPrinterKey(tctx, p, handle, key_array[i], NULL),
4514 "failed to call test_EnumPrinterKey");
4516 for (i=0; key_array && key_array[i]; i++) {
4517 torture_assert(tctx, test_EnumPrinterDataEx(tctx, p, handle, key_array[i]),
4518 "failed to call test_EnumPrinterDataEx");
4521 return true;
4524 static bool test_one_printer(struct torture_context *tctx,
4525 struct dcerpc_pipe *p,
4526 struct policy_handle *handle,
4527 const char *name)
4529 bool ret = true;
4531 if (!test_printer_info(tctx, p, handle)) {
4532 ret = false;
4535 if (!test_PrinterInfo_SD(tctx, p, handle)) {
4536 ret = false;
4539 if (!test_PrinterInfo_DevMode(tctx, p, handle, name)) {
4540 ret = false;
4543 if (!test_ChangeID(tctx, p, handle)) {
4544 ret = false;
4547 if (!test_printer_keys(tctx, p, handle)) {
4548 ret = false;
4551 return ret;
4554 static bool test_printer(struct torture_context *tctx,
4555 struct dcerpc_pipe *p)
4557 bool ret = true;
4558 struct policy_handle handle[2];
4559 bool found = false;
4560 const char *drivername = "Microsoft XPS Document Writer";
4561 const char *portname = "LPT1:";
4563 /* test printer created via AddPrinter */
4565 if (!test_AddPrinter(tctx, p, &handle[0], TORTURE_PRINTER, drivername, portname)) {
4566 return false;
4569 if (!test_one_printer(tctx, p, &handle[0], TORTURE_PRINTER)) {
4570 ret = false;
4573 if (!test_DeletePrinter(tctx, p, &handle[0])) {
4574 ret = false;
4577 if (!test_EnumPrinters_findname(tctx, p, PRINTER_ENUM_LOCAL, 1,
4578 TORTURE_PRINTER, &found)) {
4579 ret = false;
4582 torture_assert(tctx, !found, "deleted printer still there");
4584 /* test printer created via AddPrinterEx */
4586 if (!test_AddPrinterEx(tctx, p, &handle[1], TORTURE_PRINTER_EX, drivername, portname)) {
4587 return false;
4590 if (!test_one_printer(tctx, p, &handle[1], TORTURE_PRINTER_EX)) {
4591 ret = false;
4594 if (!test_DeletePrinter(tctx, p, &handle[1])) {
4595 ret = false;
4598 if (!test_EnumPrinters_findname(tctx, p, PRINTER_ENUM_LOCAL, 1,
4599 TORTURE_PRINTER_EX, &found)) {
4600 ret = false;
4603 torture_assert(tctx, !found, "deleted printer still there");
4605 return ret;
4608 static bool test_architecture_buffer(struct torture_context *tctx,
4609 struct dcerpc_pipe *p)
4611 struct spoolss_OpenPrinterEx r;
4612 struct spoolss_UserLevel1 u1;
4613 struct policy_handle handle;
4614 uint32_t architectures[] = {
4615 PROCESSOR_ARCHITECTURE_INTEL,
4616 PROCESSOR_ARCHITECTURE_IA64,
4617 PROCESSOR_ARCHITECTURE_AMD64
4619 uint32_t needed[3];
4620 int i;
4622 for (i=0; i < ARRAY_SIZE(architectures); i++) {
4624 torture_comment(tctx, "Testing OpenPrinterEx with architecture %d\n", architectures[i]);
4626 u1.size = 0;
4627 u1.client = NULL;
4628 u1.user = NULL;
4629 u1.build = 0;
4630 u1.major = 3;
4631 u1.minor = 0;
4632 u1.processor = architectures[i];
4634 r.in.printername = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
4635 r.in.datatype = NULL;
4636 r.in.devmode_ctr.devmode= NULL;
4637 r.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
4638 r.in.level = 1;
4639 r.in.userlevel.level1 = &u1;
4640 r.out.handle = &handle;
4642 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_OpenPrinterEx(p, tctx, &r), "");
4643 torture_assert_werr_ok(tctx, r.out.result, "");
4646 struct spoolss_EnumPrinters e;
4647 uint32_t count;
4648 union spoolss_PrinterInfo *info;
4650 e.in.flags = PRINTER_ENUM_LOCAL;
4651 e.in.server = NULL;
4652 e.in.level = 2;
4653 e.in.buffer = NULL;
4654 e.in.offered = 0;
4655 e.out.count = &count;
4656 e.out.info = &info;
4657 e.out.needed = &needed[i];
4659 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_EnumPrinters(p, tctx, &e), "");
4660 #if 0
4661 torture_comment(tctx, "needed was %d\n", needed[i]);
4662 #endif
4665 torture_assert(tctx, test_ClosePrinter(tctx, p, &handle), "");
4668 for (i=1; i < ARRAY_SIZE(architectures); i++) {
4669 if (needed[i-1] != needed[i]) {
4670 torture_fail(tctx,
4671 talloc_asprintf(tctx, "needed size %d for architecture %d != needed size %d for architecture %d\n",
4672 needed[i-1], architectures[i-1], needed[i], architectures[i]));
4676 return true;
4679 bool torture_rpc_spoolss(struct torture_context *torture)
4681 NTSTATUS status;
4682 struct dcerpc_pipe *p;
4683 bool ret = true;
4684 struct test_spoolss_context *ctx;
4685 const char *environment = SPOOLSS_ARCHITECTURE_NT_X86;
4687 status = torture_rpc_connection(torture, &p, &ndr_table_spoolss);
4688 if (!NT_STATUS_IS_OK(status)) {
4689 return false;
4692 ctx = talloc_zero(torture, struct test_spoolss_context);
4694 ret &= test_OpenPrinter_server(torture, p, &ctx->server_handle);
4695 ret &= test_GetPrinterData_list(torture, p, &ctx->server_handle);
4696 ret &= test_EnumForms(torture, p, &ctx->server_handle, true);
4697 ret &= test_AddForm(torture, p, &ctx->server_handle, true);
4698 ret &= test_EnumPorts(torture, p, ctx);
4699 ret &= test_GetPrinterDriverDirectory(torture, p, ctx, environment);
4700 ret &= test_GetPrintProcessorDirectory(torture, p, ctx, environment);
4701 ret &= test_EnumPrinterDrivers(torture, p, ctx, environment);
4702 ret &= test_EnumPrinterDrivers(torture, p, ctx, SPOOLSS_ARCHITECTURE_ALL);
4703 ret &= test_EnumMonitors(torture, p, ctx);
4704 ret &= test_EnumPrintProcessors(torture, p, ctx, environment);
4705 ret &= test_EnumPrintProcDataTypes(torture, p, ctx);
4706 ret &= test_EnumPrinters(torture, p, ctx);
4707 ret &= test_OpenPrinter_badname(torture, p, "__INVALID_PRINTER__");
4708 ret &= test_OpenPrinter_badname(torture, p, "\\\\__INVALID_HOST__");
4709 ret &= test_OpenPrinter_badname(torture, p, "");
4710 ret &= test_OpenPrinter_badname(torture, p, "\\\\\\");
4711 ret &= test_OpenPrinter_badname(torture, p, "\\\\\\__INVALID_PRINTER__");
4712 ret &= test_OpenPrinter_badname(torture, p, talloc_asprintf(torture, "\\\\%s\\", dcerpc_server_name(p)));
4713 ret &= test_OpenPrinter_badname(torture, p,
4714 talloc_asprintf(torture, "\\\\%s\\__INVALID_PRINTER__", dcerpc_server_name(p)));
4717 ret &= test_AddPort(torture, p);
4718 ret &= test_EnumPorts_old(torture, p);
4719 ret &= test_EnumPrinters_old(torture, p, environment);
4720 ret &= test_EnumPrinterDrivers_old(torture, p, environment);
4721 ret &= test_architecture_buffer(torture, p);
4723 return ret;
4726 struct torture_suite *torture_rpc_spoolss_printer(TALLOC_CTX *mem_ctx)
4728 struct torture_suite *suite = torture_suite_create(mem_ctx, "SPOOLSS-PRINTER");
4730 struct torture_rpc_tcase *tcase = torture_suite_add_rpc_iface_tcase(suite,
4731 "printer", &ndr_table_spoolss);
4733 torture_rpc_tcase_add_test(tcase, "printer", test_printer);
4735 return suite;