s4-smbtorture: add stricter SetPrinterDataEx tests to spoolss tests.
[Samba/cd1.git] / source4 / torture / rpc / spoolss.c
blob2b4d9480614a8df5fb980e15704c2627a3d1d362
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"
33 #include "lib/registry/registry.h"
35 #define TORTURE_WELLKNOWN_PRINTER "torture_wkn_printer"
36 #define TORTURE_PRINTER "torture_printer"
37 #define TORTURE_WELLKNOWN_PRINTER_EX "torture_wkn_printer_ex"
38 #define TORTURE_PRINTER_EX "torture_printer_ex"
40 struct test_spoolss_context {
41 /* print server handle */
42 struct policy_handle server_handle;
44 /* for EnumPorts */
45 uint32_t port_count[3];
46 union spoolss_PortInfo *ports[3];
48 /* for EnumPrinterDrivers */
49 uint32_t driver_count[8];
50 union spoolss_DriverInfo *drivers[8];
52 /* for EnumMonitors */
53 uint32_t monitor_count[3];
54 union spoolss_MonitorInfo *monitors[3];
56 /* for EnumPrintProcessors */
57 uint32_t print_processor_count[2];
58 union spoolss_PrintProcessorInfo *print_processors[2];
60 /* for EnumPrinters */
61 uint32_t printer_count[6];
62 union spoolss_PrinterInfo *printers[6];
65 #define COMPARE_STRING(tctx, c,r,e) \
66 torture_assert_str_equal(tctx, c.e, r.e, "invalid value")
68 /* not every compiler supports __typeof__() */
69 #if (__GNUC__ >= 3)
70 #define _CHECK_FIELD_SIZE(c,r,e,type) do {\
71 if (sizeof(__typeof__(c.e)) != sizeof(type)) { \
72 torture_fail(tctx, #c "." #e "field is not " #type "\n"); \
74 if (sizeof(__typeof__(r.e)) != sizeof(type)) { \
75 torture_fail(tctx, #r "." #e "field is not " #type "\n"); \
77 } while(0)
78 #else
79 #define _CHECK_FIELD_SIZE(c,r,e,type) do {} while(0)
80 #endif
82 #define COMPARE_UINT32(tctx, c, r, e) do {\
83 _CHECK_FIELD_SIZE(c, r, e, uint32_t); \
84 torture_assert_int_equal(tctx, c.e, r.e, "invalid value"); \
85 } while(0)
87 #define COMPARE_UINT64(tctx, c, r, e) do {\
88 _CHECK_FIELD_SIZE(c, r, e, uint64_t); \
89 torture_assert_int_equal(tctx, c.e, r.e, "invalid value"); \
90 } while(0)
93 #define COMPARE_NTTIME(tctx, c, r, e) do {\
94 _CHECK_FIELD_SIZE(c, r, e, NTTIME); \
95 torture_assert_int_equal(tctx, c.e, r.e, "invalid value"); \
96 } while(0)
98 #define COMPARE_STRING_ARRAY(tctx, c,r,e) do {\
99 int __i; \
100 if (!c.e && !r.e) { \
101 break; \
103 if (c.e && !r.e) { \
104 torture_fail(tctx, #r "." #e " field is NULL and " #c "." #e " is not\n"); \
106 if (!c.e && r.e) { \
107 torture_fail(tctx, #c "." #e " field is NULL and " #r "." #e " is not\n"); \
109 for (__i=0;c.e[__i] != NULL; __i++) { \
110 torture_assert_str_equal(tctx, c.e[__i], r.e[__i], "invalid value"); \
112 } while(0)
114 #define CHECK_ALIGN(size, n) do {\
115 if (size % n) {\
116 torture_warning(tctx, "%d is *NOT* %d byte aligned, should be %d",\
117 size, n, size + n - (size % n));\
119 } while(0)
121 #define DO_ROUND(size, n) (((size)+((n)-1)) & ~((n)-1))
123 #define CHECK_NEEDED_SIZE_ENUM_LEVEL(fn, info, level, count, ic, needed, align) do { \
124 if (torture_setting_bool(tctx, "spoolss_check_size", false)) {\
125 uint32_t size = ndr_size_##fn##_info(tctx, ic, level, count, info);\
126 uint32_t round_size = DO_ROUND(size, align);\
127 if (round_size != needed) {\
128 torture_warning(tctx, __location__": "#fn" level %d (count: %d) got unexpected needed size: %d, we calculated: %d", level, count, needed, round_size);\
129 CHECK_ALIGN(size, align);\
132 } while(0)
134 #define CHECK_NEEDED_SIZE_ENUM(fn, info, count, ic, needed, align) do { \
135 if (torture_setting_bool(tctx, "spoolss_check_size", false)) {\
136 uint32_t size = ndr_size_##fn##_info(tctx, ic, count, info);\
137 uint32_t round_size = DO_ROUND(size, align);\
138 if (round_size != needed) {\
139 torture_warning(tctx, __location__": "#fn" (count: %d) got unexpected needed size: %d, we calculated: %d", count, needed, round_size);\
140 CHECK_ALIGN(size, align);\
143 } while(0)
145 #define CHECK_NEEDED_SIZE_LEVEL(fn, info, level, ic, needed, align) do { \
146 if (torture_setting_bool(tctx, "spoolss_check_size", false)) {\
147 uint32_t size = ndr_size_##fn(info, level, ic, 0);\
148 uint32_t round_size = DO_ROUND(size, align);\
149 if (round_size != needed) {\
150 torture_warning(tctx, __location__": "#fn" level %d got unexpected needed size: %d, we calculated: %d", level, needed, round_size);\
151 CHECK_ALIGN(size, align);\
154 } while(0)
156 static bool test_OpenPrinter_server(struct torture_context *tctx,
157 struct dcerpc_pipe *p,
158 struct policy_handle *server_handle)
160 NTSTATUS status;
161 struct spoolss_OpenPrinter op;
163 op.in.printername = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
164 op.in.datatype = NULL;
165 op.in.devmode_ctr.devmode= NULL;
166 op.in.access_mask = 0;
167 op.out.handle = server_handle;
169 torture_comment(tctx, "Testing OpenPrinter(%s)\n", op.in.printername);
171 status = dcerpc_spoolss_OpenPrinter(p, tctx, &op);
172 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_OpenPrinter failed");
173 torture_assert_werr_ok(tctx, op.out.result, "dcerpc_spoolss_OpenPrinter failed");
175 return true;
178 static bool test_EnumPorts(struct torture_context *tctx,
179 struct dcerpc_pipe *p,
180 struct test_spoolss_context *ctx)
182 NTSTATUS status;
183 struct spoolss_EnumPorts r;
184 uint16_t levels[] = { 1, 2 };
185 int i, j;
187 for (i=0;i<ARRAY_SIZE(levels);i++) {
188 int level = levels[i];
189 DATA_BLOB blob;
190 uint32_t needed;
191 uint32_t count;
192 union spoolss_PortInfo *info;
194 r.in.servername = "";
195 r.in.level = level;
196 r.in.buffer = NULL;
197 r.in.offered = 0;
198 r.out.needed = &needed;
199 r.out.count = &count;
200 r.out.info = &info;
202 torture_comment(tctx, "Testing EnumPorts level %u\n", r.in.level);
204 status = dcerpc_spoolss_EnumPorts(p, ctx, &r);
205 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EnumPorts failed");
206 if (W_ERROR_IS_OK(r.out.result)) {
207 /* TODO: do some more checks here */
208 continue;
210 torture_assert_werr_equal(tctx, r.out.result, WERR_INSUFFICIENT_BUFFER,
211 "EnumPorts unexpected return code");
213 blob = data_blob_talloc(ctx, NULL, needed);
214 data_blob_clear(&blob);
215 r.in.buffer = &blob;
216 r.in.offered = needed;
218 status = dcerpc_spoolss_EnumPorts(p, ctx, &r);
219 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EnumPorts failed");
221 torture_assert_werr_ok(tctx, r.out.result, "EnumPorts failed");
223 torture_assert(tctx, info, "EnumPorts returned no info");
225 CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumPorts, info, r.in.level, count, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
227 ctx->port_count[level] = count;
228 ctx->ports[level] = info;
231 for (i=1;i<ARRAY_SIZE(levels);i++) {
232 int level = levels[i];
233 int old_level = levels[i-1];
234 torture_assert_int_equal(tctx, ctx->port_count[level], ctx->port_count[old_level],
235 "EnumPorts invalid value");
237 /* if the array sizes are not the same we would maybe segfault in the following code */
239 for (i=0;i<ARRAY_SIZE(levels);i++) {
240 int level = levels[i];
241 for (j=0;j<ctx->port_count[level];j++) {
242 union spoolss_PortInfo *cur = &ctx->ports[level][j];
243 union spoolss_PortInfo *ref = &ctx->ports[2][j];
244 switch (level) {
245 case 1:
246 COMPARE_STRING(tctx, cur->info1, ref->info2, port_name);
247 break;
248 case 2:
249 /* level 2 is our reference, and it makes no sense to compare it to itself */
250 break;
255 return true;
258 static bool test_GetPrintProcessorDirectory(struct torture_context *tctx,
259 struct dcerpc_pipe *p,
260 struct test_spoolss_context *ctx,
261 const char *environment)
263 NTSTATUS status;
264 struct spoolss_GetPrintProcessorDirectory r;
265 struct {
266 uint16_t level;
267 const char *server;
268 } levels[] = {{
269 .level = 1,
270 .server = NULL
272 .level = 1,
273 .server = ""
275 .level = 78,
276 .server = ""
278 .level = 1,
279 .server = talloc_asprintf(ctx, "\\\\%s", dcerpc_server_name(p))
281 .level = 1024,
282 .server = talloc_asprintf(ctx, "\\\\%s", dcerpc_server_name(p))
285 int i;
286 uint32_t needed;
288 for (i=0;i<ARRAY_SIZE(levels);i++) {
289 int level = levels[i].level;
290 DATA_BLOB blob;
292 r.in.server = levels[i].server;
293 r.in.environment = environment;
294 r.in.level = level;
295 r.in.buffer = NULL;
296 r.in.offered = 0;
297 r.out.needed = &needed;
299 torture_comment(tctx, "Testing GetPrintProcessorDirectory level %u\n", r.in.level);
301 status = dcerpc_spoolss_GetPrintProcessorDirectory(p, ctx, &r);
302 torture_assert_ntstatus_ok(tctx, status,
303 "dcerpc_spoolss_GetPrintProcessorDirectory failed");
304 torture_assert_werr_equal(tctx, r.out.result, WERR_INSUFFICIENT_BUFFER,
305 "GetPrintProcessorDirectory unexpected return code");
307 blob = data_blob_talloc(ctx, NULL, needed);
308 data_blob_clear(&blob);
309 r.in.buffer = &blob;
310 r.in.offered = needed;
312 status = dcerpc_spoolss_GetPrintProcessorDirectory(p, ctx, &r);
313 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_GetPrintProcessorDirectory failed");
315 torture_assert_werr_ok(tctx, r.out.result, "GetPrintProcessorDirectory failed");
317 CHECK_NEEDED_SIZE_LEVEL(spoolss_PrintProcessorDirectoryInfo, r.out.info, r.in.level, lp_iconv_convenience(tctx->lp_ctx), needed, 2);
320 return true;
324 static bool test_GetPrinterDriverDirectory(struct torture_context *tctx,
325 struct dcerpc_pipe *p,
326 struct test_spoolss_context *ctx,
327 const char *environment)
329 NTSTATUS status;
330 struct spoolss_GetPrinterDriverDirectory r;
331 struct {
332 uint16_t level;
333 const char *server;
334 } levels[] = {{
335 .level = 1,
336 .server = NULL
338 .level = 1,
339 .server = ""
341 .level = 78,
342 .server = ""
344 .level = 1,
345 .server = talloc_asprintf(ctx, "\\\\%s", dcerpc_server_name(p))
347 .level = 1024,
348 .server = talloc_asprintf(ctx, "\\\\%s", dcerpc_server_name(p))
351 int i;
352 uint32_t needed;
354 for (i=0;i<ARRAY_SIZE(levels);i++) {
355 int level = levels[i].level;
356 DATA_BLOB blob;
358 r.in.server = levels[i].server;
359 r.in.environment = environment;
360 r.in.level = level;
361 r.in.buffer = NULL;
362 r.in.offered = 0;
363 r.out.needed = &needed;
365 torture_comment(tctx, "Testing GetPrinterDriverDirectory level %u\n", r.in.level);
367 status = dcerpc_spoolss_GetPrinterDriverDirectory(p, ctx, &r);
368 torture_assert_ntstatus_ok(tctx, status,
369 "dcerpc_spoolss_GetPrinterDriverDirectory failed");
370 torture_assert_werr_equal(tctx, r.out.result, WERR_INSUFFICIENT_BUFFER,
371 "GetPrinterDriverDirectory unexpected return code");
373 blob = data_blob_talloc(ctx, NULL, needed);
374 data_blob_clear(&blob);
375 r.in.buffer = &blob;
376 r.in.offered = needed;
378 status = dcerpc_spoolss_GetPrinterDriverDirectory(p, ctx, &r);
379 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_GetPrinterDriverDirectory failed");
381 torture_assert_werr_ok(tctx, r.out.result, "GetPrinterDriverDirectory failed");
383 CHECK_NEEDED_SIZE_LEVEL(spoolss_DriverDirectoryInfo, r.out.info, r.in.level, lp_iconv_convenience(tctx->lp_ctx), needed, 2);
386 return true;
389 static bool test_EnumPrinterDrivers(struct torture_context *tctx,
390 struct dcerpc_pipe *p,
391 struct test_spoolss_context *ctx,
392 const char *architecture)
394 NTSTATUS status;
395 struct spoolss_EnumPrinterDrivers r;
396 uint16_t levels[] = { 1, 2, 3, 4, 5, 6, 8 };
397 int i, j;
399 for (i=0;i<ARRAY_SIZE(levels);i++) {
400 int level = levels[i];
401 DATA_BLOB blob;
402 uint32_t needed;
403 uint32_t count;
404 union spoolss_DriverInfo *info;
406 /* FIXME: gd, come back and fix "" as server, and handle
407 * priority of returned error codes in torture test and samba 3
408 * server */
410 r.in.server = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
411 r.in.environment = architecture;
412 r.in.level = level;
413 r.in.buffer = NULL;
414 r.in.offered = 0;
415 r.out.needed = &needed;
416 r.out.count = &count;
417 r.out.info = &info;
419 torture_comment(tctx, "Testing EnumPrinterDrivers level %u (%s)\n", r.in.level, r.in.environment);
421 status = dcerpc_spoolss_EnumPrinterDrivers(p, ctx, &r);
422 torture_assert_ntstatus_ok(tctx, status,
423 "dcerpc_spoolss_EnumPrinterDrivers failed");
424 if (W_ERROR_IS_OK(r.out.result)) {
425 /* TODO: do some more checks here */
426 continue;
428 if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
429 blob = data_blob_talloc(ctx, NULL, needed);
430 data_blob_clear(&blob);
431 r.in.buffer = &blob;
432 r.in.offered = needed;
434 status = dcerpc_spoolss_EnumPrinterDrivers(p, ctx, &r);
435 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EnumPrinterDrivers failed");
438 torture_assert_werr_ok(tctx, r.out.result, "EnumPrinterDrivers failed");
440 CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumPrinterDrivers, info, r.in.level, count, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
442 ctx->driver_count[level] = count;
443 ctx->drivers[level] = info;
446 for (i=1;i<ARRAY_SIZE(levels);i++) {
447 int level = levels[i];
448 int old_level = levels[i-1];
450 torture_assert_int_equal(tctx, ctx->driver_count[level], ctx->driver_count[old_level],
451 "EnumPrinterDrivers invalid value");
454 for (i=0;i<ARRAY_SIZE(levels);i++) {
455 int level = levels[i];
457 for (j=0;j<ctx->driver_count[level];j++) {
458 union spoolss_DriverInfo *cur = &ctx->drivers[level][j];
459 union spoolss_DriverInfo *ref = &ctx->drivers[8][j];
461 switch (level) {
462 case 1:
463 COMPARE_STRING(tctx, cur->info1, ref->info8, driver_name);
464 break;
465 case 2:
466 COMPARE_UINT32(tctx, cur->info2, ref->info8, version);
467 COMPARE_STRING(tctx, cur->info2, ref->info8, driver_name);
468 COMPARE_STRING(tctx, cur->info2, ref->info8, architecture);
469 COMPARE_STRING(tctx, cur->info2, ref->info8, driver_path);
470 COMPARE_STRING(tctx, cur->info2, ref->info8, data_file);
471 COMPARE_STRING(tctx, cur->info2, ref->info8, config_file);
472 break;
473 case 3:
474 COMPARE_UINT32(tctx, cur->info3, ref->info8, version);
475 COMPARE_STRING(tctx, cur->info3, ref->info8, driver_name);
476 COMPARE_STRING(tctx, cur->info3, ref->info8, architecture);
477 COMPARE_STRING(tctx, cur->info3, ref->info8, driver_path);
478 COMPARE_STRING(tctx, cur->info3, ref->info8, data_file);
479 COMPARE_STRING(tctx, cur->info3, ref->info8, config_file);
480 COMPARE_STRING(tctx, cur->info3, ref->info8, help_file);
481 COMPARE_STRING_ARRAY(tctx, cur->info3, ref->info8, dependent_files);
482 COMPARE_STRING(tctx, cur->info3, ref->info8, monitor_name);
483 COMPARE_STRING(tctx, cur->info3, ref->info8, default_datatype);
484 break;
485 case 4:
486 COMPARE_UINT32(tctx, cur->info4, ref->info8, version);
487 COMPARE_STRING(tctx, cur->info4, ref->info8, driver_name);
488 COMPARE_STRING(tctx, cur->info4, ref->info8, architecture);
489 COMPARE_STRING(tctx, cur->info4, ref->info8, driver_path);
490 COMPARE_STRING(tctx, cur->info4, ref->info8, data_file);
491 COMPARE_STRING(tctx, cur->info4, ref->info8, config_file);
492 COMPARE_STRING(tctx, cur->info4, ref->info8, help_file);
493 COMPARE_STRING_ARRAY(tctx, cur->info4, ref->info8, dependent_files);
494 COMPARE_STRING(tctx, cur->info4, ref->info8, monitor_name);
495 COMPARE_STRING(tctx, cur->info4, ref->info8, default_datatype);
496 COMPARE_STRING_ARRAY(tctx, cur->info4, ref->info8, previous_names);
497 break;
498 case 5:
499 COMPARE_UINT32(tctx, cur->info5, ref->info8, version);
500 COMPARE_STRING(tctx, cur->info5, ref->info8, driver_name);
501 COMPARE_STRING(tctx, cur->info5, ref->info8, architecture);
502 COMPARE_STRING(tctx, cur->info5, ref->info8, driver_path);
503 COMPARE_STRING(tctx, cur->info5, ref->info8, data_file);
504 COMPARE_STRING(tctx, cur->info5, ref->info8, config_file);
505 /*COMPARE_UINT32(tctx, cur->info5, ref->info8, driver_attributes);*/
506 /*COMPARE_UINT32(tctx, cur->info5, ref->info8, config_version);*/
507 /*TODO: ! COMPARE_UINT32(tctx, cur->info5, ref->info8, driver_version); */
508 break;
509 case 6:
510 COMPARE_UINT32(tctx, cur->info6, ref->info8, version);
511 COMPARE_STRING(tctx, cur->info6, ref->info8, driver_name);
512 COMPARE_STRING(tctx, cur->info6, ref->info8, architecture);
513 COMPARE_STRING(tctx, cur->info6, ref->info8, driver_path);
514 COMPARE_STRING(tctx, cur->info6, ref->info8, data_file);
515 COMPARE_STRING(tctx, cur->info6, ref->info8, config_file);
516 COMPARE_STRING(tctx, cur->info6, ref->info8, help_file);
517 COMPARE_STRING_ARRAY(tctx, cur->info6, ref->info8, dependent_files);
518 COMPARE_STRING(tctx, cur->info6, ref->info8, monitor_name);
519 COMPARE_STRING(tctx, cur->info6, ref->info8, default_datatype);
520 COMPARE_STRING_ARRAY(tctx, cur->info6, ref->info8, previous_names);
521 COMPARE_NTTIME(tctx, cur->info6, ref->info8, driver_date);
522 COMPARE_UINT64(tctx, cur->info6, ref->info8, driver_version);
523 COMPARE_STRING(tctx, cur->info6, ref->info8, manufacturer_name);
524 COMPARE_STRING(tctx, cur->info6, ref->info8, manufacturer_url);
525 COMPARE_STRING(tctx, cur->info6, ref->info8, hardware_id);
526 COMPARE_STRING(tctx, cur->info6, ref->info8, provider);
527 break;
528 case 8:
529 /* level 8 is our reference, and it makes no sense to compare it to itself */
530 break;
535 return true;
538 static bool test_EnumMonitors(struct torture_context *tctx,
539 struct dcerpc_pipe *p,
540 struct test_spoolss_context *ctx)
542 NTSTATUS status;
543 struct spoolss_EnumMonitors r;
544 uint16_t levels[] = { 1, 2 };
545 int i, j;
547 for (i=0;i<ARRAY_SIZE(levels);i++) {
548 int level = levels[i];
549 DATA_BLOB blob;
550 uint32_t needed;
551 uint32_t count;
552 union spoolss_MonitorInfo *info;
554 r.in.servername = "";
555 r.in.level = level;
556 r.in.buffer = NULL;
557 r.in.offered = 0;
558 r.out.needed = &needed;
559 r.out.count = &count;
560 r.out.info = &info;
562 torture_comment(tctx, "Testing EnumMonitors level %u\n", r.in.level);
564 status = dcerpc_spoolss_EnumMonitors(p, ctx, &r);
565 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EnumMonitors failed");
566 if (W_ERROR_IS_OK(r.out.result)) {
567 /* TODO: do some more checks here */
568 continue;
570 torture_assert_werr_equal(tctx, r.out.result, WERR_INSUFFICIENT_BUFFER,
571 "EnumMonitors failed");
573 blob = data_blob_talloc(ctx, NULL, needed);
574 data_blob_clear(&blob);
575 r.in.buffer = &blob;
576 r.in.offered = needed;
578 status = dcerpc_spoolss_EnumMonitors(p, ctx, &r);
579 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EnumMonitors failed");
581 torture_assert_werr_ok(tctx, r.out.result, "EnumMonitors failed");
583 CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumMonitors, info, r.in.level, count, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
585 ctx->monitor_count[level] = count;
586 ctx->monitors[level] = info;
589 for (i=1;i<ARRAY_SIZE(levels);i++) {
590 int level = levels[i];
591 int old_level = levels[i-1];
592 torture_assert_int_equal(tctx, ctx->monitor_count[level], ctx->monitor_count[old_level],
593 "EnumMonitors invalid value");
596 for (i=0;i<ARRAY_SIZE(levels);i++) {
597 int level = levels[i];
598 for (j=0;j<ctx->monitor_count[level];j++) {
599 union spoolss_MonitorInfo *cur = &ctx->monitors[level][j];
600 union spoolss_MonitorInfo *ref = &ctx->monitors[2][j];
601 switch (level) {
602 case 1:
603 COMPARE_STRING(tctx, cur->info1, ref->info2, monitor_name);
604 break;
605 case 2:
606 /* level 2 is our reference, and it makes no sense to compare it to itself */
607 break;
612 return true;
615 static bool test_EnumPrintProcessors(struct torture_context *tctx,
616 struct dcerpc_pipe *p,
617 struct test_spoolss_context *ctx,
618 const char *environment)
620 NTSTATUS status;
621 struct spoolss_EnumPrintProcessors r;
622 uint16_t levels[] = { 1 };
623 int i, j;
625 for (i=0;i<ARRAY_SIZE(levels);i++) {
626 int level = levels[i];
627 DATA_BLOB blob;
628 uint32_t needed;
629 uint32_t count;
630 union spoolss_PrintProcessorInfo *info;
632 r.in.servername = "";
633 r.in.environment = environment;
634 r.in.level = level;
635 r.in.buffer = NULL;
636 r.in.offered = 0;
637 r.out.needed = &needed;
638 r.out.count = &count;
639 r.out.info = &info;
641 torture_comment(tctx, "Testing EnumPrintProcessors level %u\n", r.in.level);
643 status = dcerpc_spoolss_EnumPrintProcessors(p, ctx, &r);
644 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EnumPrintProcessors failed");
645 if (W_ERROR_IS_OK(r.out.result)) {
646 /* TODO: do some more checks here */
647 continue;
649 torture_assert_werr_equal(tctx, r.out.result, WERR_INSUFFICIENT_BUFFER,
650 "EnumPrintProcessors unexpected return code");
652 blob = data_blob_talloc(ctx, NULL, needed);
653 data_blob_clear(&blob);
654 r.in.buffer = &blob;
655 r.in.offered = needed;
657 status = dcerpc_spoolss_EnumPrintProcessors(p, ctx, &r);
658 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EnumPrintProcessors failed");
660 torture_assert_werr_ok(tctx, r.out.result, "EnumPrintProcessors failed");
662 CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumPrintProcessors, info, r.in.level, count, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
664 ctx->print_processor_count[level] = count;
665 ctx->print_processors[level] = info;
668 for (i=1;i<ARRAY_SIZE(levels);i++) {
669 int level = levels[i];
670 int old_level = levels[i-1];
671 torture_assert_int_equal(tctx, ctx->print_processor_count[level], ctx->print_processor_count[old_level],
672 "EnumPrintProcessors failed");
675 for (i=0;i<ARRAY_SIZE(levels);i++) {
676 int level = levels[i];
677 for (j=0;j<ctx->print_processor_count[level];j++) {
678 #if 0
679 union spoolss_PrintProcessorInfo *cur = &ctx->print_processors[level][j];
680 union spoolss_PrintProcessorInfo *ref = &ctx->print_processors[1][j];
681 #endif
682 switch (level) {
683 case 1:
684 /* level 1 is our reference, and it makes no sense to compare it to itself */
685 break;
690 return true;
693 static bool test_EnumPrintProcDataTypes(struct torture_context *tctx,
694 struct dcerpc_pipe *p,
695 struct test_spoolss_context *ctx)
697 NTSTATUS status;
698 struct spoolss_EnumPrintProcDataTypes r;
699 uint16_t levels[] = { 1 };
700 int i;
702 for (i=0;i<ARRAY_SIZE(levels);i++) {
703 int level = levels[i];
704 DATA_BLOB blob;
705 uint32_t needed;
706 uint32_t count;
707 union spoolss_PrintProcDataTypesInfo *info;
709 r.in.servername = "";
710 r.in.print_processor_name = "winprint";
711 r.in.level = level;
712 r.in.buffer = NULL;
713 r.in.offered = 0;
714 r.out.needed = &needed;
715 r.out.count = &count;
716 r.out.info = &info;
718 torture_comment(tctx, "Testing EnumPrintProcDataTypes level %u\n", r.in.level);
720 status = dcerpc_spoolss_EnumPrintProcDataTypes(p, ctx, &r);
721 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EnumPrintProcDataType failed");
722 if (W_ERROR_IS_OK(r.out.result)) {
723 /* TODO: do some more checks here */
724 continue;
726 torture_assert_werr_equal(tctx, r.out.result, WERR_INSUFFICIENT_BUFFER,
727 "EnumPrintProcDataTypes unexpected return code");
729 blob = data_blob_talloc(ctx, NULL, needed);
730 data_blob_clear(&blob);
731 r.in.buffer = &blob;
732 r.in.offered = needed;
734 status = dcerpc_spoolss_EnumPrintProcDataTypes(p, ctx, &r);
735 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EnumPrintProcDataTypes failed");
737 torture_assert_werr_ok(tctx, r.out.result, "EnumPrintProcDataTypes failed");
739 CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumPrintProcDataTypes, info, r.in.level, count, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
743 return true;
747 static bool test_EnumPrinters(struct torture_context *tctx,
748 struct dcerpc_pipe *p,
749 struct test_spoolss_context *ctx)
751 struct spoolss_EnumPrinters r;
752 NTSTATUS status;
753 uint16_t levels[] = { 0, 1, 2, 4, 5 };
754 int i, j;
756 for (i=0;i<ARRAY_SIZE(levels);i++) {
757 int level = levels[i];
758 DATA_BLOB blob;
759 uint32_t needed;
760 uint32_t count;
761 union spoolss_PrinterInfo *info;
763 r.in.flags = PRINTER_ENUM_LOCAL;
764 r.in.server = "";
765 r.in.level = level;
766 r.in.buffer = NULL;
767 r.in.offered = 0;
768 r.out.needed = &needed;
769 r.out.count = &count;
770 r.out.info = &info;
772 torture_comment(tctx, "Testing EnumPrinters level %u\n", r.in.level);
774 status = dcerpc_spoolss_EnumPrinters(p, ctx, &r);
775 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EnumPrinters failed");
776 if (W_ERROR_IS_OK(r.out.result)) {
777 /* TODO: do some more checks here */
778 continue;
780 torture_assert_werr_equal(tctx, r.out.result, WERR_INSUFFICIENT_BUFFER,
781 "EnumPrinters unexpected return code");
783 blob = data_blob_talloc(ctx, NULL, needed);
784 data_blob_clear(&blob);
785 r.in.buffer = &blob;
786 r.in.offered = needed;
788 status = dcerpc_spoolss_EnumPrinters(p, ctx, &r);
789 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EnumPrinters failed");
791 torture_assert_werr_ok(tctx, r.out.result, "EnumPrinters failed");
793 CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumPrinters, info, r.in.level, count, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
795 ctx->printer_count[level] = count;
796 ctx->printers[level] = info;
799 for (i=1;i<ARRAY_SIZE(levels);i++) {
800 int level = levels[i];
801 int old_level = levels[i-1];
802 torture_assert_int_equal(tctx, ctx->printer_count[level], ctx->printer_count[old_level],
803 "EnumPrinters invalid value");
806 for (i=0;i<ARRAY_SIZE(levels);i++) {
807 int level = levels[i];
808 for (j=0;j<ctx->printer_count[level];j++) {
809 union spoolss_PrinterInfo *cur = &ctx->printers[level][j];
810 union spoolss_PrinterInfo *ref = &ctx->printers[2][j];
811 switch (level) {
812 case 0:
813 COMPARE_STRING(tctx, cur->info0, ref->info2, printername);
814 COMPARE_STRING(tctx, cur->info0, ref->info2, servername);
815 COMPARE_UINT32(tctx, cur->info0, ref->info2, cjobs);
816 /*COMPARE_UINT32(tctx, cur->info0, ref->info2, total_jobs);
817 COMPARE_UINT32(tctx, cur->info0, ref->info2, total_bytes);
818 COMPARE_SPOOLSS_TIME(cur->info0, ref->info2, spoolss_Time time);
819 COMPARE_UINT32(tctx, cur->info0, ref->info2, global_counter);
820 COMPARE_UINT32(tctx, cur->info0, ref->info2, total_pages);
821 COMPARE_UINT32(tctx, cur->info0, ref->info2, version);
822 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown10);
823 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown11);
824 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown12);
825 COMPARE_UINT32(tctx, cur->info0, ref->info2, session_counter);
826 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown14);
827 COMPARE_UINT32(tctx, cur->info0, ref->info2, printer_errors);
828 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown16);
829 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown17);
830 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown18);
831 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown19);
832 COMPARE_UINT32(tctx, cur->info0, ref->info2, change_id);
833 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown21);*/
834 COMPARE_UINT32(tctx, cur->info0, ref->info2, status);
835 /*COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown23);
836 COMPARE_UINT32(tctx, cur->info0, ref->info2, c_setprinter);
837 COMPARE_UINT16(cur->info0, ref->info2, unknown25);
838 COMPARE_UINT16(cur->info0, ref->info2, unknown26);
839 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown27);
840 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown28);
841 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown29);*/
842 break;
843 case 1:
844 /*COMPARE_UINT32(tctx, cur->info1, ref->info2, flags);*/
845 /*COMPARE_STRING(tctx, cur->info1, ref->info2, name);*/
846 /*COMPARE_STRING(tctx, cur->info1, ref->info2, description);*/
847 COMPARE_STRING(tctx, cur->info1, ref->info2, comment);
848 break;
849 case 2:
850 /* level 2 is our reference, and it makes no sense to compare it to itself */
851 break;
852 case 4:
853 COMPARE_STRING(tctx, cur->info4, ref->info2, printername);
854 COMPARE_STRING(tctx, cur->info4, ref->info2, servername);
855 COMPARE_UINT32(tctx, cur->info4, ref->info2, attributes);
856 break;
857 case 5:
858 COMPARE_STRING(tctx, cur->info5, ref->info2, printername);
859 COMPARE_STRING(tctx, cur->info5, ref->info2, portname);
860 COMPARE_UINT32(tctx, cur->info5, ref->info2, attributes);
861 /*COMPARE_UINT32(tctx, cur->info5, ref->info2, device_not_selected_timeout);
862 COMPARE_UINT32(tctx, cur->info5, ref->info2, transmission_retry_timeout);*/
863 break;
868 /* TODO:
869 * - verify that the port of a printer was in the list returned by EnumPorts
872 return true;
875 static bool test_GetPrinterDriver2(struct torture_context *tctx,
876 struct dcerpc_pipe *p,
877 struct policy_handle *handle,
878 const char *driver_name,
879 const char *environment);
881 bool test_GetPrinter_level(struct torture_context *tctx,
882 struct dcerpc_pipe *p,
883 struct policy_handle *handle,
884 uint32_t level,
885 union spoolss_PrinterInfo *info)
887 struct spoolss_GetPrinter r;
888 uint32_t needed;
890 r.in.handle = handle;
891 r.in.level = level;
892 r.in.buffer = NULL;
893 r.in.offered = 0;
894 r.out.needed = &needed;
896 torture_comment(tctx, "Testing GetPrinter level %u\n", r.in.level);
898 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_GetPrinter(p, tctx, &r),
899 "GetPrinter failed");
901 if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
902 DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed);
903 data_blob_clear(&blob);
904 r.in.buffer = &blob;
905 r.in.offered = needed;
907 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_GetPrinter(p, tctx, &r),
908 "GetPrinter failed");
911 torture_assert_werr_ok(tctx, r.out.result, "GetPrinter failed");
913 CHECK_NEEDED_SIZE_LEVEL(spoolss_PrinterInfo, r.out.info, r.in.level, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
915 if (info && r.out.info) {
916 *info = *r.out.info;
919 return true;
923 static bool test_GetPrinter(struct torture_context *tctx,
924 struct dcerpc_pipe *p,
925 struct policy_handle *handle,
926 const char *environment)
928 uint32_t levels[] = {0, 1, 2, 3, 4, 5, 6, 7, 8};
929 int i;
931 for (i=0;i<ARRAY_SIZE(levels);i++) {
933 union spoolss_PrinterInfo info;
935 ZERO_STRUCT(info);
937 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, levels[i], &info),
938 "failed to call GetPrinter");
940 if ((levels[i] == 2) && info.info2.drivername && strlen(info.info2.drivername)) {
941 torture_assert(tctx,
942 test_GetPrinterDriver2(tctx, p, handle, info.info2.drivername, environment),
943 "failed to call test_GetPrinterDriver2");
947 return true;
950 static bool test_SetPrinter(struct torture_context *tctx,
951 struct dcerpc_pipe *p,
952 struct policy_handle *handle,
953 struct spoolss_SetPrinterInfoCtr *info_ctr,
954 struct spoolss_DevmodeContainer *devmode_ctr,
955 struct sec_desc_buf *secdesc_ctr,
956 enum spoolss_PrinterControl command)
958 struct spoolss_SetPrinter r;
960 r.in.handle = handle;
961 r.in.info_ctr = info_ctr;
962 r.in.devmode_ctr = devmode_ctr;
963 r.in.secdesc_ctr = secdesc_ctr;
964 r.in.command = command;
966 torture_comment(tctx, "Testing SetPrinter level %d\n", r.in.info_ctr->level);
968 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_SetPrinter(p, tctx, &r),
969 "failed to call SetPrinter");
970 torture_assert_werr_ok(tctx, r.out.result,
971 "failed to call SetPrinter");
973 return true;
976 static bool test_SetPrinter_errors(struct torture_context *tctx,
977 struct dcerpc_pipe *p,
978 struct policy_handle *handle)
980 struct spoolss_SetPrinter r;
981 uint16_t levels[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
982 int i;
984 struct spoolss_SetPrinterInfoCtr info_ctr;
985 struct spoolss_DevmodeContainer devmode_ctr;
986 struct sec_desc_buf secdesc_ctr;
988 info_ctr.level = 0;
989 info_ctr.info.info0 = NULL;
991 ZERO_STRUCT(devmode_ctr);
992 ZERO_STRUCT(secdesc_ctr);
994 r.in.handle = handle;
995 r.in.info_ctr = &info_ctr;
996 r.in.devmode_ctr = &devmode_ctr;
997 r.in.secdesc_ctr = &secdesc_ctr;
998 r.in.command = 0;
1000 torture_comment(tctx, "Testing SetPrinter all zero\n");
1002 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_SetPrinter(p, tctx, &r),
1003 "failed to call SetPrinter");
1004 torture_assert_werr_equal(tctx, r.out.result, WERR_INVALID_PARAM,
1005 "failed to call SetPrinter");
1007 again:
1008 for (i=0; i < ARRAY_SIZE(levels); i++) {
1010 struct spoolss_SetPrinterInfo0 info0;
1011 struct spoolss_SetPrinterInfo1 info1;
1012 struct spoolss_SetPrinterInfo2 info2;
1013 struct spoolss_SetPrinterInfo3 info3;
1014 struct spoolss_SetPrinterInfo4 info4;
1015 struct spoolss_SetPrinterInfo5 info5;
1016 struct spoolss_SetPrinterInfo6 info6;
1017 struct spoolss_SetPrinterInfo7 info7;
1018 struct spoolss_SetPrinterInfo8 info8;
1019 struct spoolss_SetPrinterInfo9 info9;
1022 info_ctr.level = levels[i];
1023 switch (levels[i]) {
1024 case 0:
1025 ZERO_STRUCT(info0);
1026 info_ctr.info.info0 = &info0;
1027 break;
1028 case 1:
1029 ZERO_STRUCT(info1);
1030 info_ctr.info.info1 = &info1;
1031 break;
1032 case 2:
1033 ZERO_STRUCT(info2);
1034 info_ctr.info.info2 = &info2;
1035 break;
1036 case 3:
1037 ZERO_STRUCT(info3);
1038 info_ctr.info.info3 = &info3;
1039 break;
1040 case 4:
1041 ZERO_STRUCT(info4);
1042 info_ctr.info.info4 = &info4;
1043 break;
1044 case 5:
1045 ZERO_STRUCT(info5);
1046 info_ctr.info.info5 = &info5;
1047 break;
1048 case 6:
1049 ZERO_STRUCT(info6);
1050 info_ctr.info.info6 = &info6;
1051 break;
1052 case 7:
1053 ZERO_STRUCT(info7);
1054 info_ctr.info.info7 = &info7;
1055 break;
1056 case 8:
1057 ZERO_STRUCT(info8);
1058 info_ctr.info.info8 = &info8;
1059 break;
1060 case 9:
1061 ZERO_STRUCT(info9);
1062 info_ctr.info.info9 = &info9;
1063 break;
1066 torture_comment(tctx, "Testing SetPrinter level %d, command %d\n",
1067 info_ctr.level, r.in.command);
1069 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_SetPrinter(p, tctx, &r),
1070 "failed to call SetPrinter");
1072 switch (r.in.command) {
1073 case SPOOLSS_PRINTER_CONTROL_UNPAUSE: /* 0 */
1074 /* is ignored for all levels other then 0 */
1075 if (info_ctr.level > 0) {
1076 /* ignored then */
1077 break;
1079 case SPOOLSS_PRINTER_CONTROL_PAUSE: /* 1 */
1080 case SPOOLSS_PRINTER_CONTROL_RESUME: /* 2 */
1081 case SPOOLSS_PRINTER_CONTROL_PURGE: /* 3 */
1082 if (info_ctr.level > 0) {
1083 /* is invalid for all levels other then 0 */
1084 torture_assert_werr_equal(tctx, r.out.result, WERR_INVALID_PRINTER_COMMAND,
1085 "unexpected error code returned");
1086 continue;
1087 } else {
1088 torture_assert_werr_ok(tctx, r.out.result,
1089 "failed to call SetPrinter with non 0 command");
1090 continue;
1092 break;
1094 case SPOOLSS_PRINTER_CONTROL_SET_STATUS: /* 4 */
1095 /* FIXME: gd needs further investigation */
1096 default:
1097 torture_assert_werr_equal(tctx, r.out.result, WERR_INVALID_PRINTER_COMMAND,
1098 "unexpected error code returned");
1099 continue;
1102 switch (info_ctr.level) {
1103 case 1:
1104 torture_assert_werr_equal(tctx, r.out.result, WERR_UNKNOWN_LEVEL,
1105 "unexpected error code returned");
1106 break;
1107 case 2:
1108 torture_assert_werr_equal(tctx, r.out.result, WERR_UNKNOWN_PRINTER_DRIVER,
1109 "unexpected error code returned");
1110 break;
1111 case 3:
1112 case 4:
1113 case 5:
1114 case 7:
1115 torture_assert_werr_equal(tctx, r.out.result, WERR_INVALID_PARAM,
1116 "unexpected error code returned");
1117 break;
1118 case 9:
1119 torture_assert_werr_equal(tctx, r.out.result, WERR_NOT_SUPPORTED,
1120 "unexpected error code returned");
1121 break;
1122 default:
1123 torture_assert_werr_ok(tctx, r.out.result,
1124 "failed to call SetPrinter");
1125 break;
1129 if (r.in.command < 5) {
1130 r.in.command++;
1131 goto again;
1134 return true;
1137 static void clear_info2(struct spoolss_SetPrinterInfoCtr *r)
1139 if ((r->level == 2) && (r->info.info2)) {
1140 r->info.info2->secdesc_ptr = 0;
1141 r->info.info2->devmode_ptr = 0;
1145 static bool test_PrinterInfo(struct torture_context *tctx,
1146 struct dcerpc_pipe *p,
1147 struct policy_handle *handle)
1149 NTSTATUS status;
1150 struct spoolss_SetPrinter s;
1151 struct spoolss_GetPrinter q;
1152 struct spoolss_GetPrinter q0;
1153 struct spoolss_SetPrinterInfoCtr info_ctr;
1154 union spoolss_PrinterInfo info;
1155 struct spoolss_DevmodeContainer devmode_ctr;
1156 struct sec_desc_buf secdesc_ctr;
1157 uint32_t needed;
1158 bool ret = true;
1159 int i;
1161 uint32_t status_list[] = {
1162 /* these do not stick
1163 PRINTER_STATUS_PAUSED,
1164 PRINTER_STATUS_ERROR,
1165 PRINTER_STATUS_PENDING_DELETION, */
1166 PRINTER_STATUS_PAPER_JAM,
1167 PRINTER_STATUS_PAPER_OUT,
1168 PRINTER_STATUS_MANUAL_FEED,
1169 PRINTER_STATUS_PAPER_PROBLEM,
1170 PRINTER_STATUS_OFFLINE,
1171 PRINTER_STATUS_IO_ACTIVE,
1172 PRINTER_STATUS_BUSY,
1173 PRINTER_STATUS_PRINTING,
1174 PRINTER_STATUS_OUTPUT_BIN_FULL,
1175 PRINTER_STATUS_NOT_AVAILABLE,
1176 PRINTER_STATUS_WAITING,
1177 PRINTER_STATUS_PROCESSING,
1178 PRINTER_STATUS_INITIALIZING,
1179 PRINTER_STATUS_WARMING_UP,
1180 PRINTER_STATUS_TONER_LOW,
1181 PRINTER_STATUS_NO_TONER,
1182 PRINTER_STATUS_PAGE_PUNT,
1183 PRINTER_STATUS_USER_INTERVENTION,
1184 PRINTER_STATUS_OUT_OF_MEMORY,
1185 PRINTER_STATUS_DOOR_OPEN,
1186 PRINTER_STATUS_SERVER_UNKNOWN,
1187 PRINTER_STATUS_POWER_SAVE,
1188 /* these do not stick
1189 0x02000000,
1190 0x04000000,
1191 0x08000000,
1192 0x10000000,
1193 0x20000000,
1194 0x40000000,
1195 0x80000000 */
1197 uint32_t default_attribute = PRINTER_ATTRIBUTE_LOCAL;
1198 uint32_t attribute_list[] = {
1199 PRINTER_ATTRIBUTE_QUEUED,
1200 /* fails with WERR_INVALID_DATATYPE:
1201 PRINTER_ATTRIBUTE_DIRECT, */
1202 /* does not stick
1203 PRINTER_ATTRIBUTE_DEFAULT, */
1204 PRINTER_ATTRIBUTE_SHARED,
1205 /* does not stick
1206 PRINTER_ATTRIBUTE_NETWORK, */
1207 PRINTER_ATTRIBUTE_HIDDEN,
1208 PRINTER_ATTRIBUTE_LOCAL,
1209 PRINTER_ATTRIBUTE_ENABLE_DEVQ,
1210 PRINTER_ATTRIBUTE_KEEPPRINTEDJOBS,
1211 PRINTER_ATTRIBUTE_DO_COMPLETE_FIRST,
1212 PRINTER_ATTRIBUTE_WORK_OFFLINE,
1213 /* does not stick
1214 PRINTER_ATTRIBUTE_ENABLE_BIDI, */
1215 /* fails with WERR_INVALID_DATATYPE:
1216 PRINTER_ATTRIBUTE_RAW_ONLY, */
1217 /* these do not stick
1218 PRINTER_ATTRIBUTE_PUBLISHED,
1219 PRINTER_ATTRIBUTE_FAX,
1220 PRINTER_ATTRIBUTE_TS,
1221 0x00010000,
1222 0x00020000,
1223 0x00040000,
1224 0x00080000,
1225 0x00100000,
1226 0x00200000,
1227 0x00400000,
1228 0x00800000,
1229 0x01000000,
1230 0x02000000,
1231 0x04000000,
1232 0x08000000,
1233 0x10000000,
1234 0x20000000,
1235 0x40000000,
1236 0x80000000 */
1239 ZERO_STRUCT(devmode_ctr);
1240 ZERO_STRUCT(secdesc_ctr);
1242 s.in.handle = handle;
1243 s.in.command = 0;
1244 s.in.info_ctr = &info_ctr;
1245 s.in.devmode_ctr = &devmode_ctr;
1246 s.in.secdesc_ctr = &secdesc_ctr;
1248 q.in.handle = handle;
1249 q.out.info = &info;
1250 q0 = q;
1252 #define TESTGETCALL(call, r) \
1253 r.in.buffer = NULL; \
1254 r.in.offered = 0;\
1255 r.out.needed = &needed; \
1256 status = dcerpc_spoolss_ ##call(p, tctx, &r); \
1257 if (!NT_STATUS_IS_OK(status)) { \
1258 torture_comment(tctx, #call " level %u failed - %s (%s)\n", \
1259 r.in.level, nt_errstr(status), __location__); \
1260 ret = false; \
1261 break; \
1263 if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {\
1264 DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed); \
1265 data_blob_clear(&blob); \
1266 r.in.buffer = &blob; \
1267 r.in.offered = needed; \
1269 status = dcerpc_spoolss_ ##call(p, tctx, &r); \
1270 if (!NT_STATUS_IS_OK(status)) { \
1271 torture_comment(tctx, #call " level %u failed - %s (%s)\n", \
1272 r.in.level, nt_errstr(status), __location__); \
1273 ret = false; \
1274 break; \
1276 if (!W_ERROR_IS_OK(r.out.result)) { \
1277 torture_comment(tctx, #call " level %u failed - %s (%s)\n", \
1278 r.in.level, win_errstr(r.out.result), __location__); \
1279 ret = false; \
1280 break; \
1284 #define TESTSETCALL_EXP(call, r, err) \
1285 clear_info2(&info_ctr);\
1286 status = dcerpc_spoolss_ ##call(p, tctx, &r); \
1287 if (!NT_STATUS_IS_OK(status)) { \
1288 torture_comment(tctx, #call " level %u failed - %s (%s)\n", \
1289 r.in.info_ctr->level, nt_errstr(status), __location__); \
1290 ret = false; \
1291 break; \
1293 if (!W_ERROR_IS_OK(err)) { \
1294 if (!W_ERROR_EQUAL(err, r.out.result)) { \
1295 torture_comment(tctx, #call " level %u failed - %s, expected %s (%s)\n", \
1296 r.in.info_ctr->level, win_errstr(r.out.result), win_errstr(err), __location__); \
1297 ret = false; \
1299 break; \
1301 if (!W_ERROR_IS_OK(r.out.result)) { \
1302 torture_comment(tctx, #call " level %u failed - %s (%s)\n", \
1303 r.in.info_ctr->level, win_errstr(r.out.result), __location__); \
1304 ret = false; \
1305 break; \
1308 #define TESTSETCALL(call, r) \
1309 TESTSETCALL_EXP(call, r, WERR_OK)
1311 #define STRING_EQUAL(s1, s2, field) \
1312 if ((s1 && !s2) || (s2 && !s1) || strcmp(s1, s2)) { \
1313 torture_comment(tctx, "Failed to set %s to '%s' (%s)\n", \
1314 #field, s2, __location__); \
1315 ret = false; \
1316 break; \
1319 #define MEM_EQUAL(s1, s2, length, field) \
1320 if ((s1 && !s2) || (s2 && !s1) || memcmp(s1, s2, length)) { \
1321 torture_comment(tctx, "Failed to set %s to '%s' (%s)\n", \
1322 #field, (const char *)s2, __location__); \
1323 ret = false; \
1324 break; \
1327 #define INT_EQUAL(i1, i2, field) \
1328 if (i1 != i2) { \
1329 torture_comment(tctx, "Failed to set %s to 0x%llx - got 0x%llx (%s)\n", \
1330 #field, (unsigned long long)i2, (unsigned long long)i1, __location__); \
1331 ret = false; \
1332 break; \
1335 #define SD_EQUAL(sd1, sd2, field) \
1336 if (!security_descriptor_equal(sd1, sd2)) { \
1337 torture_comment(tctx, "Failed to set %s (%s)\n", \
1338 #field, __location__); \
1339 ret = false; \
1340 break; \
1343 #define TEST_PRINTERINFO_STRING_EXP_ERR(lvl1, field1, lvl2, field2, value, err) do { \
1344 torture_comment(tctx, "field test %d/%s vs %d/%s\n", lvl1, #field1, lvl2, #field2); \
1345 q.in.level = lvl1; \
1346 TESTGETCALL(GetPrinter, q) \
1347 info_ctr.level = lvl1; \
1348 info_ctr.info.info ## lvl1 = (struct spoolss_SetPrinterInfo ## lvl1 *)&q.out.info->info ## lvl1; \
1349 info_ctr.info.info ## lvl1->field1 = value;\
1350 TESTSETCALL_EXP(SetPrinter, s, err) \
1351 info_ctr.info.info ## lvl1->field1 = ""; \
1352 TESTGETCALL(GetPrinter, q) \
1353 info_ctr.info.info ## lvl1->field1 = value; \
1354 STRING_EQUAL(info_ctr.info.info ## lvl1->field1, value, field1); \
1355 q.in.level = lvl2; \
1356 TESTGETCALL(GetPrinter, q) \
1357 info_ctr.info.info ## lvl2 = (struct spoolss_SetPrinterInfo ## lvl2 *)&q.out.info->info ## lvl2; \
1358 STRING_EQUAL(info_ctr.info.info ## lvl2->field2, value, field2); \
1359 } while (0)
1361 #define TEST_PRINTERINFO_STRING(lvl1, field1, lvl2, field2, value) do { \
1362 TEST_PRINTERINFO_STRING_EXP_ERR(lvl1, field1, lvl2, field2, value, WERR_OK); \
1363 } while (0);
1365 #define TEST_PRINTERINFO_INT_EXP(lvl1, field1, lvl2, field2, value, exp_value) do { \
1366 torture_comment(tctx, "field test %d/%s vs %d/%s\n", lvl1, #field1, lvl2, #field2); \
1367 q.in.level = lvl1; \
1368 TESTGETCALL(GetPrinter, q) \
1369 info_ctr.level = lvl1; \
1370 info_ctr.info.info ## lvl1 = (struct spoolss_SetPrinterInfo ## lvl1 *)&q.out.info->info ## lvl1; \
1371 info_ctr.info.info ## lvl1->field1 = value; \
1372 TESTSETCALL(SetPrinter, s) \
1373 info_ctr.info.info ## lvl1->field1 = 0; \
1374 TESTGETCALL(GetPrinter, q) \
1375 info_ctr.info.info ## lvl1 = (struct spoolss_SetPrinterInfo ## lvl1 *)&q.out.info->info ## lvl1; \
1376 INT_EQUAL(info_ctr.info.info ## lvl1->field1, exp_value, field1); \
1377 q.in.level = lvl2; \
1378 TESTGETCALL(GetPrinter, q) \
1379 info_ctr.info.info ## lvl2 = (struct spoolss_SetPrinterInfo ## lvl2 *)&q.out.info->info ## lvl2; \
1380 INT_EQUAL(info_ctr.info.info ## lvl2->field2, exp_value, field1); \
1381 } while (0)
1383 #define TEST_PRINTERINFO_INT(lvl1, field1, lvl2, field2, value) do { \
1384 TEST_PRINTERINFO_INT_EXP(lvl1, field1, lvl2, field2, value, value); \
1385 } while (0)
1387 q0.in.level = 0;
1388 do { TESTGETCALL(GetPrinter, q0) } while (0);
1390 TEST_PRINTERINFO_STRING(2, comment, 1, comment, "xx2-1 comment");
1391 TEST_PRINTERINFO_STRING(2, comment, 2, comment, "xx2-2 comment");
1393 /* level 0 printername does not stick */
1394 /* TEST_PRINTERINFO_STRING(2, printername, 0, printername, "xx2-0 printer"); */
1395 TEST_PRINTERINFO_STRING(2, printername, 1, name, "xx2-1 printer");
1396 TEST_PRINTERINFO_STRING(2, printername, 2, printername, "xx2-2 printer");
1397 TEST_PRINTERINFO_STRING(2, printername, 4, printername, "xx2-4 printer");
1398 TEST_PRINTERINFO_STRING(2, printername, 5, printername, "xx2-5 printer");
1399 /* TEST_PRINTERINFO_STRING(4, printername, 0, printername, "xx4-0 printer"); */
1400 TEST_PRINTERINFO_STRING(4, printername, 1, name, "xx4-1 printer");
1401 TEST_PRINTERINFO_STRING(4, printername, 2, printername, "xx4-2 printer");
1402 TEST_PRINTERINFO_STRING(4, printername, 4, printername, "xx4-4 printer");
1403 TEST_PRINTERINFO_STRING(4, printername, 5, printername, "xx4-5 printer");
1404 /* TEST_PRINTERINFO_STRING(5, printername, 0, printername, "xx5-0 printer"); */
1405 TEST_PRINTERINFO_STRING(5, printername, 1, name, "xx5-1 printer");
1406 TEST_PRINTERINFO_STRING(5, printername, 2, printername, "xx5-2 printer");
1407 TEST_PRINTERINFO_STRING(5, printername, 4, printername, "xx5-4 printer");
1408 TEST_PRINTERINFO_STRING(5, printername, 5, printername, "xx5-5 printer");
1410 /* servername can be set but does not stick
1411 TEST_PRINTERINFO_STRING(2, servername, 0, servername, "xx2-0 servername");
1412 TEST_PRINTERINFO_STRING(2, servername, 2, servername, "xx2-2 servername");
1413 TEST_PRINTERINFO_STRING(2, servername, 4, servername, "xx2-4 servername");
1416 /* passing an invalid port will result in WERR_UNKNOWN_PORT */
1417 TEST_PRINTERINFO_STRING_EXP_ERR(2, portname, 2, portname, "xx2-2 portname", WERR_UNKNOWN_PORT);
1418 TEST_PRINTERINFO_STRING_EXP_ERR(2, portname, 5, portname, "xx2-5 portname", WERR_UNKNOWN_PORT);
1419 TEST_PRINTERINFO_STRING_EXP_ERR(5, portname, 2, portname, "xx5-2 portname", WERR_UNKNOWN_PORT);
1420 TEST_PRINTERINFO_STRING_EXP_ERR(5, portname, 5, portname, "xx5-5 portname", WERR_UNKNOWN_PORT);
1422 TEST_PRINTERINFO_STRING(2, sharename, 2, sharename, "xx2-2 sharename");
1423 /* passing an invalid driver will result in WERR_UNKNOWN_PRINTER_DRIVER */
1424 TEST_PRINTERINFO_STRING_EXP_ERR(2, drivername, 2, drivername, "xx2-2 drivername", WERR_UNKNOWN_PRINTER_DRIVER);
1425 TEST_PRINTERINFO_STRING(2, location, 2, location, "xx2-2 location");
1426 /* passing an invalid sepfile will result in WERR_INVALID_SEPARATOR_FILE */
1427 TEST_PRINTERINFO_STRING_EXP_ERR(2, sepfile, 2, sepfile, "xx2-2 sepfile", WERR_INVALID_SEPARATOR_FILE);
1428 /* passing an invalid printprocessor will result in WERR_UNKNOWN_PRINTPROCESSOR */
1429 TEST_PRINTERINFO_STRING_EXP_ERR(2, printprocessor, 2, printprocessor, "xx2-2 printprocessor", WERR_UNKNOWN_PRINTPROCESSOR);
1430 TEST_PRINTERINFO_STRING(2, datatype, 2, datatype, "xx2-2 datatype");
1431 TEST_PRINTERINFO_STRING(2, parameters, 2, parameters, "xx2-2 parameters");
1433 for (i=0; i < ARRAY_SIZE(attribute_list); i++) {
1434 /* TEST_PRINTERINFO_INT_EXP(2, attributes, 1, flags,
1435 attribute_list[i],
1436 (attribute_list[i] | default_attribute)
1437 ); */
1438 TEST_PRINTERINFO_INT_EXP(2, attributes, 2, attributes,
1439 attribute_list[i],
1440 (attribute_list[i] | default_attribute)
1442 TEST_PRINTERINFO_INT_EXP(2, attributes, 4, attributes,
1443 attribute_list[i],
1444 (attribute_list[i] | default_attribute)
1446 TEST_PRINTERINFO_INT_EXP(2, attributes, 5, attributes,
1447 attribute_list[i],
1448 (attribute_list[i] | default_attribute)
1450 /* TEST_PRINTERINFO_INT_EXP(4, attributes, 1, flags,
1451 attribute_list[i],
1452 (attribute_list[i] | default_attribute)
1453 ); */
1454 TEST_PRINTERINFO_INT_EXP(4, attributes, 2, attributes,
1455 attribute_list[i],
1456 (attribute_list[i] | default_attribute)
1458 TEST_PRINTERINFO_INT_EXP(4, attributes, 4, attributes,
1459 attribute_list[i],
1460 (attribute_list[i] | default_attribute)
1462 TEST_PRINTERINFO_INT_EXP(4, attributes, 5, attributes,
1463 attribute_list[i],
1464 (attribute_list[i] | default_attribute)
1466 /* TEST_PRINTERINFO_INT_EXP(5, attributes, 1, flags,
1467 attribute_list[i],
1468 (attribute_list[i] | default_attribute)
1469 ); */
1470 TEST_PRINTERINFO_INT_EXP(5, attributes, 2, attributes,
1471 attribute_list[i],
1472 (attribute_list[i] | default_attribute)
1474 TEST_PRINTERINFO_INT_EXP(5, attributes, 4, attributes,
1475 attribute_list[i],
1476 (attribute_list[i] | default_attribute)
1478 TEST_PRINTERINFO_INT_EXP(5, attributes, 5, attributes,
1479 attribute_list[i],
1480 (attribute_list[i] | default_attribute)
1484 for (i=0; i < ARRAY_SIZE(status_list); i++) {
1485 /* level 2 sets do not stick
1486 TEST_PRINTERINFO_INT(2, status, 0, status, status_list[i]);
1487 TEST_PRINTERINFO_INT(2, status, 2, status, status_list[i]);
1488 TEST_PRINTERINFO_INT(2, status, 6, status, status_list[i]); */
1489 TEST_PRINTERINFO_INT(6, status, 0, status, status_list[i]);
1490 TEST_PRINTERINFO_INT(6, status, 2, status, status_list[i]);
1491 TEST_PRINTERINFO_INT(6, status, 6, status, status_list[i]);
1494 /* priorities need to be between 0 and 99
1495 passing an invalid priority will result in WERR_INVALID_PRIORITY */
1496 TEST_PRINTERINFO_INT(2, priority, 2, priority, 0);
1497 TEST_PRINTERINFO_INT(2, priority, 2, priority, 1);
1498 TEST_PRINTERINFO_INT(2, priority, 2, priority, 99);
1499 /* TEST_PRINTERINFO_INT(2, priority, 2, priority, 100); */
1500 TEST_PRINTERINFO_INT(2, defaultpriority,2, defaultpriority, 0);
1501 TEST_PRINTERINFO_INT(2, defaultpriority,2, defaultpriority, 1);
1502 TEST_PRINTERINFO_INT(2, defaultpriority,2, defaultpriority, 99);
1503 /* TEST_PRINTERINFO_INT(2, defaultpriority,2, defaultpriority, 100); */
1505 TEST_PRINTERINFO_INT(2, starttime, 2, starttime, __LINE__);
1506 TEST_PRINTERINFO_INT(2, untiltime, 2, untiltime, __LINE__);
1508 /* does not stick
1509 TEST_PRINTERINFO_INT(2, cjobs, 2, cjobs, __LINE__);
1510 TEST_PRINTERINFO_INT(2, averageppm, 2, averageppm, __LINE__); */
1512 /* does not stick
1513 TEST_PRINTERINFO_INT(5, device_not_selected_timeout, 5, device_not_selected_timeout, __LINE__);
1514 TEST_PRINTERINFO_INT(5, transmission_retry_timeout, 5, transmission_retry_timeout, __LINE__); */
1516 /* FIXME: gd also test devmode and secdesc behavior */
1519 /* verify composition of level 1 description field */
1520 const char *description;
1521 const char *tmp;
1523 q0.in.level = 1;
1524 do { TESTGETCALL(GetPrinter, q0) } while (0);
1526 description = talloc_strdup(tctx, q0.out.info->info1.description);
1528 q0.in.level = 2;
1529 do { TESTGETCALL(GetPrinter, q0) } while (0);
1531 tmp = talloc_asprintf(tctx, "%s,%s,%s",
1532 q0.out.info->info2.printername,
1533 q0.out.info->info2.drivername,
1534 q0.out.info->info2.location);
1536 do { STRING_EQUAL(description, tmp, "description")} while (0);
1539 return ret;
1542 #define torture_assert_sid_equal(torture_ctx,got,expected,cmt)\
1543 do { struct dom_sid *__got = (got), *__expected = (expected); \
1544 if (!dom_sid_equal(__got, __expected)) { \
1545 torture_result(torture_ctx, TORTURE_FAIL, \
1546 __location__": "#got" was %s, expected %s: %s", \
1547 dom_sid_string(torture_ctx, __got), dom_sid_string(torture_ctx, __expected), cmt); \
1548 return false; \
1550 } while(0)
1552 static bool test_security_descriptor_equal(struct torture_context *tctx,
1553 const struct security_descriptor *sd1,
1554 const struct security_descriptor *sd2)
1556 if (sd1 == sd2) {
1557 return true;
1560 if (!sd1 || !sd2) {
1561 torture_comment(tctx, "%s\n", __location__);
1562 return false;
1565 torture_assert_int_equal(tctx, sd1->revision, sd2->revision, "revision mismatch");
1566 torture_assert_int_equal(tctx, sd1->type, sd2->type, "type mismatch");
1568 torture_assert_sid_equal(tctx, sd1->owner_sid, sd2->owner_sid, "owner mismatch");
1569 torture_assert_sid_equal(tctx, sd1->group_sid, sd2->group_sid, "group mismatch");
1571 if (!security_acl_equal(sd1->sacl, sd2->sacl)) {
1572 torture_comment(tctx, "%s: sacl mismatch\n", __location__);
1573 NDR_PRINT_DEBUG(security_acl, sd1->sacl);
1574 NDR_PRINT_DEBUG(security_acl, sd2->sacl);
1575 return false;
1577 if (!security_acl_equal(sd1->dacl, sd2->dacl)) {
1578 torture_comment(tctx, "%s: dacl mismatch\n", __location__);
1579 NDR_PRINT_DEBUG(security_acl, sd1->dacl);
1580 NDR_PRINT_DEBUG(security_acl, sd2->dacl);
1581 return false;
1584 return true;
1587 static bool test_sd_set_level(struct torture_context *tctx,
1588 struct dcerpc_pipe *p,
1589 struct policy_handle *handle,
1590 uint32_t level,
1591 struct security_descriptor *sd)
1593 struct spoolss_SetPrinterInfoCtr info_ctr;
1594 struct spoolss_DevmodeContainer devmode_ctr;
1595 struct sec_desc_buf secdesc_ctr;
1597 ZERO_STRUCT(devmode_ctr);
1598 ZERO_STRUCT(secdesc_ctr);
1600 switch (level) {
1601 case 2: {
1602 union spoolss_PrinterInfo info;
1603 struct spoolss_SetPrinterInfo2 info2;
1604 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 2, &info), "");
1606 info2.servername = info.info2.servername;
1607 info2.printername = info.info2.printername;
1608 info2.sharename = info.info2.sharename;
1609 info2.portname = info.info2.portname;
1610 info2.drivername = info.info2.drivername;
1611 info2.comment = info.info2.comment;
1612 info2.location = info.info2.location;
1613 info2.devmode_ptr = 0;
1614 info2.sepfile = info.info2.sepfile;
1615 info2.printprocessor = info.info2.printprocessor;
1616 info2.datatype = info.info2.datatype;
1617 info2.parameters = info.info2.parameters;
1618 info2.secdesc_ptr = 0;
1619 info2.attributes = info.info2.attributes;
1620 info2.priority = info.info2.priority;
1621 info2.defaultpriority = info.info2.defaultpriority;
1622 info2.starttime = info.info2.starttime;
1623 info2.untiltime = info.info2.untiltime;
1624 info2.status = info.info2.status;
1625 info2.cjobs = info.info2.cjobs;
1626 info2.averageppm = info.info2.averageppm;
1628 info_ctr.level = 2;
1629 info_ctr.info.info2 = &info2;
1631 break;
1633 case 3: {
1634 struct spoolss_SetPrinterInfo3 info3;
1636 info3.sec_desc_ptr = 0;
1638 info_ctr.level = 3;
1639 info_ctr.info.info3 = &info3;
1641 break;
1643 default:
1644 return false;
1647 secdesc_ctr.sd = sd;
1649 torture_assert(tctx,
1650 test_SetPrinter(tctx, p, handle, &info_ctr, &devmode_ctr, &secdesc_ctr, 0), "");
1652 return true;
1655 static bool test_PrinterInfo_SDs(struct torture_context *tctx,
1656 struct dcerpc_pipe *p,
1657 struct policy_handle *handle)
1659 union spoolss_PrinterInfo info;
1660 struct security_descriptor *sd1, *sd2;
1661 int i;
1663 /* just compare level 2 and level 3 */
1665 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 2, &info), "");
1667 sd1 = info.info2.secdesc;
1669 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 3, &info), "");
1671 sd2 = info.info3.secdesc;
1673 torture_assert(tctx, test_security_descriptor_equal(tctx, sd1, sd2),
1674 "SD level 2 != SD level 3");
1677 /* query level 2, set level 2, query level 2 */
1679 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 2, &info), "");
1681 sd1 = info.info2.secdesc;
1683 torture_assert(tctx, test_sd_set_level(tctx, p, handle, 2, sd1), "");
1685 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 2, &info), "");
1687 sd2 = info.info2.secdesc;
1688 if (sd1->type & SEC_DESC_DACL_DEFAULTED) {
1689 torture_comment(tctx, "removing SEC_DESC_DACL_DEFAULTED\n");
1690 sd1->type &= ~SEC_DESC_DACL_DEFAULTED;
1693 torture_assert(tctx, test_security_descriptor_equal(tctx, sd1, sd2),
1694 "SD level 2 != SD level 2 after SD has been set via level 2");
1697 /* query level 2, set level 3, query level 2 */
1699 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 2, &info), "");
1701 sd1 = info.info2.secdesc;
1703 torture_assert(tctx, test_sd_set_level(tctx, p, handle, 3, sd1), "");
1705 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 2, &info), "");
1707 sd2 = info.info2.secdesc;
1709 torture_assert(tctx, test_security_descriptor_equal(tctx, sd1, sd2),
1710 "SD level 2 != SD level 2 after SD has been set via level 3");
1712 /* set modified sd level 3, query level 2 */
1714 for (i=0; i < 93; i++) {
1715 struct security_ace a;
1716 const char *sid_string = talloc_asprintf(tctx, "S-1-5-32-9999%i", i);
1717 a.type = SEC_ACE_TYPE_ACCESS_ALLOWED;
1718 a.flags = 0;
1719 a.size = 0; /* autogenerated */
1720 a.access_mask = 0;
1721 a.trustee = *dom_sid_parse_talloc(tctx, sid_string);
1722 torture_assert_ntstatus_ok(tctx, security_descriptor_dacl_add(sd1, &a), "");
1725 torture_assert(tctx, test_sd_set_level(tctx, p, handle, 3, sd1), "");
1727 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 2, &info), "");
1728 sd2 = info.info2.secdesc;
1730 if (sd1->type & SEC_DESC_DACL_DEFAULTED) {
1731 torture_comment(tctx, "removing SEC_DESC_DACL_DEFAULTED\n");
1732 sd1->type &= ~SEC_DESC_DACL_DEFAULTED;
1735 torture_assert(tctx, test_security_descriptor_equal(tctx, sd1, sd2),
1736 "modified SD level 2 != SD level 2 after SD has been set via level 3");
1739 return true;
1743 * wrapper call that saves original sd, runs tests, and restores sd
1746 static bool test_PrinterInfo_SD(struct torture_context *tctx,
1747 struct dcerpc_pipe *p,
1748 struct policy_handle *handle)
1750 union spoolss_PrinterInfo info;
1751 struct security_descriptor *sd;
1752 bool ret = true;
1754 torture_comment(tctx, "\nTesting Printer Security Descriptors\n");
1756 /* save original sd */
1758 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 2, &info),
1759 "failed to get initial security descriptor");
1761 sd = security_descriptor_copy(tctx, info.info2.secdesc);
1763 /* run tests */
1765 ret = test_PrinterInfo_SDs(tctx, p, handle);
1767 /* restore original sd */
1769 torture_assert(tctx, test_sd_set_level(tctx, p, handle, 3, sd),
1770 "failed to restore initial security descriptor");
1772 torture_comment(tctx, "Printer Security Descriptors test %s\n",
1773 ret ? "succeeded" : "failed");
1776 return ret;
1779 static bool test_devmode_set_level(struct torture_context *tctx,
1780 struct dcerpc_pipe *p,
1781 struct policy_handle *handle,
1782 uint32_t level,
1783 struct spoolss_DeviceMode *devmode)
1785 struct spoolss_SetPrinterInfoCtr info_ctr;
1786 struct spoolss_DevmodeContainer devmode_ctr;
1787 struct sec_desc_buf secdesc_ctr;
1789 ZERO_STRUCT(devmode_ctr);
1790 ZERO_STRUCT(secdesc_ctr);
1792 switch (level) {
1793 case 2: {
1794 union spoolss_PrinterInfo info;
1795 struct spoolss_SetPrinterInfo2 info2;
1796 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 2, &info), "");
1798 info2.servername = info.info2.servername;
1799 info2.printername = info.info2.printername;
1800 info2.sharename = info.info2.sharename;
1801 info2.portname = info.info2.portname;
1802 info2.drivername = info.info2.drivername;
1803 info2.comment = info.info2.comment;
1804 info2.location = info.info2.location;
1805 info2.devmode_ptr = 0;
1806 info2.sepfile = info.info2.sepfile;
1807 info2.printprocessor = info.info2.printprocessor;
1808 info2.datatype = info.info2.datatype;
1809 info2.parameters = info.info2.parameters;
1810 info2.secdesc_ptr = 0;
1811 info2.attributes = info.info2.attributes;
1812 info2.priority = info.info2.priority;
1813 info2.defaultpriority = info.info2.defaultpriority;
1814 info2.starttime = info.info2.starttime;
1815 info2.untiltime = info.info2.untiltime;
1816 info2.status = info.info2.status;
1817 info2.cjobs = info.info2.cjobs;
1818 info2.averageppm = info.info2.averageppm;
1820 info_ctr.level = 2;
1821 info_ctr.info.info2 = &info2;
1823 break;
1825 case 8: {
1826 struct spoolss_SetPrinterInfo8 info8;
1828 info8.devmode_ptr = 0;
1830 info_ctr.level = 8;
1831 info_ctr.info.info8 = &info8;
1833 break;
1835 default:
1836 return false;
1839 devmode_ctr.devmode = devmode;
1841 torture_assert(tctx,
1842 test_SetPrinter(tctx, p, handle, &info_ctr, &devmode_ctr, &secdesc_ctr, 0), "");
1844 return true;
1848 static bool test_devicemode_equal(struct torture_context *tctx,
1849 const struct spoolss_DeviceMode *d1,
1850 const struct spoolss_DeviceMode *d2)
1852 if (d1 == d2) {
1853 return true;
1856 if (!d1 || !d2) {
1857 torture_comment(tctx, "%s\n", __location__);
1858 return false;
1860 torture_assert_str_equal(tctx, d1->devicename, d2->devicename, "devicename mismatch");
1861 torture_assert_int_equal(tctx, d1->specversion, d2->specversion, "specversion mismatch");
1862 torture_assert_int_equal(tctx, d1->driverversion, d2->driverversion, "driverversion mismatch");
1863 torture_assert_int_equal(tctx, d1->size, d2->size, "size mismatch");
1864 torture_assert_int_equal(tctx, d1->__driverextra_length, d2->__driverextra_length, "__driverextra_length mismatch");
1865 torture_assert_int_equal(tctx, d1->fields, d2->fields, "fields mismatch");
1866 torture_assert_int_equal(tctx, d1->orientation, d2->orientation, "orientation mismatch");
1867 torture_assert_int_equal(tctx, d1->papersize, d2->papersize, "papersize mismatch");
1868 torture_assert_int_equal(tctx, d1->paperlength, d2->paperlength, "paperlength mismatch");
1869 torture_assert_int_equal(tctx, d1->paperwidth, d2->paperwidth, "paperwidth mismatch");
1870 torture_assert_int_equal(tctx, d1->scale, d2->scale, "scale mismatch");
1871 torture_assert_int_equal(tctx, d1->copies, d2->copies, "copies mismatch");
1872 torture_assert_int_equal(tctx, d1->defaultsource, d2->defaultsource, "defaultsource mismatch");
1873 torture_assert_int_equal(tctx, d1->printquality, d2->printquality, "printquality mismatch");
1874 torture_assert_int_equal(tctx, d1->color, d2->color, "color mismatch");
1875 torture_assert_int_equal(tctx, d1->duplex, d2->duplex, "duplex mismatch");
1876 torture_assert_int_equal(tctx, d1->yresolution, d2->yresolution, "yresolution mismatch");
1877 torture_assert_int_equal(tctx, d1->ttoption, d2->ttoption, "ttoption mismatch");
1878 torture_assert_int_equal(tctx, d1->collate, d2->collate, "collate mismatch");
1879 torture_assert_str_equal(tctx, d1->formname, d2->formname, "formname mismatch");
1880 torture_assert_int_equal(tctx, d1->logpixels, d2->logpixels, "logpixels mismatch");
1881 torture_assert_int_equal(tctx, d1->bitsperpel, d2->bitsperpel, "bitsperpel mismatch");
1882 torture_assert_int_equal(tctx, d1->pelswidth, d2->pelswidth, "pelswidth mismatch");
1883 torture_assert_int_equal(tctx, d1->pelsheight, d2->pelsheight, "pelsheight mismatch");
1884 torture_assert_int_equal(tctx, d1->displayflags, d2->displayflags, "displayflags mismatch");
1885 torture_assert_int_equal(tctx, d1->displayfrequency, d2->displayfrequency, "displayfrequency mismatch");
1886 torture_assert_int_equal(tctx, d1->icmmethod, d2->icmmethod, "icmmethod mismatch");
1887 torture_assert_int_equal(tctx, d1->icmintent, d2->icmintent, "icmintent mismatch");
1888 torture_assert_int_equal(tctx, d1->mediatype, d2->mediatype, "mediatype mismatch");
1889 torture_assert_int_equal(tctx, d1->dithertype, d2->dithertype, "dithertype mismatch");
1890 torture_assert_int_equal(tctx, d1->reserved1, d2->reserved1, "reserved1 mismatch");
1891 torture_assert_int_equal(tctx, d1->reserved2, d2->reserved2, "reserved2 mismatch");
1892 torture_assert_int_equal(tctx, d1->panningwidth, d2->panningwidth, "panningwidth mismatch");
1893 torture_assert_int_equal(tctx, d1->panningheight, d2->panningheight, "panningheight mismatch");
1894 torture_assert_data_blob_equal(tctx, d1->driverextra_data, d2->driverextra_data, "driverextra_data mismatch");
1896 return true;
1899 static bool test_devicemode_full(struct torture_context *tctx,
1900 struct dcerpc_pipe *p,
1901 struct policy_handle *handle)
1903 struct spoolss_SetPrinter s;
1904 struct spoolss_GetPrinter q;
1905 struct spoolss_GetPrinter q0;
1906 struct spoolss_SetPrinterInfoCtr info_ctr;
1907 struct spoolss_SetPrinterInfo8 info8;
1908 union spoolss_PrinterInfo info;
1909 struct spoolss_DevmodeContainer devmode_ctr;
1910 struct sec_desc_buf secdesc_ctr;
1911 uint32_t needed;
1912 bool ret = true;
1913 NTSTATUS status;
1915 #define TEST_DEVMODE_INT_EXP(lvl1, field1, lvl2, field2, value, exp_value) do { \
1916 torture_comment(tctx, "field test %d/%s vs %d/%s\n", lvl1, #field1, lvl2, #field2); \
1917 q.in.level = lvl1; \
1918 TESTGETCALL(GetPrinter, q) \
1919 info_ctr.level = lvl1; \
1920 if (lvl1 == 2) {\
1921 info_ctr.info.info ## lvl1 = (struct spoolss_SetPrinterInfo ## lvl1 *)&q.out.info->info ## lvl1; \
1922 } else if (lvl1 == 8) {\
1923 info_ctr.info.info ## lvl1 = &info8; \
1925 devmode_ctr.devmode = q.out.info->info ## lvl1.devmode; \
1926 devmode_ctr.devmode->field1 = value; \
1927 TESTSETCALL(SetPrinter, s) \
1928 TESTGETCALL(GetPrinter, q) \
1929 INT_EQUAL(q.out.info->info ## lvl1.devmode->field1, exp_value, field1); \
1930 q.in.level = lvl2; \
1931 TESTGETCALL(GetPrinter, q) \
1932 INT_EQUAL(q.out.info->info ## lvl2.devmode->field2, exp_value, field1); \
1933 } while (0)
1935 #define TEST_DEVMODE_INT(lvl1, field1, lvl2, field2, value) do { \
1936 TEST_DEVMODE_INT_EXP(lvl1, field1, lvl2, field2, value, value); \
1937 } while (0)
1939 ZERO_STRUCT(devmode_ctr);
1940 ZERO_STRUCT(secdesc_ctr);
1941 ZERO_STRUCT(info8);
1943 s.in.handle = handle;
1944 s.in.command = 0;
1945 s.in.info_ctr = &info_ctr;
1946 s.in.devmode_ctr = &devmode_ctr;
1947 s.in.secdesc_ctr = &secdesc_ctr;
1949 q.in.handle = handle;
1950 q.out.info = &info;
1951 q0 = q;
1953 #if 0
1954 const char *devicename;/* [charset(UTF16)] */
1955 enum spoolss_DeviceModeSpecVersion specversion;
1956 uint16_t driverversion;
1957 uint16_t size;
1958 uint16_t __driverextra_length;/* [value(r->driverextra_data.length)] */
1959 uint32_t fields;
1960 #endif
1962 TEST_DEVMODE_INT(8, orientation, 8, orientation, __LINE__);
1963 TEST_DEVMODE_INT(8, papersize, 8, papersize, __LINE__);
1964 TEST_DEVMODE_INT(8, paperlength, 8, paperlength, __LINE__);
1965 TEST_DEVMODE_INT(8, paperwidth, 8, paperwidth, __LINE__);
1966 TEST_DEVMODE_INT(8, scale, 8, scale, __LINE__);
1967 TEST_DEVMODE_INT(8, copies, 8, copies, __LINE__);
1968 TEST_DEVMODE_INT(8, defaultsource, 8, defaultsource, __LINE__);
1969 TEST_DEVMODE_INT(8, printquality, 8, printquality, __LINE__);
1970 TEST_DEVMODE_INT(8, color, 8, color, __LINE__);
1971 TEST_DEVMODE_INT(8, duplex, 8, duplex, __LINE__);
1972 TEST_DEVMODE_INT(8, yresolution, 8, yresolution, __LINE__);
1973 TEST_DEVMODE_INT(8, ttoption, 8, ttoption, __LINE__);
1974 TEST_DEVMODE_INT(8, collate, 8, collate, __LINE__);
1975 #if 0
1976 const char *formname;/* [charset(UTF16)] */
1977 #endif
1978 TEST_DEVMODE_INT(8, logpixels, 8, logpixels, __LINE__);
1979 TEST_DEVMODE_INT(8, bitsperpel, 8, bitsperpel, __LINE__);
1980 TEST_DEVMODE_INT(8, pelswidth, 8, pelswidth, __LINE__);
1981 TEST_DEVMODE_INT(8, pelsheight, 8, pelsheight, __LINE__);
1982 TEST_DEVMODE_INT(8, displayflags, 8, displayflags, __LINE__);
1983 TEST_DEVMODE_INT(8, displayfrequency, 8, displayfrequency, __LINE__);
1984 TEST_DEVMODE_INT(8, icmmethod, 8, icmmethod, __LINE__);
1985 TEST_DEVMODE_INT(8, icmintent, 8, icmintent, __LINE__);
1986 TEST_DEVMODE_INT(8, mediatype, 8, mediatype, __LINE__);
1987 TEST_DEVMODE_INT(8, dithertype, 8, dithertype, __LINE__);
1988 TEST_DEVMODE_INT(8, reserved1, 8, reserved1, __LINE__);
1989 TEST_DEVMODE_INT(8, reserved2, 8, reserved2, __LINE__);
1990 TEST_DEVMODE_INT(8, panningwidth, 8, panningwidth, __LINE__);
1991 TEST_DEVMODE_INT(8, panningheight, 8, panningheight, __LINE__);
1993 return ret;
1996 static bool call_OpenPrinterEx(struct torture_context *tctx,
1997 struct dcerpc_pipe *p,
1998 const char *name,
1999 struct spoolss_DeviceMode *devmode,
2000 struct policy_handle *handle);
2002 static bool test_ClosePrinter(struct torture_context *tctx,
2003 struct dcerpc_pipe *p,
2004 struct policy_handle *handle);
2006 static bool test_PrinterInfo_DevModes(struct torture_context *tctx,
2007 struct dcerpc_pipe *p,
2008 struct policy_handle *handle,
2009 const char *name)
2011 union spoolss_PrinterInfo info;
2012 struct spoolss_DeviceMode *devmode;
2013 struct spoolss_DeviceMode *devmode2;
2014 struct policy_handle handle_devmode;
2016 /* simply compare level8 and level2 devmode */
2018 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 8, &info), "");
2020 devmode = info.info8.devmode;
2022 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 2, &info), "");
2024 devmode2 = info.info2.devmode;
2026 torture_assert(tctx, test_devicemode_equal(tctx, devmode, devmode2),
2027 "DM level 8 != DM level 2");
2030 /* set devicemode level 8 and see if it persists */
2032 devmode->copies = 93;
2033 devmode->formname = talloc_strdup(tctx, "Legal");
2035 torture_assert(tctx, test_devmode_set_level(tctx, p, handle, 8, devmode), "");
2037 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 8, &info), "");
2039 devmode2 = info.info8.devmode;
2041 torture_assert(tctx, test_devicemode_equal(tctx, devmode, devmode2),
2042 "modified DM level 8 != DM level 8 after DM has been set via level 8");
2044 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 2, &info), "");
2046 devmode2 = info.info2.devmode;
2048 torture_assert(tctx, test_devicemode_equal(tctx, devmode, devmode2),
2049 "modified DM level 8 != DM level 2");
2052 /* set devicemode level 2 and see if it persists */
2054 devmode->copies = 39;
2055 devmode->formname = talloc_strdup(tctx, "Executive");
2057 torture_assert(tctx, test_devmode_set_level(tctx, p, handle, 2, devmode), "");
2059 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 8, &info), "");
2061 devmode2 = info.info8.devmode;
2063 torture_assert(tctx, test_devicemode_equal(tctx, devmode, devmode2),
2064 "modified DM level 8 != DM level 8 after DM has been set via level 2");
2066 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 2, &info), "");
2068 devmode2 = info.info2.devmode;
2070 torture_assert(tctx, test_devicemode_equal(tctx, devmode, devmode2),
2071 "modified DM level 8 != DM level 2");
2074 /* check every single bit in public part of devicemode */
2076 torture_assert(tctx, test_devicemode_full(tctx, p, handle),
2077 "failed to set every single devicemode component");
2080 /* change formname upon open and see if it persists in getprinter calls */
2082 devmode->formname = talloc_strdup(tctx, "A4");
2083 devmode->copies = 42;
2085 torture_assert(tctx, call_OpenPrinterEx(tctx, p, name, devmode, &handle_devmode),
2086 "failed to open printer handle");
2088 torture_assert(tctx, test_GetPrinter_level(tctx, p, &handle_devmode, 8, &info), "");
2090 devmode2 = info.info8.devmode;
2092 if (strequal(devmode->devicename, devmode2->devicename)) {
2093 torture_comment(tctx, "devicenames are the same\n");
2094 } else {
2095 torture_comment(tctx, "devicename passed in for open: %s\n", devmode->devicename);
2096 torture_comment(tctx, "devicename after level 8 get: %s\n", devmode2->devicename);
2099 if (strequal(devmode->formname, devmode2->formname)) {
2100 torture_warning(tctx, "formname are the same\n");
2101 } else {
2102 torture_comment(tctx, "formname passed in for open: %s\n", devmode->formname);
2103 torture_comment(tctx, "formname after level 8 get: %s\n", devmode2->formname);
2106 if (devmode->copies == devmode2->copies) {
2107 torture_warning(tctx, "copies are the same\n");
2108 } else {
2109 torture_comment(tctx, "copies passed in for open: %d\n", devmode->copies);
2110 torture_comment(tctx, "copies after level 8 get: %d\n", devmode2->copies);
2113 torture_assert(tctx, test_GetPrinter_level(tctx, p, &handle_devmode, 2, &info), "");
2115 devmode2 = info.info2.devmode;
2117 if (strequal(devmode->devicename, devmode2->devicename)) {
2118 torture_comment(tctx, "devicenames are the same\n");
2119 } else {
2120 torture_comment(tctx, "devicename passed in for open: %s\n", devmode->devicename);
2121 torture_comment(tctx, "devicename after level 2 get: %s\n", devmode2->devicename);
2124 if (strequal(devmode->formname, devmode2->formname)) {
2125 torture_warning(tctx, "formname is the same\n");
2126 } else {
2127 torture_comment(tctx, "formname passed in for open: %s\n", devmode->formname);
2128 torture_comment(tctx, "formname after level 2 get: %s\n", devmode2->formname);
2131 if (devmode->copies == devmode2->copies) {
2132 torture_warning(tctx, "copies are the same\n");
2133 } else {
2134 torture_comment(tctx, "copies passed in for open: %d\n", devmode->copies);
2135 torture_comment(tctx, "copies after level 2 get: %d\n", devmode2->copies);
2138 test_ClosePrinter(tctx, p, &handle_devmode);
2140 return true;
2144 * wrapper call that saves original devmode, runs tests, and restores devmode
2147 static bool test_PrinterInfo_DevMode(struct torture_context *tctx,
2148 struct dcerpc_pipe *p,
2149 struct policy_handle *handle,
2150 const char *name)
2152 union spoolss_PrinterInfo info;
2153 struct spoolss_DeviceMode *devmode;
2154 bool ret = true;
2156 torture_comment(tctx, "\nTesting Printer Devicemodes\n");
2158 /* save original devmode */
2160 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 8, &info),
2161 "failed to get initial global devicemode");
2163 devmode = info.info8.devmode;
2165 /* run tests */
2167 ret = test_PrinterInfo_DevModes(tctx, p, handle, name);
2169 /* restore original devmode */
2171 torture_assert(tctx, test_devmode_set_level(tctx, p, handle, 8, devmode),
2172 "failed to restore initial global device mode");
2174 torture_comment(tctx, "Printer Devicemodes test %s\n",
2175 ret ? "succeeded" : "failed");
2178 return ret;
2181 static bool test_ClosePrinter(struct torture_context *tctx,
2182 struct dcerpc_pipe *p,
2183 struct policy_handle *handle)
2185 NTSTATUS status;
2186 struct spoolss_ClosePrinter r;
2188 r.in.handle = handle;
2189 r.out.handle = handle;
2191 torture_comment(tctx, "Testing ClosePrinter\n");
2193 status = dcerpc_spoolss_ClosePrinter(p, tctx, &r);
2194 torture_assert_ntstatus_ok(tctx, status, "ClosePrinter failed");
2195 torture_assert_werr_ok(tctx, r.out.result, "ClosePrinter failed");
2197 return true;
2200 static bool test_GetForm(struct torture_context *tctx,
2201 struct dcerpc_pipe *p,
2202 struct policy_handle *handle,
2203 const char *form_name,
2204 uint32_t level)
2206 NTSTATUS status;
2207 struct spoolss_GetForm r;
2208 uint32_t needed;
2210 r.in.handle = handle;
2211 r.in.form_name = form_name;
2212 r.in.level = level;
2213 r.in.buffer = NULL;
2214 r.in.offered = 0;
2215 r.out.needed = &needed;
2217 torture_comment(tctx, "Testing GetForm level %d\n", r.in.level);
2219 status = dcerpc_spoolss_GetForm(p, tctx, &r);
2220 torture_assert_ntstatus_ok(tctx, status, "GetForm failed");
2222 if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
2223 DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed);
2224 data_blob_clear(&blob);
2225 r.in.buffer = &blob;
2226 r.in.offered = needed;
2227 status = dcerpc_spoolss_GetForm(p, tctx, &r);
2228 torture_assert_ntstatus_ok(tctx, status, "GetForm failed");
2230 torture_assert_werr_ok(tctx, r.out.result, "GetForm failed");
2232 torture_assert(tctx, r.out.info, "No form info returned");
2235 torture_assert_werr_ok(tctx, r.out.result, "GetForm failed");
2237 CHECK_NEEDED_SIZE_LEVEL(spoolss_FormInfo, r.out.info, r.in.level, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
2239 return true;
2242 static bool test_EnumForms(struct torture_context *tctx,
2243 struct dcerpc_pipe *p,
2244 struct policy_handle *handle, bool print_server)
2246 NTSTATUS status;
2247 struct spoolss_EnumForms r;
2248 bool ret = true;
2249 uint32_t needed;
2250 uint32_t count;
2251 uint32_t levels[] = { 1, 2 };
2252 int i;
2254 for (i=0; i<ARRAY_SIZE(levels); i++) {
2256 union spoolss_FormInfo *info;
2258 r.in.handle = handle;
2259 r.in.level = levels[i];
2260 r.in.buffer = NULL;
2261 r.in.offered = 0;
2262 r.out.needed = &needed;
2263 r.out.count = &count;
2264 r.out.info = &info;
2266 torture_comment(tctx, "Testing EnumForms level %d\n", levels[i]);
2268 status = dcerpc_spoolss_EnumForms(p, tctx, &r);
2269 torture_assert_ntstatus_ok(tctx, status, "EnumForms failed");
2271 if ((r.in.level == 2) && (W_ERROR_EQUAL(r.out.result, WERR_UNKNOWN_LEVEL))) {
2272 break;
2275 if (print_server && W_ERROR_EQUAL(r.out.result, WERR_BADFID))
2276 torture_fail(tctx, "EnumForms on the PrintServer isn't supported by test server (NT4)");
2278 if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
2279 int j;
2280 DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed);
2281 data_blob_clear(&blob);
2282 r.in.buffer = &blob;
2283 r.in.offered = needed;
2285 status = dcerpc_spoolss_EnumForms(p, tctx, &r);
2287 torture_assert(tctx, info, "No forms returned");
2289 for (j = 0; j < count; j++) {
2290 if (!print_server)
2291 ret &= test_GetForm(tctx, p, handle, info[j].info1.form_name, levels[i]);
2295 torture_assert_ntstatus_ok(tctx, status, "EnumForms failed");
2297 torture_assert_werr_ok(tctx, r.out.result, "EnumForms failed");
2299 CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumForms, info, r.in.level, count, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
2302 return true;
2305 static bool test_DeleteForm(struct torture_context *tctx,
2306 struct dcerpc_pipe *p,
2307 struct policy_handle *handle,
2308 const char *form_name)
2310 NTSTATUS status;
2311 struct spoolss_DeleteForm r;
2313 r.in.handle = handle;
2314 r.in.form_name = form_name;
2316 status = dcerpc_spoolss_DeleteForm(p, tctx, &r);
2318 torture_assert_ntstatus_ok(tctx, status, "DeleteForm failed");
2320 torture_assert_werr_ok(tctx, r.out.result, "DeleteForm failed");
2322 return true;
2325 static bool test_AddForm(struct torture_context *tctx,
2326 struct dcerpc_pipe *p,
2327 struct policy_handle *handle, bool print_server)
2329 struct spoolss_AddForm r;
2330 struct spoolss_AddFormInfo1 addform;
2331 const char *form_name = "testform3";
2332 NTSTATUS status;
2333 bool ret = true;
2335 r.in.handle = handle;
2336 r.in.level = 1;
2337 r.in.info.info1 = &addform;
2338 addform.flags = SPOOLSS_FORM_USER;
2339 addform.form_name = form_name;
2340 addform.size.width = 50;
2341 addform.size.height = 25;
2342 addform.area.left = 5;
2343 addform.area.top = 10;
2344 addform.area.right = 45;
2345 addform.area.bottom = 15;
2347 status = dcerpc_spoolss_AddForm(p, tctx, &r);
2349 torture_assert_ntstatus_ok(tctx, status, "AddForm failed");
2351 torture_assert_werr_ok(tctx, r.out.result, "AddForm failed");
2353 if (!print_server) ret &= test_GetForm(tctx, p, handle, form_name, 1);
2356 struct spoolss_SetForm sf;
2357 struct spoolss_AddFormInfo1 setform;
2359 sf.in.handle = handle;
2360 sf.in.form_name = form_name;
2361 sf.in.level = 1;
2362 sf.in.info.info1= &setform;
2363 setform.flags = addform.flags;
2364 setform.form_name = addform.form_name;
2365 setform.size = addform.size;
2366 setform.area = addform.area;
2368 setform.size.width = 1234;
2370 status = dcerpc_spoolss_SetForm(p, tctx, &sf);
2372 torture_assert_ntstatus_ok(tctx, status, "SetForm failed");
2374 torture_assert_werr_ok(tctx, r.out.result, "SetForm failed");
2377 if (!print_server) ret &= test_GetForm(tctx, p, handle, form_name, 1);
2380 struct spoolss_EnumForms e;
2381 union spoolss_FormInfo *info;
2382 uint32_t needed;
2383 uint32_t count;
2384 bool found = false;
2386 e.in.handle = handle;
2387 e.in.level = 1;
2388 e.in.buffer = NULL;
2389 e.in.offered = 0;
2390 e.out.needed = &needed;
2391 e.out.count = &count;
2392 e.out.info = &info;
2394 torture_comment(tctx, "Testing EnumForms level 1\n");
2396 status = dcerpc_spoolss_EnumForms(p, tctx, &e);
2397 torture_assert_ntstatus_ok(tctx, status, "EnumForms failed");
2399 if (print_server && W_ERROR_EQUAL(e.out.result, WERR_BADFID))
2400 torture_fail(tctx, "EnumForms on the PrintServer isn't supported by test server (NT4)");
2402 if (W_ERROR_EQUAL(e.out.result, WERR_INSUFFICIENT_BUFFER)) {
2403 int j;
2404 DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed);
2405 data_blob_clear(&blob);
2406 e.in.buffer = &blob;
2407 e.in.offered = needed;
2409 status = dcerpc_spoolss_EnumForms(p, tctx, &e);
2411 torture_assert(tctx, info, "No forms returned");
2413 for (j = 0; j < count; j++) {
2414 if (strequal(form_name, info[j].info1.form_name)) {
2415 found = true;
2416 break;
2420 torture_assert(tctx, found, "Newly added form not found in enum call");
2423 if (!test_DeleteForm(tctx, p, handle, form_name)) {
2424 ret = false;
2427 return ret;
2430 static bool test_EnumPorts_old(struct torture_context *tctx,
2431 struct dcerpc_pipe *p)
2433 NTSTATUS status;
2434 struct spoolss_EnumPorts r;
2435 uint32_t needed;
2436 uint32_t count;
2437 union spoolss_PortInfo *info;
2439 r.in.servername = talloc_asprintf(tctx, "\\\\%s",
2440 dcerpc_server_name(p));
2441 r.in.level = 2;
2442 r.in.buffer = NULL;
2443 r.in.offered = 0;
2444 r.out.needed = &needed;
2445 r.out.count = &count;
2446 r.out.info = &info;
2448 torture_comment(tctx, "Testing EnumPorts\n");
2450 status = dcerpc_spoolss_EnumPorts(p, tctx, &r);
2452 torture_assert_ntstatus_ok(tctx, status, "EnumPorts failed");
2454 if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
2455 DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed);
2456 data_blob_clear(&blob);
2457 r.in.buffer = &blob;
2458 r.in.offered = needed;
2460 status = dcerpc_spoolss_EnumPorts(p, tctx, &r);
2461 torture_assert_ntstatus_ok(tctx, status, "EnumPorts failed");
2462 torture_assert_werr_ok(tctx, r.out.result, "EnumPorts failed");
2464 torture_assert(tctx, info, "No ports returned");
2467 torture_assert_werr_ok(tctx, r.out.result, "EnumPorts failed");
2469 CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumPorts, info, 2, count, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
2471 return true;
2474 static bool test_AddPort(struct torture_context *tctx,
2475 struct dcerpc_pipe *p)
2477 NTSTATUS status;
2478 struct spoolss_AddPort r;
2480 r.in.server_name = talloc_asprintf(tctx, "\\\\%s",
2481 dcerpc_server_name(p));
2482 r.in.unknown = 0;
2483 r.in.monitor_name = "foo";
2485 torture_comment(tctx, "Testing AddPort\n");
2487 status = dcerpc_spoolss_AddPort(p, tctx, &r);
2489 torture_assert_ntstatus_ok(tctx, status, "AddPort failed");
2491 /* win2k3 returns WERR_NOT_SUPPORTED */
2493 #if 0
2495 if (!W_ERROR_IS_OK(r.out.result)) {
2496 printf("AddPort failed - %s\n", win_errstr(r.out.result));
2497 return false;
2500 #endif
2502 return true;
2505 static bool test_GetJob(struct torture_context *tctx,
2506 struct dcerpc_pipe *p,
2507 struct policy_handle *handle, uint32_t job_id)
2509 NTSTATUS status;
2510 struct spoolss_GetJob r;
2511 union spoolss_JobInfo info;
2512 uint32_t needed;
2513 uint32_t levels[] = {1, 2 /* 3, 4 */};
2514 uint32_t i;
2516 r.in.handle = handle;
2517 r.in.job_id = job_id;
2518 r.in.level = 0;
2519 r.in.buffer = NULL;
2520 r.in.offered = 0;
2521 r.out.needed = &needed;
2522 r.out.info = &info;
2524 torture_comment(tctx, "Testing GetJob level %d\n", r.in.level);
2526 status = dcerpc_spoolss_GetJob(p, tctx, &r);
2527 torture_assert_werr_equal(tctx, r.out.result, WERR_UNKNOWN_LEVEL, "Unexpected return code");
2529 for (i = 0; i < ARRAY_SIZE(levels); i++) {
2531 torture_comment(tctx, "Testing GetJob level %d\n", r.in.level);
2533 needed = 0;
2535 r.in.level = levels[i];
2536 r.in.offered = 0;
2537 r.in.buffer = NULL;
2539 status = dcerpc_spoolss_GetJob(p, tctx, &r);
2540 torture_assert_ntstatus_ok(tctx, status, "GetJob failed");
2542 if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
2543 DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed);
2544 data_blob_clear(&blob);
2545 r.in.buffer = &blob;
2546 r.in.offered = needed;
2548 status = dcerpc_spoolss_GetJob(p, tctx, &r);
2549 torture_assert_ntstatus_ok(tctx, status, "GetJob failed");
2552 torture_assert(tctx, r.out.info, "No job info returned");
2553 torture_assert_werr_ok(tctx, r.out.result, "GetJob failed");
2555 CHECK_NEEDED_SIZE_LEVEL(spoolss_JobInfo, r.out.info, r.in.level, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
2558 return true;
2561 static bool test_SetJob(struct torture_context *tctx,
2562 struct dcerpc_pipe *p,
2563 struct policy_handle *handle, uint32_t job_id,
2564 enum spoolss_JobControl command)
2566 NTSTATUS status;
2567 struct spoolss_SetJob r;
2569 r.in.handle = handle;
2570 r.in.job_id = job_id;
2571 r.in.ctr = NULL;
2572 r.in.command = command;
2574 switch (command) {
2575 case SPOOLSS_JOB_CONTROL_PAUSE:
2576 torture_comment(tctx, "Testing SetJob: SPOOLSS_JOB_CONTROL_PAUSE\n");
2577 break;
2578 case SPOOLSS_JOB_CONTROL_RESUME:
2579 torture_comment(tctx, "Testing SetJob: SPOOLSS_JOB_CONTROL_RESUME\n");
2580 break;
2581 case SPOOLSS_JOB_CONTROL_CANCEL:
2582 torture_comment(tctx, "Testing SetJob: SPOOLSS_JOB_CONTROL_CANCEL\n");
2583 break;
2584 case SPOOLSS_JOB_CONTROL_RESTART:
2585 torture_comment(tctx, "Testing SetJob: SPOOLSS_JOB_CONTROL_RESTART\n");
2586 break;
2587 case SPOOLSS_JOB_CONTROL_DELETE:
2588 torture_comment(tctx, "Testing SetJob: SPOOLSS_JOB_CONTROL_DELETE\n");
2589 break;
2590 case SPOOLSS_JOB_CONTROL_SEND_TO_PRINTER:
2591 torture_comment(tctx, "Testing SetJob: SPOOLSS_JOB_CONTROL_SEND_TO_PRINTER\n");
2592 break;
2593 case SPOOLSS_JOB_CONTROL_LAST_PAGE_EJECTED:
2594 torture_comment(tctx, "Testing SetJob: SPOOLSS_JOB_CONTROL_LAST_PAGE_EJECTED\n");
2595 break;
2596 case SPOOLSS_JOB_CONTROL_RETAIN:
2597 torture_comment(tctx, "Testing SetJob: SPOOLSS_JOB_CONTROL_RETAIN\n");
2598 break;
2599 case SPOOLSS_JOB_CONTROL_RELEASE:
2600 torture_comment(tctx, "Testing SetJob: SPOOLSS_JOB_CONTROL_RELEASE\n");
2601 break;
2602 default:
2603 torture_comment(tctx, "Testing SetJob\n");
2604 break;
2607 status = dcerpc_spoolss_SetJob(p, tctx, &r);
2608 torture_assert_ntstatus_ok(tctx, status, "SetJob failed");
2609 torture_assert_werr_ok(tctx, r.out.result, "SetJob failed");
2611 return true;
2614 static bool test_AddJob(struct torture_context *tctx,
2615 struct dcerpc_pipe *p,
2616 struct policy_handle *handle)
2618 NTSTATUS status;
2619 struct spoolss_AddJob r;
2620 uint32_t needed;
2622 r.in.level = 0;
2623 r.in.handle = handle;
2624 r.in.offered = 0;
2625 r.out.needed = &needed;
2626 r.in.buffer = r.out.buffer = NULL;
2628 torture_comment(tctx, "Testing AddJob\n");
2630 status = dcerpc_spoolss_AddJob(p, tctx, &r);
2631 torture_assert_werr_equal(tctx, r.out.result, WERR_UNKNOWN_LEVEL, "AddJob failed");
2633 r.in.level = 1;
2635 status = dcerpc_spoolss_AddJob(p, tctx, &r);
2636 torture_assert_werr_equal(tctx, r.out.result, WERR_INVALID_PARAM, "AddJob failed");
2638 return true;
2642 static bool test_EnumJobs(struct torture_context *tctx,
2643 struct dcerpc_pipe *p,
2644 struct policy_handle *handle)
2646 NTSTATUS status;
2647 struct spoolss_EnumJobs r;
2648 uint32_t needed;
2649 uint32_t count;
2650 union spoolss_JobInfo *info;
2652 r.in.handle = handle;
2653 r.in.firstjob = 0;
2654 r.in.numjobs = 0xffffffff;
2655 r.in.level = 1;
2656 r.in.buffer = NULL;
2657 r.in.offered = 0;
2658 r.out.needed = &needed;
2659 r.out.count = &count;
2660 r.out.info = &info;
2662 torture_comment(tctx, "Testing EnumJobs\n");
2664 status = dcerpc_spoolss_EnumJobs(p, tctx, &r);
2666 torture_assert_ntstatus_ok(tctx, status, "EnumJobs failed");
2668 if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
2669 int j;
2670 DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed);
2671 data_blob_clear(&blob);
2672 r.in.buffer = &blob;
2673 r.in.offered = needed;
2675 status = dcerpc_spoolss_EnumJobs(p, tctx, &r);
2677 torture_assert_ntstatus_ok(tctx, status, "EnumJobs failed");
2678 torture_assert_werr_ok(tctx, r.out.result, "EnumJobs failed");
2679 torture_assert(tctx, info, "No jobs returned");
2681 CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumJobs, *r.out.info, r.in.level, count, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
2683 for (j = 0; j < count; j++) {
2685 torture_assert(tctx, test_GetJob(tctx, p, handle, info[j].info1.job_id),
2686 "failed to call test_GetJob");
2688 /* FIXME - gd */
2689 if (!torture_setting_bool(tctx, "samba3", false)) {
2690 test_SetJob(tctx, p, handle, info[j].info1.job_id, SPOOLSS_JOB_CONTROL_PAUSE);
2691 test_SetJob(tctx, p, handle, info[j].info1.job_id, SPOOLSS_JOB_CONTROL_RESUME);
2695 } else {
2696 torture_assert_werr_ok(tctx, r.out.result, "EnumJobs failed");
2699 return true;
2702 static bool test_DoPrintTest(struct torture_context *tctx,
2703 struct dcerpc_pipe *p,
2704 struct policy_handle *handle)
2706 bool ret = true;
2707 NTSTATUS status;
2708 struct spoolss_StartDocPrinter s;
2709 struct spoolss_DocumentInfo1 info1;
2710 struct spoolss_StartPagePrinter sp;
2711 struct spoolss_WritePrinter w;
2712 struct spoolss_EndPagePrinter ep;
2713 struct spoolss_EndDocPrinter e;
2714 int i;
2715 uint32_t job_id;
2716 uint32_t num_written;
2718 torture_comment(tctx, "Testing StartDocPrinter\n");
2720 s.in.handle = handle;
2721 s.in.level = 1;
2722 s.in.info.info1 = &info1;
2723 s.out.job_id = &job_id;
2724 info1.document_name = "TorturePrintJob";
2725 info1.output_file = NULL;
2726 info1.datatype = "RAW";
2728 status = dcerpc_spoolss_StartDocPrinter(p, tctx, &s);
2729 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_StartDocPrinter failed");
2730 torture_assert_werr_ok(tctx, s.out.result, "StartDocPrinter failed");
2732 for (i=1; i < 4; i++) {
2733 torture_comment(tctx, "Testing StartPagePrinter: Page[%d]\n", i);
2735 sp.in.handle = handle;
2737 status = dcerpc_spoolss_StartPagePrinter(p, tctx, &sp);
2738 torture_assert_ntstatus_ok(tctx, status,
2739 "dcerpc_spoolss_StartPagePrinter failed");
2740 torture_assert_werr_ok(tctx, sp.out.result, "StartPagePrinter failed");
2742 torture_comment(tctx, "Testing WritePrinter: Page[%d]\n", i);
2744 w.in.handle = handle;
2745 w.in.data = data_blob_string_const(talloc_asprintf(tctx,"TortureTestPage: %d\nData\n",i));
2746 w.out.num_written = &num_written;
2748 status = dcerpc_spoolss_WritePrinter(p, tctx, &w);
2749 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_WritePrinter failed");
2750 torture_assert_werr_ok(tctx, w.out.result, "WritePrinter failed");
2752 torture_comment(tctx, "Testing EndPagePrinter: Page[%d]\n", i);
2754 ep.in.handle = handle;
2756 status = dcerpc_spoolss_EndPagePrinter(p, tctx, &ep);
2757 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EndPagePrinter failed");
2758 torture_assert_werr_ok(tctx, ep.out.result, "EndPagePrinter failed");
2761 torture_comment(tctx, "Testing EndDocPrinter\n");
2763 e.in.handle = handle;
2765 status = dcerpc_spoolss_EndDocPrinter(p, tctx, &e);
2766 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EndDocPrinter failed");
2767 torture_assert_werr_ok(tctx, e.out.result, "EndDocPrinter failed");
2769 ret &= test_AddJob(tctx, p, handle);
2770 ret &= test_EnumJobs(tctx, p, handle);
2772 ret &= test_SetJob(tctx, p, handle, job_id, SPOOLSS_JOB_CONTROL_DELETE);
2774 return ret;
2777 static bool test_PausePrinter(struct torture_context *tctx,
2778 struct dcerpc_pipe *p,
2779 struct policy_handle *handle)
2781 NTSTATUS status;
2782 struct spoolss_SetPrinter r;
2783 struct spoolss_SetPrinterInfoCtr info_ctr;
2784 struct spoolss_DevmodeContainer devmode_ctr;
2785 struct sec_desc_buf secdesc_ctr;
2787 info_ctr.level = 0;
2788 info_ctr.info.info0 = NULL;
2790 ZERO_STRUCT(devmode_ctr);
2791 ZERO_STRUCT(secdesc_ctr);
2793 r.in.handle = handle;
2794 r.in.info_ctr = &info_ctr;
2795 r.in.devmode_ctr = &devmode_ctr;
2796 r.in.secdesc_ctr = &secdesc_ctr;
2797 r.in.command = SPOOLSS_PRINTER_CONTROL_PAUSE;
2799 torture_comment(tctx, "Testing SetPrinter: SPOOLSS_PRINTER_CONTROL_PAUSE\n");
2801 status = dcerpc_spoolss_SetPrinter(p, tctx, &r);
2803 torture_assert_ntstatus_ok(tctx, status, "SetPrinter failed");
2805 torture_assert_werr_ok(tctx, r.out.result, "SetPrinter failed");
2807 return true;
2810 static bool test_ResumePrinter(struct torture_context *tctx,
2811 struct dcerpc_pipe *p,
2812 struct policy_handle *handle)
2814 NTSTATUS status;
2815 struct spoolss_SetPrinter r;
2816 struct spoolss_SetPrinterInfoCtr info_ctr;
2817 struct spoolss_DevmodeContainer devmode_ctr;
2818 struct sec_desc_buf secdesc_ctr;
2820 info_ctr.level = 0;
2821 info_ctr.info.info0 = NULL;
2823 ZERO_STRUCT(devmode_ctr);
2824 ZERO_STRUCT(secdesc_ctr);
2826 r.in.handle = handle;
2827 r.in.info_ctr = &info_ctr;
2828 r.in.devmode_ctr = &devmode_ctr;
2829 r.in.secdesc_ctr = &secdesc_ctr;
2830 r.in.command = SPOOLSS_PRINTER_CONTROL_RESUME;
2832 torture_comment(tctx, "Testing SetPrinter: SPOOLSS_PRINTER_CONTROL_RESUME\n");
2834 status = dcerpc_spoolss_SetPrinter(p, tctx, &r);
2836 torture_assert_ntstatus_ok(tctx, status, "SetPrinter failed");
2838 torture_assert_werr_ok(tctx, r.out.result, "SetPrinter failed");
2840 return true;
2843 static bool test_GetPrinterData(struct torture_context *tctx,
2844 struct dcerpc_pipe *p,
2845 struct policy_handle *handle,
2846 const char *value_name,
2847 enum winreg_Type *type_p,
2848 union spoolss_PrinterData *data_p)
2850 NTSTATUS status;
2851 struct spoolss_GetPrinterData r;
2852 uint32_t needed;
2853 enum winreg_Type type;
2854 union spoolss_PrinterData data;
2856 r.in.handle = handle;
2857 r.in.value_name = value_name;
2858 r.in.offered = 0;
2859 r.out.needed = &needed;
2860 r.out.type = &type;
2861 r.out.data = &data;
2863 torture_comment(tctx, "Testing GetPrinterData(%s)\n", r.in.value_name);
2865 status = dcerpc_spoolss_GetPrinterData(p, tctx, &r);
2866 torture_assert_ntstatus_ok(tctx, status, "GetPrinterData failed");
2868 if (W_ERROR_EQUAL(r.out.result, WERR_MORE_DATA)) {
2869 r.in.offered = needed;
2871 status = dcerpc_spoolss_GetPrinterData(p, tctx, &r);
2872 torture_assert_ntstatus_ok(tctx, status, "GetPrinterData failed");
2875 torture_assert_werr_ok(tctx, r.out.result,
2876 talloc_asprintf(tctx, "GetPrinterData(%s) failed", r.in.value_name));
2878 CHECK_NEEDED_SIZE_LEVEL(spoolss_PrinterData, &data, type, lp_iconv_convenience(tctx->lp_ctx), needed, 1);
2880 if (type_p) {
2881 *type_p = type;
2884 if (data_p) {
2885 *data_p = data;
2888 return true;
2891 static bool test_GetPrinterDataEx(struct torture_context *tctx,
2892 struct dcerpc_pipe *p,
2893 struct policy_handle *handle,
2894 const char *key_name,
2895 const char *value_name,
2896 enum winreg_Type *type_p,
2897 union spoolss_PrinterData *data_p,
2898 uint32_t *needed_p)
2900 NTSTATUS status;
2901 struct spoolss_GetPrinterDataEx r;
2902 enum winreg_Type type;
2903 uint32_t needed;
2904 union spoolss_PrinterData data;
2906 r.in.handle = handle;
2907 r.in.key_name = key_name;
2908 r.in.value_name = value_name;
2909 r.in.offered = 0;
2910 r.out.type = &type;
2911 r.out.needed = &needed;
2912 r.out.data = &data;
2914 torture_comment(tctx, "Testing GetPrinterDataEx(%s - %s)\n",
2915 r.in.key_name, r.in.value_name);
2917 status = dcerpc_spoolss_GetPrinterDataEx(p, tctx, &r);
2918 if (!NT_STATUS_IS_OK(status)) {
2919 if (NT_STATUS_EQUAL(status,NT_STATUS_NET_WRITE_FAULT) &&
2920 p->last_fault_code == DCERPC_FAULT_OP_RNG_ERROR) {
2921 torture_skip(tctx, "GetPrinterDataEx not supported by server\n");
2923 torture_assert_ntstatus_ok(tctx, status, "GetPrinterDataEx failed");
2926 if (W_ERROR_EQUAL(r.out.result, WERR_MORE_DATA)) {
2927 r.in.offered = needed;
2928 status = dcerpc_spoolss_GetPrinterDataEx(p, tctx, &r);
2929 torture_assert_ntstatus_ok(tctx, status, "GetPrinterDataEx failed");
2932 torture_assert_werr_ok(tctx, r.out.result,
2933 talloc_asprintf(tctx, "GetPrinterDataEx(%s - %s) failed", r.in.key_name, r.in.value_name));
2935 CHECK_NEEDED_SIZE_LEVEL(spoolss_PrinterData, &data, type, lp_iconv_convenience(tctx->lp_ctx), needed, 1);
2937 if (type_p) {
2938 *type_p = type;
2941 if (data_p) {
2942 *data_p = data;
2945 if (needed_p) {
2946 *needed_p = needed;
2949 return true;
2952 static bool test_GetPrinterData_list(struct torture_context *tctx,
2953 struct dcerpc_pipe *p,
2954 struct policy_handle *handle)
2956 const char *list[] = {
2957 "W3SvcInstalled",
2958 "BeepEnabled",
2959 "EventLog",
2960 /* "NetPopup", not on w2k8 */
2961 /* "NetPopupToComputer", not on w2k8 */
2962 "MajorVersion",
2963 "MinorVersion",
2964 "DefaultSpoolDirectory",
2965 "Architecture",
2966 "DsPresent",
2967 "OSVersion",
2968 /* "OSVersionEx", not on s3 */
2969 "DNSMachineName"
2971 int i;
2973 for (i=0; i < ARRAY_SIZE(list); i++) {
2974 enum winreg_Type type, type_ex;
2975 union spoolss_PrinterData data, data_ex;
2977 torture_assert(tctx, test_GetPrinterData(tctx, p, handle, list[i], &type, &data),
2978 talloc_asprintf(tctx, "GetPrinterData failed on %s\n", list[i]));
2979 torture_assert(tctx, test_GetPrinterDataEx(tctx, p, handle, "random_string", list[i], &type_ex, &data_ex, NULL),
2980 talloc_asprintf(tctx, "GetPrinterDataEx failed on %s\n", list[i]));
2981 torture_assert_int_equal(tctx, type, type_ex, "type mismatch");
2982 switch (type) {
2983 case REG_SZ:
2984 torture_assert_str_equal(tctx, data.string, data_ex.string, "REG_SZ mismatch");
2985 break;
2986 case REG_DWORD:
2987 torture_assert_int_equal(tctx, data.value, data_ex.value, "REG_DWORD mismatch");
2988 break;
2989 case REG_BINARY:
2990 torture_assert_data_blob_equal(tctx, data.binary, data_ex.binary, "REG_BINARY mismatch");
2991 break;
2992 default:
2993 break;
2997 return true;
3000 static bool test_EnumPrinterData(struct torture_context *tctx, struct dcerpc_pipe *p,
3001 struct policy_handle *handle)
3003 NTSTATUS status;
3004 struct spoolss_EnumPrinterData r;
3006 ZERO_STRUCT(r);
3007 r.in.handle = handle;
3008 r.in.enum_index = 0;
3010 do {
3011 uint32_t value_size = 0;
3012 uint32_t data_size = 0;
3013 enum winreg_Type type = 0;
3015 r.in.value_offered = value_size;
3016 r.out.value_needed = &value_size;
3017 r.in.data_offered = data_size;
3018 r.out.data_needed = &data_size;
3020 r.out.type = &type;
3021 r.out.data = talloc_zero_array(tctx, uint8_t, 0);
3023 torture_comment(tctx, "Testing EnumPrinterData\n");
3025 status = dcerpc_spoolss_EnumPrinterData(p, tctx, &r);
3027 torture_assert_ntstatus_ok(tctx, status, "EnumPrinterData failed");
3028 if (W_ERROR_EQUAL(r.out.result, WERR_NO_MORE_ITEMS)) {
3029 break;
3031 torture_assert_werr_ok(tctx, r.out.result, "EnumPrinterData");
3033 r.in.value_offered = value_size;
3034 r.out.value_name = talloc_zero_array(tctx, const char, value_size);
3035 r.in.data_offered = data_size;
3036 r.out.data = talloc_zero_array(tctx, uint8_t, data_size);
3038 status = dcerpc_spoolss_EnumPrinterData(p, tctx, &r);
3040 torture_assert_ntstatus_ok(tctx, status, "EnumPrinterData failed");
3041 if (W_ERROR_EQUAL(r.out.result, WERR_NO_MORE_ITEMS)) {
3042 break;
3045 torture_assert_werr_ok(tctx, r.out.result, "EnumPrinterData failed");
3047 torture_assert(tctx, test_GetPrinterData(tctx, p, handle, r.out.value_name, NULL, NULL),
3048 talloc_asprintf(tctx, "failed to call GetPrinterData for %s\n", r.out.value_name));
3050 torture_assert(tctx, test_GetPrinterDataEx(tctx, p, handle, "PrinterDriverData", r.out.value_name, NULL, NULL, NULL),
3051 talloc_asprintf(tctx, "failed to call GetPrinterDataEx on PrinterDriverData for %s\n", r.out.value_name));
3053 r.in.enum_index++;
3055 } while (W_ERROR_IS_OK(r.out.result));
3057 return true;
3060 static bool test_EnumPrinterDataEx(struct torture_context *tctx,
3061 struct dcerpc_pipe *p,
3062 struct policy_handle *handle,
3063 const char *key_name)
3065 struct spoolss_EnumPrinterDataEx r;
3066 struct spoolss_PrinterEnumValues *info;
3067 uint32_t needed;
3068 uint32_t count;
3070 r.in.handle = handle;
3071 r.in.key_name = key_name;
3072 r.in.offered = 0;
3073 r.out.needed = &needed;
3074 r.out.count = &count;
3075 r.out.info = &info;
3077 torture_comment(tctx, "Testing EnumPrinterDataEx(%s)\n", key_name);
3079 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_EnumPrinterDataEx(p, tctx, &r),
3080 "EnumPrinterDataEx failed");
3081 if (W_ERROR_EQUAL(r.out.result, WERR_MORE_DATA)) {
3082 r.in.offered = needed;
3083 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_EnumPrinterDataEx(p, tctx, &r),
3084 "EnumPrinterDataEx failed");
3087 torture_assert_werr_ok(tctx, r.out.result, "EnumPrinterDataEx failed");
3089 CHECK_NEEDED_SIZE_ENUM(spoolss_EnumPrinterDataEx, info, count, lp_iconv_convenience(tctx->lp_ctx), needed, 1);
3091 return true;
3095 static bool test_DeletePrinterData(struct torture_context *tctx,
3096 struct dcerpc_pipe *p,
3097 struct policy_handle *handle,
3098 const char *value_name)
3100 NTSTATUS status;
3101 struct spoolss_DeletePrinterData r;
3103 r.in.handle = handle;
3104 r.in.value_name = value_name;
3106 torture_comment(tctx, "Testing DeletePrinterData(%s)\n",
3107 r.in.value_name);
3109 status = dcerpc_spoolss_DeletePrinterData(p, tctx, &r);
3111 torture_assert_ntstatus_ok(tctx, status, "DeletePrinterData failed");
3112 torture_assert_werr_ok(tctx, r.out.result, "DeletePrinterData failed");
3114 return true;
3117 static bool test_DeletePrinterDataEx(struct torture_context *tctx,
3118 struct dcerpc_pipe *p,
3119 struct policy_handle *handle,
3120 const char *key_name,
3121 const char *value_name)
3123 struct spoolss_DeletePrinterDataEx r;
3125 r.in.handle = handle;
3126 r.in.key_name = key_name;
3127 r.in.value_name = value_name;
3129 torture_comment(tctx, "Testing DeletePrinterDataEx(%s - %s)\n",
3130 r.in.key_name, r.in.value_name);
3132 torture_assert_ntstatus_ok(tctx,
3133 dcerpc_spoolss_DeletePrinterDataEx(p, tctx, &r),
3134 "DeletePrinterDataEx failed");
3135 torture_assert_werr_ok(tctx, r.out.result,
3136 "DeletePrinterDataEx failed");
3138 return true;
3141 static bool test_DeletePrinterKey(struct torture_context *tctx,
3142 struct dcerpc_pipe *p,
3143 struct policy_handle *handle,
3144 const char *key_name)
3146 struct spoolss_DeletePrinterKey r;
3148 r.in.handle = handle;
3149 r.in.key_name = key_name;
3151 torture_comment(tctx, "Testing DeletePrinterKey(%s)\n", r.in.key_name);
3153 if (strequal(key_name, "") && !torture_setting_bool(tctx, "dangerous", false)) {
3154 torture_skip(tctx, "not wiping out printer registry - enable dangerous tests to use\n");
3155 return true;
3158 torture_assert_ntstatus_ok(tctx,
3159 dcerpc_spoolss_DeletePrinterKey(p, tctx, &r),
3160 "DeletePrinterKey failed");
3161 torture_assert_werr_ok(tctx, r.out.result,
3162 "DeletePrinterKey failed");
3164 return true;
3167 static bool test_SetPrinterData(struct torture_context *tctx,
3168 struct dcerpc_pipe *p,
3169 struct policy_handle *handle)
3171 NTSTATUS status;
3172 struct spoolss_SetPrinterData r;
3173 const char *values[] = {
3174 "spootyfoot",
3175 "spooty\\foot",
3176 #if 0
3177 /* FIXME: not working with s3 atm. */
3178 "spooty,foot",
3179 "spooty,fo,ot",
3180 #endif
3181 "spooty foot",
3182 #if 0
3183 /* FIXME: not working with s3 atm. */
3184 "spooty\\fo,ot",
3185 "spooty,fo\\ot"
3186 #endif
3188 int i;
3190 for (i=0; i < ARRAY_SIZE(values); i++) {
3192 enum winreg_Type type;
3193 union spoolss_PrinterData data;
3195 r.in.handle = handle;
3196 r.in.value_name = values[i];
3197 r.in.type = REG_SZ;
3198 r.in.data.string = "dog";
3200 torture_comment(tctx, "Testing SetPrinterData(%s)\n",
3201 r.in.value_name);
3203 status = dcerpc_spoolss_SetPrinterData(p, tctx, &r);
3205 torture_assert_ntstatus_ok(tctx, status, "SetPrinterData failed");
3206 torture_assert_werr_ok(tctx, r.out.result, "SetPrinterData failed");
3208 if (!test_GetPrinterData(tctx, p, handle, r.in.value_name, &type, &data)) {
3209 return false;
3212 torture_assert_int_equal(tctx, r.in.type, type, "type mismatch");
3213 torture_assert_str_equal(tctx, r.in.data.string, data.string, "data mismatch");
3215 if (!test_DeletePrinterData(tctx, p, handle, r.in.value_name)) {
3216 return false;
3220 return true;
3223 static bool test_EnumPrinterKey(struct torture_context *tctx,
3224 struct dcerpc_pipe *p,
3225 struct policy_handle *handle,
3226 const char *key_name,
3227 const char ***array);
3229 static bool test_SetPrinterDataEx(struct torture_context *tctx,
3230 struct dcerpc_pipe *p,
3231 struct policy_handle *handle,
3232 const char *key_name,
3233 const char *value_name,
3234 enum winreg_Type type,
3235 union spoolss_PrinterData *data,
3236 uint32_t _offered)
3238 NTSTATUS status;
3239 struct spoolss_SetPrinterDataEx r;
3241 r.in.handle = handle;
3242 r.in.key_name = key_name;
3243 r.in.value_name = value_name;
3244 r.in.type = type;
3245 r.in.data = *data;
3246 r.in._offered = _offered;
3248 torture_comment(tctx, "Testing SetPrinterDataEx(%s - %s) type: %s, offered: 0x%08x\n",
3249 r.in.key_name, r.in.value_name, str_regtype(r.in.type), r.in._offered);
3251 status = dcerpc_spoolss_SetPrinterDataEx(p, tctx, &r);
3253 torture_assert_ntstatus_ok(tctx, status, "SetPrinterDataEx failed");
3254 torture_assert_werr_ok(tctx, r.out.result, "SetPrinterDataEx failed");
3256 return true;
3259 static bool test_SetPrinterDataEx_matrix(struct torture_context *tctx,
3260 struct dcerpc_pipe *p,
3261 struct policy_handle *handle)
3263 const char *value_name = "dog";
3264 const char *keys[] = {
3265 "torturedataex",
3266 "torture data ex",
3267 #if 0
3268 /* FIXME: not working with s3 atm. */
3269 "torturedataex_with_subkey\\subkey",
3270 "torturedataex_with_subkey\\subkey:0",
3271 "torturedataex_with_subkey\\subkey:1",
3272 "torturedataex_with_subkey\\subkey\\subsubkey",
3273 "torturedataex_with_subkey\\subkey\\subsubkey:0",
3274 "torturedataex_with_subkey\\subkey\\subsubkey:1",
3275 #endif
3276 "torture,data",
3277 #if 0
3278 /* FIXME: not working with s3 atm. */
3280 "torture,data,ex",
3281 "torture,data\\ex",
3282 "torture\\data,ex"
3283 #endif
3285 enum winreg_Type types[] = {
3286 REG_SZ,
3287 REG_DWORD,
3288 REG_BINARY
3290 uint32_t value = 12345678;
3291 const char *str = "abcdefghijklmnopqrstuvwxzy";
3292 int i, t, s;
3295 for (i=0; i < ARRAY_SIZE(keys); i++) {
3296 for (t=0; t < ARRAY_SIZE(types); t++) {
3297 for (s=0; s < strlen(str); s++) {
3299 char *c;
3300 const char *key;
3301 enum winreg_Type type;
3302 const char *string = talloc_strndup(tctx, str, s);
3303 DATA_BLOB blob = data_blob_string_const(string);
3304 const char **subkeys;
3305 union spoolss_PrinterData data;
3306 uint32_t needed, offered = 0;
3308 if (types[t] == REG_DWORD) {
3309 s = 0xffff;
3312 switch (types[t]) {
3313 case REG_BINARY:
3314 data.binary = blob;
3315 offered = blob.length;
3316 break;
3317 case REG_DWORD:
3318 data.value = value;
3319 offered = 4;
3320 break;
3321 case REG_SZ:
3322 data.string = string;
3323 offered = strlen_m_term(data.string)*2;
3324 break;
3325 default:
3326 torture_fail(tctx, talloc_asprintf(tctx, "type %d untested\n", types[t]));
3329 torture_assert(tctx,
3330 test_SetPrinterDataEx(tctx, p, handle, keys[i], value_name, types[t], &data, offered),
3331 "failed to call SetPrinterDataEx");
3333 if (!test_GetPrinterDataEx(tctx, p, handle, keys[i], value_name, &type, &data, &needed)) {
3334 return false;
3337 /* special case, a REG_BINARY set with 0 size returns a 0 sized
3338 * REG_NONE - gd */
3339 if ((types[t] == REG_BINARY) && (offered == 0)) {
3340 torture_assert_int_equal(tctx, REG_NONE, type, "type mismatch");
3341 } else {
3342 torture_assert_int_equal(tctx, types[t], type, "type mismatch");
3345 switch (type) {
3346 case REG_BINARY:
3347 torture_assert_data_blob_equal(tctx, blob, data.binary, "data mismatch");
3348 break;
3349 case REG_DWORD:
3350 torture_assert_int_equal(tctx, value, data.value, "data mismatch");
3351 break;
3352 case REG_SZ:
3353 torture_assert_str_equal(tctx, string, data.string, "data mismatch");
3354 break;
3355 default:
3356 break;
3359 torture_assert_int_equal(tctx, needed, offered, "size mismatch");
3361 key = talloc_strdup(tctx, keys[i]);
3363 if (!test_EnumPrinterDataEx(tctx, p, handle, keys[i])) {
3364 return false;
3367 if (!test_DeletePrinterDataEx(tctx, p, handle, keys[i], value_name)) {
3368 return false;
3371 c = strchr(key, '\\');
3372 if (c) {
3373 int i;
3375 /* we have subkeys */
3377 *c = 0;
3379 if (!test_EnumPrinterKey(tctx, p, handle, key, &subkeys)) {
3380 return false;
3383 for (i=0; subkeys && subkeys[i]; i++) {
3385 const char *current_key = talloc_asprintf(tctx, "%s\\%s", key, subkeys[i]);
3387 if (!test_DeletePrinterKey(tctx, p, handle, current_key)) {
3388 return false;
3392 if (!test_DeletePrinterKey(tctx, p, handle, key)) {
3393 return false;
3396 } else {
3397 if (!test_DeletePrinterKey(tctx, p, handle, key)) {
3398 return false;
3405 return true;
3408 static bool test_GetChangeID_PrinterData(struct torture_context *tctx,
3409 struct dcerpc_pipe *p,
3410 struct policy_handle *handle,
3411 uint32_t *change_id)
3413 enum winreg_Type type;
3414 union spoolss_PrinterData data;
3416 torture_assert(tctx,
3417 test_GetPrinterData(tctx, p, handle, "ChangeID", &type, &data),
3418 "failed to call GetPrinterData");
3420 torture_assert(tctx, type == REG_DWORD, "unexpected type");
3422 *change_id = data.value;
3424 return true;
3427 static bool test_GetChangeID_PrinterDataEx(struct torture_context *tctx,
3428 struct dcerpc_pipe *p,
3429 struct policy_handle *handle,
3430 uint32_t *change_id)
3432 enum winreg_Type type;
3433 union spoolss_PrinterData data;
3435 torture_assert(tctx,
3436 test_GetPrinterDataEx(tctx, p, handle, "PrinterDriverData", "ChangeID", &type, &data, NULL),
3437 "failed to call GetPrinterData");
3439 torture_assert(tctx, type == REG_DWORD, "unexpected type");
3441 *change_id = data.value;
3443 return true;
3446 static bool test_GetChangeID_PrinterInfo(struct torture_context *tctx,
3447 struct dcerpc_pipe *p,
3448 struct policy_handle *handle,
3449 uint32_t *change_id)
3451 union spoolss_PrinterInfo info;
3453 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 0, &info),
3454 "failed to query Printer level 0");
3456 *change_id = info.info0.change_id;
3458 return true;
3461 static bool test_ChangeID(struct torture_context *tctx,
3462 struct dcerpc_pipe *p,
3463 struct policy_handle *handle)
3465 uint32_t change_id, change_id_ex, change_id_info;
3466 uint32_t change_id2, change_id_ex2, change_id_info2;
3467 union spoolss_PrinterInfo info;
3468 const char *comment;
3471 torture_comment(tctx, "Testing ChangeID: id change test #1\n");
3473 torture_assert(tctx, test_GetChangeID_PrinterData(tctx, p, handle, &change_id),
3474 "failed to query for ChangeID");
3475 torture_assert(tctx, test_GetChangeID_PrinterDataEx(tctx, p, handle, &change_id_ex),
3476 "failed to query for ChangeID");
3477 torture_assert(tctx, test_GetChangeID_PrinterInfo(tctx, p, handle, &change_id_info),
3478 "failed to query for ChangeID");
3480 torture_assert_int_equal(tctx, change_id, change_id_ex,
3481 "change_ids should all be equal");
3482 torture_assert_int_equal(tctx, change_id_ex, change_id_info,
3483 "change_ids should all be equal");
3486 torture_comment(tctx, "Testing ChangeID: id change test #2\n");
3488 torture_assert(tctx, test_GetChangeID_PrinterData(tctx, p, handle, &change_id),
3489 "failed to query for ChangeID");
3490 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 2, &info),
3491 "failed to query Printer level 2");
3492 torture_assert(tctx, test_GetChangeID_PrinterDataEx(tctx, p, handle, &change_id_ex),
3493 "failed to query for ChangeID");
3494 torture_assert(tctx, test_GetChangeID_PrinterInfo(tctx, p, handle, &change_id_info),
3495 "failed to query for ChangeID");
3496 torture_assert_int_equal(tctx, change_id, change_id_ex,
3497 "change_id should not have changed");
3498 torture_assert_int_equal(tctx, change_id_ex, change_id_info,
3499 "change_id should not have changed");
3502 torture_comment(tctx, "Testing ChangeID: id change test #3\n");
3504 torture_assert(tctx, test_GetChangeID_PrinterData(tctx, p, handle, &change_id),
3505 "failed to query for ChangeID");
3506 torture_assert(tctx, test_GetChangeID_PrinterDataEx(tctx, p, handle, &change_id_ex),
3507 "failed to query for ChangeID");
3508 torture_assert(tctx, test_GetChangeID_PrinterInfo(tctx, p, handle, &change_id_info),
3509 "failed to query for ChangeID");
3510 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 2, &info),
3511 "failed to query Printer level 2");
3512 comment = talloc_strdup(tctx, info.info2.comment);
3515 struct spoolss_SetPrinterInfoCtr info_ctr;
3516 struct spoolss_DevmodeContainer devmode_ctr;
3517 struct sec_desc_buf secdesc_ctr;
3518 struct spoolss_SetPrinterInfo2 info2;
3520 ZERO_STRUCT(info_ctr);
3521 ZERO_STRUCT(devmode_ctr);
3522 ZERO_STRUCT(secdesc_ctr);
3524 info2.servername = info.info2.servername;
3525 info2.printername = info.info2.printername;
3526 info2.sharename = info.info2.sharename;
3527 info2.portname = info.info2.portname;
3528 info2.drivername = info.info2.drivername;
3529 info2.comment = "torture_comment";
3530 info2.location = info.info2.location;
3531 info2.devmode_ptr = 0;
3532 info2.sepfile = info.info2.sepfile;
3533 info2.printprocessor = info.info2.printprocessor;
3534 info2.datatype = info.info2.datatype;
3535 info2.parameters = info.info2.parameters;
3536 info2.secdesc_ptr = 0;
3537 info2.attributes = info.info2.attributes;
3538 info2.priority = info.info2.priority;
3539 info2.defaultpriority = info.info2.defaultpriority;
3540 info2.starttime = info.info2.starttime;
3541 info2.untiltime = info.info2.untiltime;
3542 info2.status = info.info2.status;
3543 info2.cjobs = info.info2.cjobs;
3544 info2.averageppm = info.info2.averageppm;
3546 info_ctr.level = 2;
3547 info_ctr.info.info2 = &info2;
3549 torture_assert(tctx, test_SetPrinter(tctx, p, handle, &info_ctr, &devmode_ctr, &secdesc_ctr, 0),
3550 "failed to call SetPrinter");
3552 info2.comment = comment;
3554 torture_assert(tctx, test_SetPrinter(tctx, p, handle, &info_ctr, &devmode_ctr, &secdesc_ctr, 0),
3555 "failed to call SetPrinter");
3559 torture_assert(tctx, test_GetChangeID_PrinterData(tctx, p, handle, &change_id2),
3560 "failed to query for ChangeID");
3561 torture_assert(tctx, test_GetChangeID_PrinterDataEx(tctx, p, handle, &change_id_ex2),
3562 "failed to query for ChangeID");
3563 torture_assert(tctx, test_GetChangeID_PrinterInfo(tctx, p, handle, &change_id_info2),
3564 "failed to query for ChangeID");
3566 torture_assert_int_equal(tctx, change_id2, change_id_ex2,
3567 "change_ids should all be equal");
3568 torture_assert_int_equal(tctx, change_id_ex2, change_id_info2,
3569 "change_ids should all be equal");
3571 torture_assert(tctx, (change_id < change_id2),
3572 talloc_asprintf(tctx, "change_id %d needs to be larger than change_id %d",
3573 change_id2, change_id));
3574 torture_assert(tctx, (change_id_ex < change_id_ex2),
3575 talloc_asprintf(tctx, "change_id %d needs to be larger than change_id %d",
3576 change_id_ex2, change_id_ex));
3577 torture_assert(tctx, (change_id_info < change_id_info2),
3578 talloc_asprintf(tctx, "change_id %d needs to be larger than change_id %d",
3579 change_id_info2, change_id_info));
3581 return true;
3584 static bool test_SecondaryClosePrinter(struct torture_context *tctx,
3585 struct dcerpc_pipe *p,
3586 struct policy_handle *handle)
3588 NTSTATUS status;
3589 struct dcerpc_binding *b;
3590 struct dcerpc_pipe *p2;
3591 struct spoolss_ClosePrinter cp;
3593 /* only makes sense on SMB */
3594 if (p->conn->transport.transport != NCACN_NP) {
3595 return true;
3598 torture_comment(tctx, "testing close on secondary pipe\n");
3600 status = dcerpc_parse_binding(tctx, p->conn->binding_string, &b);
3601 torture_assert_ntstatus_ok(tctx, status, "Failed to parse dcerpc binding");
3603 status = dcerpc_secondary_connection(p, &p2, b);
3604 torture_assert_ntstatus_ok(tctx, status, "Failed to create secondary connection");
3606 status = dcerpc_bind_auth_none(p2, &ndr_table_spoolss);
3607 torture_assert_ntstatus_ok(tctx, status, "Failed to create bind on secondary connection");
3609 cp.in.handle = handle;
3610 cp.out.handle = handle;
3612 status = dcerpc_spoolss_ClosePrinter(p2, tctx, &cp);
3613 torture_assert_ntstatus_equal(tctx, status, NT_STATUS_NET_WRITE_FAULT,
3614 "ERROR: Allowed close on secondary connection");
3616 torture_assert_int_equal(tctx, p2->last_fault_code, DCERPC_FAULT_CONTEXT_MISMATCH,
3617 "Unexpected fault code");
3619 talloc_free(p2);
3621 return true;
3624 static bool test_OpenPrinter_badname(struct torture_context *tctx,
3625 struct dcerpc_pipe *p, const char *name)
3627 NTSTATUS status;
3628 struct spoolss_OpenPrinter op;
3629 struct spoolss_OpenPrinterEx opEx;
3630 struct policy_handle handle;
3631 bool ret = true;
3633 op.in.printername = name;
3634 op.in.datatype = NULL;
3635 op.in.devmode_ctr.devmode= NULL;
3636 op.in.access_mask = 0;
3637 op.out.handle = &handle;
3639 torture_comment(tctx, "\nTesting OpenPrinter(%s) with bad name\n", op.in.printername);
3641 status = dcerpc_spoolss_OpenPrinter(p, tctx, &op);
3642 torture_assert_ntstatus_ok(tctx, status, "OpenPrinter failed");
3643 if (!W_ERROR_EQUAL(WERR_INVALID_PRINTER_NAME,op.out.result)) {
3644 torture_comment(tctx, "OpenPrinter(%s) unexpected result[%s] should be WERR_INVALID_PRINTER_NAME\n",
3645 name, win_errstr(op.out.result));
3648 if (W_ERROR_IS_OK(op.out.result)) {
3649 ret &=test_ClosePrinter(tctx, p, &handle);
3652 opEx.in.printername = name;
3653 opEx.in.datatype = NULL;
3654 opEx.in.devmode_ctr.devmode = NULL;
3655 opEx.in.access_mask = 0;
3656 opEx.in.level = 1;
3657 opEx.in.userlevel.level1 = NULL;
3658 opEx.out.handle = &handle;
3660 torture_comment(tctx, "Testing OpenPrinterEx(%s) with bad name\n", opEx.in.printername);
3662 status = dcerpc_spoolss_OpenPrinterEx(p, tctx, &opEx);
3663 torture_assert_ntstatus_ok(tctx, status, "OpenPrinterEx failed");
3664 if (!W_ERROR_EQUAL(WERR_INVALID_PARAM,opEx.out.result)) {
3665 torture_comment(tctx, "OpenPrinterEx(%s) unexpected result[%s] should be WERR_INVALID_PARAM\n",
3666 name, win_errstr(opEx.out.result));
3669 if (W_ERROR_IS_OK(opEx.out.result)) {
3670 ret &=test_ClosePrinter(tctx, p, &handle);
3673 return ret;
3676 static bool test_OpenPrinter(struct torture_context *tctx,
3677 struct dcerpc_pipe *p,
3678 const char *name,
3679 const char *environment)
3681 NTSTATUS status;
3682 struct spoolss_OpenPrinter r;
3683 struct policy_handle handle;
3684 bool ret = true;
3686 r.in.printername = talloc_asprintf(tctx, "\\\\%s\\%s", dcerpc_server_name(p), name);
3687 r.in.datatype = NULL;
3688 r.in.devmode_ctr.devmode= NULL;
3689 r.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
3690 r.out.handle = &handle;
3692 torture_comment(tctx, "Testing OpenPrinter(%s)\n", r.in.printername);
3694 status = dcerpc_spoolss_OpenPrinter(p, tctx, &r);
3696 torture_assert_ntstatus_ok(tctx, status, "OpenPrinter failed");
3698 torture_assert_werr_ok(tctx, r.out.result, "OpenPrinter failed");
3700 if (!test_GetPrinter(tctx, p, &handle, environment)) {
3701 ret = false;
3704 if (!torture_setting_bool(tctx, "samba3", false)) {
3705 if (!test_SecondaryClosePrinter(tctx, p, &handle)) {
3706 ret = false;
3710 if (!test_ClosePrinter(tctx, p, &handle)) {
3711 ret = false;
3714 return ret;
3717 static bool call_OpenPrinterEx(struct torture_context *tctx,
3718 struct dcerpc_pipe *p,
3719 const char *name,
3720 struct spoolss_DeviceMode *devmode,
3721 struct policy_handle *handle)
3723 struct spoolss_OpenPrinterEx r;
3724 struct spoolss_UserLevel1 userlevel1;
3725 NTSTATUS status;
3727 if (name && name[0]) {
3728 r.in.printername = talloc_asprintf(tctx, "\\\\%s\\%s",
3729 dcerpc_server_name(p), name);
3730 } else {
3731 r.in.printername = talloc_asprintf(tctx, "\\\\%s",
3732 dcerpc_server_name(p));
3735 r.in.datatype = NULL;
3736 r.in.devmode_ctr.devmode= devmode;
3737 r.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
3738 r.in.level = 1;
3739 r.in.userlevel.level1 = &userlevel1;
3740 r.out.handle = handle;
3742 userlevel1.size = 1234;
3743 userlevel1.client = "hello";
3744 userlevel1.user = "spottyfoot!";
3745 userlevel1.build = 1;
3746 userlevel1.major = 2;
3747 userlevel1.minor = 3;
3748 userlevel1.processor = 4;
3750 torture_comment(tctx, "Testing OpenPrinterEx(%s)\n", r.in.printername);
3752 status = dcerpc_spoolss_OpenPrinterEx(p, tctx, &r);
3754 torture_assert_ntstatus_ok(tctx, status, "OpenPrinterEx failed");
3756 torture_assert_werr_ok(tctx, r.out.result, "OpenPrinterEx failed");
3758 return true;
3761 static bool test_OpenPrinterEx(struct torture_context *tctx,
3762 struct dcerpc_pipe *p,
3763 const char *name,
3764 const char *environment)
3766 struct policy_handle handle;
3767 bool ret = true;
3769 if (!call_OpenPrinterEx(tctx, p, name, NULL, &handle)) {
3770 return false;
3773 if (!test_PrinterInfo_SD(tctx, p, &handle)) {
3774 ret = false;
3777 if (!test_GetPrinter(tctx, p, &handle, environment)) {
3778 ret = false;
3781 if (!test_EnumForms(tctx, p, &handle, false)) {
3782 ret = false;
3785 if (!test_AddForm(tctx, p, &handle, false)) {
3786 ret = false;
3789 if (!test_EnumPrinterData(tctx, p, &handle)) {
3790 ret = false;
3793 if (!test_EnumPrinterDataEx(tctx, p, &handle, "PrinterDriverData")) {
3794 ret = false;
3797 if (!test_printer_keys(tctx, p, &handle)) {
3798 ret = false;
3801 if (!test_PausePrinter(tctx, p, &handle)) {
3802 ret = false;
3805 if (!test_DoPrintTest(tctx, p, &handle)) {
3806 ret = false;
3809 if (!test_ResumePrinter(tctx, p, &handle)) {
3810 ret = false;
3813 if (!test_SetPrinterData(tctx, p, &handle)) {
3814 ret = false;
3817 if (!test_SetPrinterDataEx_matrix(tctx, p, &handle)) {
3818 ret = false;
3821 if (!torture_setting_bool(tctx, "samba3", false)) {
3822 if (!test_SecondaryClosePrinter(tctx, p, &handle)) {
3823 ret = false;
3827 if (!test_ClosePrinter(tctx, p, &handle)) {
3828 ret = false;
3831 return ret;
3834 static bool test_EnumPrinters_old(struct torture_context *tctx,
3835 struct dcerpc_pipe *p,
3836 const char *environment)
3838 struct spoolss_EnumPrinters r;
3839 NTSTATUS status;
3840 uint16_t levels[] = {1, 2, 4, 5};
3841 int i;
3842 bool ret = true;
3844 for (i=0;i<ARRAY_SIZE(levels);i++) {
3845 union spoolss_PrinterInfo *info;
3846 int j;
3847 uint32_t needed;
3848 uint32_t count;
3850 r.in.flags = PRINTER_ENUM_LOCAL;
3851 r.in.server = "";
3852 r.in.level = levels[i];
3853 r.in.buffer = NULL;
3854 r.in.offered = 0;
3855 r.out.needed = &needed;
3856 r.out.count = &count;
3857 r.out.info = &info;
3859 torture_comment(tctx, "Testing EnumPrinters level %u\n", r.in.level);
3861 status = dcerpc_spoolss_EnumPrinters(p, tctx, &r);
3862 torture_assert_ntstatus_ok(tctx, status, "EnumPrinters failed");
3864 if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
3865 DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed);
3866 data_blob_clear(&blob);
3867 r.in.buffer = &blob;
3868 r.in.offered = needed;
3869 status = dcerpc_spoolss_EnumPrinters(p, tctx, &r);
3872 torture_assert_ntstatus_ok(tctx, status, "EnumPrinters failed");
3874 torture_assert_werr_ok(tctx, r.out.result, "EnumPrinters failed");
3876 CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumPrinters, info, r.in.level, count, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
3878 if (!info) {
3879 torture_comment(tctx, "No printers returned\n");
3880 return true;
3883 for (j=0;j<count;j++) {
3884 if (r.in.level == 1) {
3885 char *unc = talloc_strdup(tctx, info[j].info1.name);
3886 char *slash, *name;
3887 name = unc;
3888 if (unc[0] == '\\' && unc[1] == '\\') {
3889 unc +=2;
3891 slash = strchr(unc, '\\');
3892 if (slash) {
3893 slash++;
3894 name = slash;
3896 if (!test_OpenPrinter(tctx, p, name, environment)) {
3897 ret = false;
3899 if (!test_OpenPrinterEx(tctx, p, name, environment)) {
3900 ret = false;
3906 return ret;
3909 static bool test_GetPrinterDriver(struct torture_context *tctx,
3910 struct dcerpc_pipe *p,
3911 struct policy_handle *handle,
3912 const char *driver_name)
3914 struct spoolss_GetPrinterDriver r;
3915 uint32_t needed;
3917 r.in.handle = handle;
3918 r.in.architecture = "W32X86";
3919 r.in.level = 1;
3920 r.in.buffer = NULL;
3921 r.in.offered = 0;
3922 r.out.needed = &needed;
3924 torture_comment(tctx, "Testing GetPrinterDriver level %d\n", r.in.level);
3926 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_GetPrinterDriver(p, tctx, &r),
3927 "failed to call GetPrinterDriver");
3928 if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
3929 DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed);
3930 data_blob_clear(&blob);
3931 r.in.buffer = &blob;
3932 r.in.offered = needed;
3933 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_GetPrinterDriver(p, tctx, &r),
3934 "failed to call GetPrinterDriver");
3937 torture_assert_werr_ok(tctx, r.out.result,
3938 "failed to call GetPrinterDriver");
3940 CHECK_NEEDED_SIZE_LEVEL(spoolss_DriverInfo, r.out.info, r.in.level, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
3942 return true;
3945 static bool test_GetPrinterDriver2(struct torture_context *tctx,
3946 struct dcerpc_pipe *p,
3947 struct policy_handle *handle,
3948 const char *driver_name,
3949 const char *architecture)
3951 struct spoolss_GetPrinterDriver2 r;
3952 uint16_t levels[] = {1, 2, 3, 4, 5, 6, 8, 101 };
3953 uint32_t needed;
3954 uint32_t server_major_version;
3955 uint32_t server_minor_version;
3956 int i;
3958 r.in.handle = handle;
3959 r.in.architecture = architecture;
3960 r.in.client_major_version = 3;
3961 r.in.client_minor_version = 0;
3962 r.out.needed = &needed;
3963 r.out.server_major_version = &server_major_version;
3964 r.out.server_minor_version = &server_minor_version;
3966 for (i=0;i<ARRAY_SIZE(levels);i++) {
3968 r.in.buffer = NULL;
3969 r.in.offered = 0;
3970 r.in.level = levels[i];
3972 torture_comment(tctx, "Testing GetPrinterDriver2(%s) level %d\n",
3973 driver_name, r.in.level);
3975 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_GetPrinterDriver2(p, tctx, &r),
3976 "failed to call GetPrinterDriver2");
3977 if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
3978 DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed);
3979 data_blob_clear(&blob);
3980 r.in.buffer = &blob;
3981 r.in.offered = needed;
3982 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_GetPrinterDriver2(p, tctx, &r),
3983 "failed to call GetPrinterDriver2");
3986 if (W_ERROR_EQUAL(r.out.result, WERR_INVALID_LEVEL)) {
3987 switch (r.in.level) {
3988 case 101:
3989 case 8:
3990 continue;
3991 default:
3992 break;
3996 torture_assert_werr_ok(tctx, r.out.result,
3997 "failed to call GetPrinterDriver2");
3999 CHECK_NEEDED_SIZE_LEVEL(spoolss_DriverInfo, r.out.info, r.in.level, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
4002 return true;
4005 static bool test_EnumPrinterDrivers_old(struct torture_context *tctx,
4006 struct dcerpc_pipe *p,
4007 const char *environment)
4009 struct spoolss_EnumPrinterDrivers r;
4010 NTSTATUS status;
4011 uint16_t levels[] = {1, 2, 3, 4, 5, 6};
4012 int i;
4014 for (i=0;i<ARRAY_SIZE(levels);i++) {
4016 uint32_t needed;
4017 uint32_t count;
4018 union spoolss_DriverInfo *info;
4020 r.in.server = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
4021 r.in.environment = environment;
4022 r.in.level = levels[i];
4023 r.in.buffer = NULL;
4024 r.in.offered = 0;
4025 r.out.needed = &needed;
4026 r.out.count = &count;
4027 r.out.info = &info;
4029 torture_comment(tctx, "Testing EnumPrinterDrivers level %u\n", r.in.level);
4031 status = dcerpc_spoolss_EnumPrinterDrivers(p, tctx, &r);
4033 torture_assert_ntstatus_ok(tctx, status, "EnumPrinterDrivers failed");
4035 if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
4036 DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed);
4037 data_blob_clear(&blob);
4038 r.in.buffer = &blob;
4039 r.in.offered = needed;
4040 status = dcerpc_spoolss_EnumPrinterDrivers(p, tctx, &r);
4043 torture_assert_ntstatus_ok(tctx, status, "EnumPrinterDrivers failed");
4045 torture_assert_werr_ok(tctx, r.out.result, "EnumPrinterDrivers failed");
4047 if (!info) {
4048 torture_comment(tctx, "No printer drivers returned\n");
4049 break;
4052 CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumPrinterDrivers, info, r.in.level, count, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
4055 return true;
4058 static bool test_DeletePrinter(struct torture_context *tctx,
4059 struct dcerpc_pipe *p,
4060 struct policy_handle *handle)
4062 struct spoolss_DeletePrinter r;
4064 torture_comment(tctx, "Testing DeletePrinter\n");
4066 r.in.handle = handle;
4068 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_DeletePrinter(p, tctx, &r),
4069 "failed to delete printer");
4070 torture_assert_werr_ok(tctx, r.out.result,
4071 "failed to delete printer");
4073 return true;
4076 static bool test_EnumPrinters_findname(struct torture_context *tctx,
4077 struct dcerpc_pipe *p,
4078 uint32_t flags,
4079 uint32_t level,
4080 const char *name,
4081 bool *found)
4083 struct spoolss_EnumPrinters e;
4084 uint32_t count;
4085 union spoolss_PrinterInfo *info;
4086 uint32_t needed;
4087 int i;
4089 *found = false;
4091 e.in.flags = flags;
4092 e.in.server = NULL;
4093 e.in.level = level;
4094 e.in.buffer = NULL;
4095 e.in.offered = 0;
4096 e.out.count = &count;
4097 e.out.info = &info;
4098 e.out.needed = &needed;
4100 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_EnumPrinters(p, tctx, &e),
4101 "failed to enum printers");
4103 if (W_ERROR_EQUAL(e.out.result, WERR_INSUFFICIENT_BUFFER)) {
4104 DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed);
4105 data_blob_clear(&blob);
4106 e.in.buffer = &blob;
4107 e.in.offered = needed;
4109 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_EnumPrinters(p, tctx, &e),
4110 "failed to enum printers");
4113 torture_assert_werr_ok(tctx, e.out.result,
4114 "failed to enum printers");
4116 for (i=0; i < count; i++) {
4118 const char *current = NULL;
4119 const char *p;
4121 switch (level) {
4122 case 1:
4123 current = info[i].info1.name;
4124 break;
4127 if (strequal(current, name)) {
4128 *found = true;
4129 break;
4132 p = strrchr(current, '\\');
4133 if (p) {
4134 if (!e.in.server) {
4135 torture_warning(tctx,
4136 "server returns printername %s incl. servername although we did not set servername", current);
4138 p++;
4139 if (strequal(p, name)) {
4140 *found = true;
4141 break;
4146 return true;
4149 static bool test_AddPrinter_wellknown(struct torture_context *tctx,
4150 struct dcerpc_pipe *p,
4151 const char *printername,
4152 bool ex)
4154 WERROR result;
4155 struct spoolss_AddPrinter r;
4156 struct spoolss_AddPrinterEx rex;
4157 struct spoolss_SetPrinterInfoCtr info_ctr;
4158 struct spoolss_SetPrinterInfo1 info1;
4159 struct spoolss_DevmodeContainer devmode_ctr;
4160 struct sec_desc_buf secdesc_ctr;
4161 struct spoolss_UserLevelCtr userlevel_ctr;
4162 struct policy_handle handle;
4163 bool found = false;
4165 ZERO_STRUCT(devmode_ctr);
4166 ZERO_STRUCT(secdesc_ctr);
4167 ZERO_STRUCT(userlevel_ctr);
4168 ZERO_STRUCT(info1);
4170 torture_comment(tctx, "Testing AddPrinter%s level 1\n", ex ? "Ex":"");
4172 /* try to add printer to wellknown printer list (level 1) */
4174 userlevel_ctr.level = 1;
4176 info_ctr.info.info1 = &info1;
4177 info_ctr.level = 1;
4179 rex.in.server = NULL;
4180 rex.in.info_ctr = &info_ctr;
4181 rex.in.devmode_ctr = &devmode_ctr;
4182 rex.in.secdesc_ctr = &secdesc_ctr;
4183 rex.in.userlevel_ctr = &userlevel_ctr;
4184 rex.out.handle = &handle;
4186 r.in.server = NULL;
4187 r.in.info_ctr = &info_ctr;
4188 r.in.devmode_ctr = &devmode_ctr;
4189 r.in.secdesc_ctr = &secdesc_ctr;
4190 r.out.handle = &handle;
4192 torture_assert_ntstatus_ok(tctx, ex ? dcerpc_spoolss_AddPrinterEx(p, tctx, &rex) :
4193 dcerpc_spoolss_AddPrinter(p, tctx, &r),
4194 "failed to add printer");
4195 result = ex ? rex.out.result : r.out.result;
4196 torture_assert_werr_equal(tctx, result, WERR_INVALID_PRINTER_NAME,
4197 "unexpected result code");
4199 info1.name = printername;
4200 info1.flags = PRINTER_ATTRIBUTE_SHARED;
4202 torture_assert_ntstatus_ok(tctx, ex ? dcerpc_spoolss_AddPrinterEx(p, tctx, &rex) :
4203 dcerpc_spoolss_AddPrinter(p, tctx, &r),
4204 "failed to add printer");
4205 result = ex ? rex.out.result : r.out.result;
4206 torture_assert_werr_equal(tctx, result, WERR_PRINTER_ALREADY_EXISTS,
4207 "unexpected result code");
4209 /* bizarre protocol, WERR_PRINTER_ALREADY_EXISTS means success here,
4210 better do a real check to see the printer is really there */
4212 torture_assert(tctx, test_EnumPrinters_findname(tctx, p,
4213 PRINTER_ENUM_NETWORK, 1,
4214 printername,
4215 &found),
4216 "failed to enum printers");
4218 torture_assert(tctx, found, "failed to find newly added printer");
4220 info1.flags = 0;
4222 torture_assert_ntstatus_ok(tctx, ex ? dcerpc_spoolss_AddPrinterEx(p, tctx, &rex) :
4223 dcerpc_spoolss_AddPrinter(p, tctx, &r),
4224 "failed to add printer");
4225 result = ex ? rex.out.result : r.out.result;
4226 torture_assert_werr_equal(tctx, result, WERR_PRINTER_ALREADY_EXISTS,
4227 "unexpected result code");
4229 /* bizarre protocol, WERR_PRINTER_ALREADY_EXISTS means success here,
4230 better do a real check to see the printer has really been removed
4231 from the well known printer list */
4233 found = false;
4235 torture_assert(tctx, test_EnumPrinters_findname(tctx, p,
4236 PRINTER_ENUM_NETWORK, 1,
4237 printername,
4238 &found),
4239 "failed to enum printers");
4240 #if 0
4241 torture_assert(tctx, !found, "printer still in well known printer list");
4242 #endif
4243 return true;
4246 static bool test_AddPrinter_normal(struct torture_context *tctx,
4247 struct dcerpc_pipe *p,
4248 struct policy_handle *handle_p,
4249 const char *printername,
4250 const char *drivername,
4251 const char *portname,
4252 bool ex)
4254 WERROR result;
4255 struct spoolss_AddPrinter r;
4256 struct spoolss_AddPrinterEx rex;
4257 struct spoolss_SetPrinterInfoCtr info_ctr;
4258 struct spoolss_SetPrinterInfo2 info2;
4259 struct spoolss_DevmodeContainer devmode_ctr;
4260 struct sec_desc_buf secdesc_ctr;
4261 struct spoolss_UserLevelCtr userlevel_ctr;
4262 struct policy_handle handle;
4263 bool found = false;
4264 bool existing_printer_deleted = false;
4266 ZERO_STRUCT(devmode_ctr);
4267 ZERO_STRUCT(secdesc_ctr);
4268 ZERO_STRUCT(userlevel_ctr);
4270 torture_comment(tctx, "Testing AddPrinter%s level 2\n", ex ? "Ex":"");
4272 userlevel_ctr.level = 1;
4274 rex.in.server = NULL;
4275 rex.in.info_ctr = &info_ctr;
4276 rex.in.devmode_ctr = &devmode_ctr;
4277 rex.in.secdesc_ctr = &secdesc_ctr;
4278 rex.in.userlevel_ctr = &userlevel_ctr;
4279 rex.out.handle = &handle;
4281 r.in.server = NULL;
4282 r.in.info_ctr = &info_ctr;
4283 r.in.devmode_ctr = &devmode_ctr;
4284 r.in.secdesc_ctr = &secdesc_ctr;
4285 r.out.handle = &handle;
4287 again:
4289 /* try to add printer to printer list (level 2) */
4291 ZERO_STRUCT(info2);
4293 info_ctr.info.info2 = &info2;
4294 info_ctr.level = 2;
4296 torture_assert_ntstatus_ok(tctx, ex ? dcerpc_spoolss_AddPrinterEx(p, tctx, &rex) :
4297 dcerpc_spoolss_AddPrinter(p, tctx, &r),
4298 "failed to add printer");
4299 result = ex ? rex.out.result : r.out.result;
4300 torture_assert_werr_equal(tctx, result, WERR_INVALID_PRINTER_NAME,
4301 "unexpected result code");
4303 info2.printername = printername;
4305 torture_assert_ntstatus_ok(tctx, ex ? dcerpc_spoolss_AddPrinterEx(p, tctx, &rex) :
4306 dcerpc_spoolss_AddPrinter(p, tctx, &r),
4307 "failed to add printer");
4308 result = ex ? rex.out.result : r.out.result;
4310 if (W_ERROR_EQUAL(result, WERR_PRINTER_ALREADY_EXISTS)) {
4311 struct policy_handle printer_handle;
4313 if (existing_printer_deleted) {
4314 torture_fail(tctx, "already deleted printer still existing?");
4317 torture_assert(tctx, call_OpenPrinterEx(tctx, p, printername, NULL, &printer_handle),
4318 "failed to open printer handle");
4320 torture_assert(tctx, test_DeletePrinter(tctx, p, &printer_handle),
4321 "failed to delete printer");
4323 torture_assert(tctx, test_ClosePrinter(tctx, p, &printer_handle),
4324 "failed to close server handle");
4326 existing_printer_deleted = true;
4328 goto again;
4331 torture_assert_werr_equal(tctx, result, WERR_UNKNOWN_PORT,
4332 "unexpected result code");
4334 info2.portname = portname;
4336 torture_assert_ntstatus_ok(tctx, ex ? dcerpc_spoolss_AddPrinterEx(p, tctx, &rex) :
4337 dcerpc_spoolss_AddPrinter(p, tctx, &r),
4338 "failed to add printer");
4339 result = ex ? rex.out.result : r.out.result;
4340 torture_assert_werr_equal(tctx, result, WERR_UNKNOWN_PRINTER_DRIVER,
4341 "unexpected result code");
4343 info2.drivername = drivername;
4345 torture_assert_ntstatus_ok(tctx, ex ? dcerpc_spoolss_AddPrinterEx(p, tctx, &rex) :
4346 dcerpc_spoolss_AddPrinter(p, tctx, &r),
4347 "failed to add printer");
4348 result = ex ? rex.out.result : r.out.result;
4350 /* w2k8r2 allows to add printer w/o defining printprocessor */
4352 if (!W_ERROR_IS_OK(result)) {
4353 torture_assert_werr_equal(tctx, result, WERR_UNKNOWN_PRINTPROCESSOR,
4354 "unexpected result code");
4356 info2.printprocessor = "winprint";
4358 torture_assert_ntstatus_ok(tctx, ex ? dcerpc_spoolss_AddPrinterEx(p, tctx, &rex) :
4359 dcerpc_spoolss_AddPrinter(p, tctx, &r),
4360 "failed to add printer");
4361 result = ex ? rex.out.result : r.out.result;
4362 torture_assert_werr_ok(tctx, result,
4363 "failed to add printer");
4366 *handle_p = handle;
4368 /* we are paranoid, really check if the printer is there now */
4370 torture_assert(tctx, test_EnumPrinters_findname(tctx, p,
4371 PRINTER_ENUM_LOCAL, 1,
4372 printername,
4373 &found),
4374 "failed to enum printers");
4375 torture_assert(tctx, found, "failed to find newly added printer");
4377 torture_assert_ntstatus_ok(tctx, ex ? dcerpc_spoolss_AddPrinterEx(p, tctx, &rex) :
4378 dcerpc_spoolss_AddPrinter(p, tctx, &r),
4379 "failed to add printer");
4380 result = ex ? rex.out.result : r.out.result;
4381 torture_assert_werr_equal(tctx, result, WERR_PRINTER_ALREADY_EXISTS,
4382 "unexpected result code");
4384 return true;
4387 static bool test_AddPrinterEx(struct torture_context *tctx,
4388 struct dcerpc_pipe *p,
4389 struct policy_handle *handle_p,
4390 const char *printername,
4391 const char *drivername,
4392 const char *portname)
4394 bool ret = true;
4396 if (!torture_setting_bool(tctx, "samba3", false)) {
4397 if (!test_AddPrinter_wellknown(tctx, p, TORTURE_WELLKNOWN_PRINTER_EX, true)) {
4398 torture_comment(tctx, "failed to add printer to well known list\n");
4399 ret = false;
4403 if (!test_AddPrinter_normal(tctx, p, handle_p,
4404 printername, drivername, portname,
4405 true)) {
4406 torture_comment(tctx, "failed to add printer to printer list\n");
4407 ret = false;
4410 return ret;
4413 static bool test_AddPrinter(struct torture_context *tctx,
4414 struct dcerpc_pipe *p,
4415 struct policy_handle *handle_p,
4416 const char *printername,
4417 const char *drivername,
4418 const char *portname)
4420 bool ret = true;
4422 if (!torture_setting_bool(tctx, "samba3", false)) {
4423 if (!test_AddPrinter_wellknown(tctx, p, TORTURE_WELLKNOWN_PRINTER, false)) {
4424 torture_comment(tctx, "failed to add printer to well known list\n");
4425 ret = false;
4429 if (!test_AddPrinter_normal(tctx, p, handle_p,
4430 printername, drivername, portname,
4431 false)) {
4432 torture_comment(tctx, "failed to add printer to printer list\n");
4433 ret = false;
4436 return ret;
4439 static bool test_printer_info(struct torture_context *tctx,
4440 struct dcerpc_pipe *p,
4441 struct policy_handle *handle)
4443 bool ret = true;
4445 if (torture_setting_bool(tctx, "samba3", false)) {
4446 torture_skip(tctx, "skipping printer info cross tests against samba 3");
4449 if (!test_PrinterInfo(tctx, p, handle)) {
4450 ret = false;
4453 if (!test_SetPrinter_errors(tctx, p, handle)) {
4454 ret = false;
4457 return ret;
4460 static bool test_EnumPrinterKey(struct torture_context *tctx,
4461 struct dcerpc_pipe *p,
4462 struct policy_handle *handle,
4463 const char *key_name,
4464 const char ***array)
4466 struct spoolss_EnumPrinterKey r;
4467 uint32_t needed = 0;
4468 union spoolss_KeyNames key_buffer;
4469 int32_t offered[] = { 0, 1, 2, 3, 4, 5, -1, -2, -3, -4, -5, 256, 512, 1024, 2048 };
4470 uint32_t _ndr_size;
4471 int i;
4473 r.in.handle = handle;
4474 r.in.key_name = key_name;
4475 r.out.key_buffer = &key_buffer;
4476 r.out.needed = &needed;
4477 r.out._ndr_size = &_ndr_size;
4479 for (i=0; i < ARRAY_SIZE(offered); i++) {
4481 if (offered[i] < 0 && needed) {
4482 if (needed <= 4) {
4483 continue;
4485 r.in.offered = needed + offered[i];
4486 } else {
4487 r.in.offered = offered[i];
4490 ZERO_STRUCT(key_buffer);
4492 torture_comment(tctx, "Testing EnumPrinterKey(%s) with %d offered\n", r.in.key_name, r.in.offered);
4494 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_EnumPrinterKey(p, tctx, &r),
4495 "failed to call EnumPrinterKey");
4496 if (W_ERROR_EQUAL(r.out.result, WERR_MORE_DATA)) {
4498 torture_assert(tctx, (_ndr_size == r.in.offered/2),
4499 talloc_asprintf(tctx, "EnumPrinterKey size mismatch, _ndr_size %d (expected %d)",
4500 _ndr_size, r.in.offered/2));
4502 r.in.offered = needed;
4503 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_EnumPrinterKey(p, tctx, &r),
4504 "failed to call EnumPrinterKey");
4507 if (offered[i] > 0) {
4508 torture_assert_werr_ok(tctx, r.out.result,
4509 "failed to call EnumPrinterKey");
4512 torture_assert(tctx, (_ndr_size == r.in.offered/2),
4513 talloc_asprintf(tctx, "EnumPrinterKey size mismatch, _ndr_size %d (expected %d)",
4514 _ndr_size, r.in.offered/2));
4516 torture_assert(tctx, (*r.out.needed <= r.in.offered),
4517 talloc_asprintf(tctx, "EnumPrinterKey size mismatch: needed %d is not <= offered %d", *r.out.needed, r.in.offered));
4519 torture_assert(tctx, (*r.out.needed <= _ndr_size * 2),
4520 talloc_asprintf(tctx, "EnumPrinterKey size mismatch: needed %d is not <= _ndr_size %d * 2", *r.out.needed, _ndr_size));
4522 if (key_buffer.string_array) {
4523 uint32_t calc_needed = 0;
4524 int s;
4525 for (s=0; key_buffer.string_array[s]; s++) {
4526 calc_needed += strlen_m_term(key_buffer.string_array[s])*2;
4528 if (!key_buffer.string_array[0]) {
4529 calc_needed += 2;
4531 calc_needed += 2;
4533 torture_assert_int_equal(tctx, *r.out.needed, calc_needed,
4534 "EnumPrinterKey unexpected size");
4538 if (array) {
4539 *array = key_buffer.string_array;
4542 return true;
4545 bool test_printer_keys(struct torture_context *tctx,
4546 struct dcerpc_pipe *p,
4547 struct policy_handle *handle)
4549 const char **key_array = NULL;
4550 int i;
4552 torture_comment(tctx, "\nTesting Printer Keys\n");
4554 torture_assert(tctx, test_EnumPrinterKey(tctx, p, handle, "", &key_array),
4555 "failed to call test_EnumPrinterKey");
4557 for (i=0; key_array && key_array[i]; i++) {
4558 torture_assert(tctx, test_EnumPrinterKey(tctx, p, handle, key_array[i], NULL),
4559 "failed to call test_EnumPrinterKey");
4561 for (i=0; key_array && key_array[i]; i++) {
4562 torture_assert(tctx, test_EnumPrinterDataEx(tctx, p, handle, key_array[i]),
4563 "failed to call test_EnumPrinterDataEx");
4566 return true;
4569 static bool test_one_printer(struct torture_context *tctx,
4570 struct dcerpc_pipe *p,
4571 struct policy_handle *handle,
4572 const char *name)
4574 bool ret = true;
4576 if (!test_printer_info(tctx, p, handle)) {
4577 ret = false;
4580 if (!test_PrinterInfo_SD(tctx, p, handle)) {
4581 ret = false;
4584 if (!test_PrinterInfo_DevMode(tctx, p, handle, name)) {
4585 ret = false;
4588 if (!test_ChangeID(tctx, p, handle)) {
4589 ret = false;
4592 if (!test_printer_keys(tctx, p, handle)) {
4593 ret = false;
4596 if (!test_SetPrinterDataEx_matrix(tctx, p, handle)) {
4597 ret = false;
4600 return ret;
4603 static bool test_printer(struct torture_context *tctx,
4604 struct dcerpc_pipe *p)
4606 bool ret = true;
4607 struct policy_handle handle[2];
4608 bool found = false;
4609 const char *drivername = "Microsoft XPS Document Writer";
4610 const char *portname = "LPT1:";
4612 /* test printer created via AddPrinter */
4614 if (!test_AddPrinter(tctx, p, &handle[0], TORTURE_PRINTER, drivername, portname)) {
4615 return false;
4618 if (!test_one_printer(tctx, p, &handle[0], TORTURE_PRINTER)) {
4619 ret = false;
4622 if (!test_DeletePrinter(tctx, p, &handle[0])) {
4623 ret = false;
4626 if (!test_EnumPrinters_findname(tctx, p, PRINTER_ENUM_LOCAL, 1,
4627 TORTURE_PRINTER, &found)) {
4628 ret = false;
4631 torture_assert(tctx, !found, "deleted printer still there");
4633 /* test printer created via AddPrinterEx */
4635 if (!test_AddPrinterEx(tctx, p, &handle[1], TORTURE_PRINTER_EX, drivername, portname)) {
4636 return false;
4639 if (!test_one_printer(tctx, p, &handle[1], TORTURE_PRINTER_EX)) {
4640 ret = false;
4643 if (!test_DeletePrinter(tctx, p, &handle[1])) {
4644 ret = false;
4647 if (!test_EnumPrinters_findname(tctx, p, PRINTER_ENUM_LOCAL, 1,
4648 TORTURE_PRINTER_EX, &found)) {
4649 ret = false;
4652 torture_assert(tctx, !found, "deleted printer still there");
4654 return ret;
4657 static bool test_architecture_buffer(struct torture_context *tctx,
4658 struct dcerpc_pipe *p)
4660 struct spoolss_OpenPrinterEx r;
4661 struct spoolss_UserLevel1 u1;
4662 struct policy_handle handle;
4663 uint32_t architectures[] = {
4664 PROCESSOR_ARCHITECTURE_INTEL,
4665 PROCESSOR_ARCHITECTURE_IA64,
4666 PROCESSOR_ARCHITECTURE_AMD64
4668 uint32_t needed[3];
4669 int i;
4671 for (i=0; i < ARRAY_SIZE(architectures); i++) {
4673 torture_comment(tctx, "Testing OpenPrinterEx with architecture %d\n", architectures[i]);
4675 u1.size = 0;
4676 u1.client = NULL;
4677 u1.user = NULL;
4678 u1.build = 0;
4679 u1.major = 3;
4680 u1.minor = 0;
4681 u1.processor = architectures[i];
4683 r.in.printername = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
4684 r.in.datatype = NULL;
4685 r.in.devmode_ctr.devmode= NULL;
4686 r.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
4687 r.in.level = 1;
4688 r.in.userlevel.level1 = &u1;
4689 r.out.handle = &handle;
4691 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_OpenPrinterEx(p, tctx, &r), "");
4692 torture_assert_werr_ok(tctx, r.out.result, "");
4695 struct spoolss_EnumPrinters e;
4696 uint32_t count;
4697 union spoolss_PrinterInfo *info;
4699 e.in.flags = PRINTER_ENUM_LOCAL;
4700 e.in.server = NULL;
4701 e.in.level = 2;
4702 e.in.buffer = NULL;
4703 e.in.offered = 0;
4704 e.out.count = &count;
4705 e.out.info = &info;
4706 e.out.needed = &needed[i];
4708 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_EnumPrinters(p, tctx, &e), "");
4709 #if 0
4710 torture_comment(tctx, "needed was %d\n", needed[i]);
4711 #endif
4714 torture_assert(tctx, test_ClosePrinter(tctx, p, &handle), "");
4717 for (i=1; i < ARRAY_SIZE(architectures); i++) {
4718 if (needed[i-1] != needed[i]) {
4719 torture_fail(tctx,
4720 talloc_asprintf(tctx, "needed size %d for architecture %d != needed size %d for architecture %d\n",
4721 needed[i-1], architectures[i-1], needed[i], architectures[i]));
4725 return true;
4728 bool torture_rpc_spoolss(struct torture_context *torture)
4730 NTSTATUS status;
4731 struct dcerpc_pipe *p;
4732 bool ret = true;
4733 struct test_spoolss_context *ctx;
4734 const char *environment = SPOOLSS_ARCHITECTURE_NT_X86;
4736 status = torture_rpc_connection(torture, &p, &ndr_table_spoolss);
4737 if (!NT_STATUS_IS_OK(status)) {
4738 return false;
4741 ctx = talloc_zero(torture, struct test_spoolss_context);
4743 ret &= test_OpenPrinter_server(torture, p, &ctx->server_handle);
4744 ret &= test_GetPrinterData_list(torture, p, &ctx->server_handle);
4745 ret &= test_EnumForms(torture, p, &ctx->server_handle, true);
4746 ret &= test_AddForm(torture, p, &ctx->server_handle, true);
4747 ret &= test_EnumPorts(torture, p, ctx);
4748 ret &= test_GetPrinterDriverDirectory(torture, p, ctx, environment);
4749 ret &= test_GetPrintProcessorDirectory(torture, p, ctx, environment);
4750 ret &= test_EnumPrinterDrivers(torture, p, ctx, environment);
4751 ret &= test_EnumPrinterDrivers(torture, p, ctx, SPOOLSS_ARCHITECTURE_ALL);
4752 ret &= test_EnumMonitors(torture, p, ctx);
4753 ret &= test_EnumPrintProcessors(torture, p, ctx, environment);
4754 ret &= test_EnumPrintProcDataTypes(torture, p, ctx);
4755 ret &= test_EnumPrinters(torture, p, ctx);
4756 ret &= test_OpenPrinter_badname(torture, p, "__INVALID_PRINTER__");
4757 ret &= test_OpenPrinter_badname(torture, p, "\\\\__INVALID_HOST__");
4758 ret &= test_OpenPrinter_badname(torture, p, "");
4759 ret &= test_OpenPrinter_badname(torture, p, "\\\\\\");
4760 ret &= test_OpenPrinter_badname(torture, p, "\\\\\\__INVALID_PRINTER__");
4761 ret &= test_OpenPrinter_badname(torture, p, talloc_asprintf(torture, "\\\\%s\\", dcerpc_server_name(p)));
4762 ret &= test_OpenPrinter_badname(torture, p,
4763 talloc_asprintf(torture, "\\\\%s\\__INVALID_PRINTER__", dcerpc_server_name(p)));
4766 ret &= test_AddPort(torture, p);
4767 ret &= test_EnumPorts_old(torture, p);
4768 ret &= test_EnumPrinters_old(torture, p, environment);
4769 ret &= test_EnumPrinterDrivers_old(torture, p, environment);
4770 ret &= test_architecture_buffer(torture, p);
4772 return ret;
4775 struct torture_suite *torture_rpc_spoolss_printer(TALLOC_CTX *mem_ctx)
4777 struct torture_suite *suite = torture_suite_create(mem_ctx, "SPOOLSS-PRINTER");
4779 struct torture_rpc_tcase *tcase = torture_suite_add_rpc_iface_tcase(suite,
4780 "printer", &ndr_table_spoolss);
4782 torture_rpc_tcase_add_test(tcase, "printer", test_printer);
4784 return suite;