s4-smbtorture: fix smbtorture after GetPrinterData{Ex} after IDL changes.
[Samba/cd1.git] / source4 / torture / rpc / spoolss.c
blobaad42a6e1a5f924838a37f87e3e5126ff1563bbf
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 uint8_t **data_p,
2849 uint32_t *needed_p)
2851 NTSTATUS status;
2852 struct spoolss_GetPrinterData r;
2853 uint32_t needed;
2854 enum winreg_Type type;
2855 union spoolss_PrinterData data;
2857 r.in.handle = handle;
2858 r.in.value_name = value_name;
2859 r.in.offered = 0;
2860 r.out.needed = &needed;
2861 r.out.type = &type;
2862 r.out.data = talloc_zero_array(tctx, uint8_t, r.in.offered);
2864 torture_comment(tctx, "Testing GetPrinterData(%s)\n", r.in.value_name);
2866 status = dcerpc_spoolss_GetPrinterData(p, tctx, &r);
2867 torture_assert_ntstatus_ok(tctx, status, "GetPrinterData failed");
2869 if (W_ERROR_EQUAL(r.out.result, WERR_MORE_DATA)) {
2870 r.in.offered = needed;
2871 r.out.data = talloc_zero_array(tctx, uint8_t, r.in.offered);
2872 status = dcerpc_spoolss_GetPrinterData(p, tctx, &r);
2873 torture_assert_ntstatus_ok(tctx, status, "GetPrinterData failed");
2876 torture_assert_werr_ok(tctx, r.out.result,
2877 talloc_asprintf(tctx, "GetPrinterData(%s) failed", r.in.value_name));
2879 CHECK_NEEDED_SIZE_LEVEL(spoolss_PrinterData, &data, type, lp_iconv_convenience(tctx->lp_ctx), needed, 1);
2881 if (type_p) {
2882 *type_p = type;
2885 if (data_p) {
2886 *data_p = r.out.data;
2889 if (needed_p) {
2890 *needed_p = needed;
2893 return true;
2896 static bool test_GetPrinterDataEx(struct torture_context *tctx,
2897 struct dcerpc_pipe *p,
2898 struct policy_handle *handle,
2899 const char *key_name,
2900 const char *value_name,
2901 enum winreg_Type *type_p,
2902 uint8_t **data_p,
2903 uint32_t *needed_p)
2905 NTSTATUS status;
2906 struct spoolss_GetPrinterDataEx r;
2907 enum winreg_Type type;
2908 uint32_t needed;
2909 union spoolss_PrinterData data;
2911 r.in.handle = handle;
2912 r.in.key_name = key_name;
2913 r.in.value_name = value_name;
2914 r.in.offered = 0;
2915 r.out.type = &type;
2916 r.out.needed = &needed;
2917 r.out.data = talloc_zero_array(tctx, uint8_t, r.in.offered);
2919 torture_comment(tctx, "Testing GetPrinterDataEx(%s - %s)\n",
2920 r.in.key_name, r.in.value_name);
2922 status = dcerpc_spoolss_GetPrinterDataEx(p, tctx, &r);
2923 if (!NT_STATUS_IS_OK(status)) {
2924 if (NT_STATUS_EQUAL(status,NT_STATUS_NET_WRITE_FAULT) &&
2925 p->last_fault_code == DCERPC_FAULT_OP_RNG_ERROR) {
2926 torture_skip(tctx, "GetPrinterDataEx not supported by server\n");
2928 torture_assert_ntstatus_ok(tctx, status, "GetPrinterDataEx failed");
2931 if (W_ERROR_EQUAL(r.out.result, WERR_MORE_DATA)) {
2932 r.in.offered = needed;
2933 r.out.data = talloc_zero_array(tctx, uint8_t, r.in.offered);
2934 status = dcerpc_spoolss_GetPrinterDataEx(p, tctx, &r);
2935 torture_assert_ntstatus_ok(tctx, status, "GetPrinterDataEx failed");
2938 torture_assert_werr_ok(tctx, r.out.result,
2939 talloc_asprintf(tctx, "GetPrinterDataEx(%s - %s) failed", r.in.key_name, r.in.value_name));
2941 CHECK_NEEDED_SIZE_LEVEL(spoolss_PrinterData, &data, type, lp_iconv_convenience(tctx->lp_ctx), needed, 1);
2943 if (type_p) {
2944 *type_p = type;
2947 if (data_p) {
2948 *data_p = r.out.data;
2951 if (needed_p) {
2952 *needed_p = needed;
2955 return true;
2958 static bool test_GetPrinterData_list(struct torture_context *tctx,
2959 struct dcerpc_pipe *p,
2960 struct policy_handle *handle)
2962 const char *list[] = {
2963 "W3SvcInstalled",
2964 "BeepEnabled",
2965 "EventLog",
2966 /* "NetPopup", not on w2k8 */
2967 /* "NetPopupToComputer", not on w2k8 */
2968 "MajorVersion",
2969 "MinorVersion",
2970 "DefaultSpoolDirectory",
2971 "Architecture",
2972 "DsPresent",
2973 "OSVersion",
2974 /* "OSVersionEx", not on s3 */
2975 "DNSMachineName"
2977 int i;
2979 for (i=0; i < ARRAY_SIZE(list); i++) {
2980 enum winreg_Type type, type_ex;
2981 uint8_t *data, *data_ex;
2982 uint32_t needed, needed_ex;
2984 torture_assert(tctx, test_GetPrinterData(tctx, p, handle, list[i], &type, &data, &needed),
2985 talloc_asprintf(tctx, "GetPrinterData failed on %s\n", list[i]));
2986 torture_assert(tctx, test_GetPrinterDataEx(tctx, p, handle, "random_string", list[i], &type_ex, &data_ex, &needed_ex),
2987 talloc_asprintf(tctx, "GetPrinterDataEx failed on %s\n", list[i]));
2988 torture_assert_int_equal(tctx, type, type_ex, "type mismatch");
2989 torture_assert_int_equal(tctx, needed, needed_ex, "needed mismatch");
2990 torture_assert_mem_equal(tctx, data, data_ex, needed, "data mismatch");
2993 return true;
2996 static bool test_EnumPrinterData(struct torture_context *tctx, struct dcerpc_pipe *p,
2997 struct policy_handle *handle)
2999 NTSTATUS status;
3000 struct spoolss_EnumPrinterData r;
3002 ZERO_STRUCT(r);
3003 r.in.handle = handle;
3004 r.in.enum_index = 0;
3006 do {
3007 uint32_t value_size = 0;
3008 uint32_t data_size = 0;
3009 enum winreg_Type type = 0;
3011 r.in.value_offered = value_size;
3012 r.out.value_needed = &value_size;
3013 r.in.data_offered = data_size;
3014 r.out.data_needed = &data_size;
3016 r.out.type = &type;
3017 r.out.data = talloc_zero_array(tctx, uint8_t, 0);
3019 torture_comment(tctx, "Testing EnumPrinterData\n");
3021 status = dcerpc_spoolss_EnumPrinterData(p, tctx, &r);
3023 torture_assert_ntstatus_ok(tctx, status, "EnumPrinterData failed");
3024 if (W_ERROR_EQUAL(r.out.result, WERR_NO_MORE_ITEMS)) {
3025 break;
3027 torture_assert_werr_ok(tctx, r.out.result, "EnumPrinterData");
3029 r.in.value_offered = value_size;
3030 r.out.value_name = talloc_zero_array(tctx, const char, value_size);
3031 r.in.data_offered = data_size;
3032 r.out.data = talloc_zero_array(tctx, uint8_t, data_size);
3034 status = dcerpc_spoolss_EnumPrinterData(p, tctx, &r);
3036 torture_assert_ntstatus_ok(tctx, status, "EnumPrinterData failed");
3037 if (W_ERROR_EQUAL(r.out.result, WERR_NO_MORE_ITEMS)) {
3038 break;
3041 torture_assert_werr_ok(tctx, r.out.result, "EnumPrinterData failed");
3043 torture_assert(tctx, test_GetPrinterData(tctx, p, handle, r.out.value_name, NULL, NULL, NULL),
3044 talloc_asprintf(tctx, "failed to call GetPrinterData for %s\n", r.out.value_name));
3046 torture_assert(tctx, test_GetPrinterDataEx(tctx, p, handle, "PrinterDriverData", r.out.value_name, NULL, NULL, NULL),
3047 talloc_asprintf(tctx, "failed to call GetPrinterDataEx on PrinterDriverData for %s\n", r.out.value_name));
3049 r.in.enum_index++;
3051 } while (W_ERROR_IS_OK(r.out.result));
3053 return true;
3056 static bool test_EnumPrinterDataEx(struct torture_context *tctx,
3057 struct dcerpc_pipe *p,
3058 struct policy_handle *handle,
3059 const char *key_name)
3061 struct spoolss_EnumPrinterDataEx r;
3062 struct spoolss_PrinterEnumValues *info;
3063 uint32_t needed;
3064 uint32_t count;
3066 r.in.handle = handle;
3067 r.in.key_name = key_name;
3068 r.in.offered = 0;
3069 r.out.needed = &needed;
3070 r.out.count = &count;
3071 r.out.info = &info;
3073 torture_comment(tctx, "Testing EnumPrinterDataEx(%s)\n", key_name);
3075 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_EnumPrinterDataEx(p, tctx, &r),
3076 "EnumPrinterDataEx failed");
3077 if (W_ERROR_EQUAL(r.out.result, WERR_MORE_DATA)) {
3078 r.in.offered = needed;
3079 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_EnumPrinterDataEx(p, tctx, &r),
3080 "EnumPrinterDataEx failed");
3083 torture_assert_werr_ok(tctx, r.out.result, "EnumPrinterDataEx failed");
3085 CHECK_NEEDED_SIZE_ENUM(spoolss_EnumPrinterDataEx, info, count, lp_iconv_convenience(tctx->lp_ctx), needed, 1);
3087 return true;
3091 static bool test_DeletePrinterData(struct torture_context *tctx,
3092 struct dcerpc_pipe *p,
3093 struct policy_handle *handle,
3094 const char *value_name)
3096 NTSTATUS status;
3097 struct spoolss_DeletePrinterData r;
3099 r.in.handle = handle;
3100 r.in.value_name = value_name;
3102 torture_comment(tctx, "Testing DeletePrinterData(%s)\n",
3103 r.in.value_name);
3105 status = dcerpc_spoolss_DeletePrinterData(p, tctx, &r);
3107 torture_assert_ntstatus_ok(tctx, status, "DeletePrinterData failed");
3108 torture_assert_werr_ok(tctx, r.out.result, "DeletePrinterData failed");
3110 return true;
3113 static bool test_DeletePrinterDataEx(struct torture_context *tctx,
3114 struct dcerpc_pipe *p,
3115 struct policy_handle *handle,
3116 const char *key_name,
3117 const char *value_name)
3119 struct spoolss_DeletePrinterDataEx r;
3121 r.in.handle = handle;
3122 r.in.key_name = key_name;
3123 r.in.value_name = value_name;
3125 torture_comment(tctx, "Testing DeletePrinterDataEx(%s - %s)\n",
3126 r.in.key_name, r.in.value_name);
3128 torture_assert_ntstatus_ok(tctx,
3129 dcerpc_spoolss_DeletePrinterDataEx(p, tctx, &r),
3130 "DeletePrinterDataEx failed");
3131 torture_assert_werr_ok(tctx, r.out.result,
3132 "DeletePrinterDataEx failed");
3134 return true;
3137 static bool test_DeletePrinterKey(struct torture_context *tctx,
3138 struct dcerpc_pipe *p,
3139 struct policy_handle *handle,
3140 const char *key_name)
3142 struct spoolss_DeletePrinterKey r;
3144 r.in.handle = handle;
3145 r.in.key_name = key_name;
3147 torture_comment(tctx, "Testing DeletePrinterKey(%s)\n", r.in.key_name);
3149 if (strequal(key_name, "") && !torture_setting_bool(tctx, "dangerous", false)) {
3150 torture_skip(tctx, "not wiping out printer registry - enable dangerous tests to use\n");
3151 return true;
3154 torture_assert_ntstatus_ok(tctx,
3155 dcerpc_spoolss_DeletePrinterKey(p, tctx, &r),
3156 "DeletePrinterKey failed");
3157 torture_assert_werr_ok(tctx, r.out.result,
3158 "DeletePrinterKey failed");
3160 return true;
3163 static bool test_SetPrinterData(struct torture_context *tctx,
3164 struct dcerpc_pipe *p,
3165 struct policy_handle *handle)
3167 NTSTATUS status;
3168 struct spoolss_SetPrinterData r;
3169 const char *values[] = {
3170 "spootyfoot",
3171 "spooty\\foot",
3172 #if 0
3173 /* FIXME: not working with s3 atm. */
3174 "spooty,foot",
3175 "spooty,fo,ot",
3176 #endif
3177 "spooty foot",
3178 #if 0
3179 /* FIXME: not working with s3 atm. */
3180 "spooty\\fo,ot",
3181 "spooty,fo\\ot"
3182 #endif
3184 int i;
3186 for (i=0; i < ARRAY_SIZE(values); i++) {
3188 enum winreg_Type type;
3189 uint8_t *data;
3190 DATA_BLOB blob;
3191 uint32_t needed;
3193 torture_assert(tctx,
3194 reg_string_to_val(tctx, lp_iconv_convenience(tctx->lp_ctx),
3195 "REG_SZ", "dog", &r.in.type, &blob), "");
3197 r.in.handle = handle;
3198 r.in.value_name = values[i];
3199 r.in.data = blob.data;
3200 r.in.offered = blob.length;
3202 torture_comment(tctx, "Testing SetPrinterData(%s)\n",
3203 r.in.value_name);
3205 status = dcerpc_spoolss_SetPrinterData(p, tctx, &r);
3207 torture_assert_ntstatus_ok(tctx, status, "SetPrinterData failed");
3208 torture_assert_werr_ok(tctx, r.out.result, "SetPrinterData failed");
3210 if (!test_GetPrinterData(tctx, p, handle, r.in.value_name, &type, &data, &needed)) {
3211 return false;
3214 torture_assert_int_equal(tctx, r.in.type, type, "type mismatch");
3215 torture_assert_int_equal(tctx, r.in.offered, needed, "size mismatch");
3216 torture_assert_mem_equal(tctx, blob.data, data, needed, "buffer mismatch");
3218 if (!test_DeletePrinterData(tctx, p, handle, r.in.value_name)) {
3219 return false;
3223 return true;
3226 static bool test_EnumPrinterKey(struct torture_context *tctx,
3227 struct dcerpc_pipe *p,
3228 struct policy_handle *handle,
3229 const char *key_name,
3230 const char ***array);
3232 static bool test_SetPrinterDataEx(struct torture_context *tctx,
3233 struct dcerpc_pipe *p,
3234 struct policy_handle *handle,
3235 const char *key_name,
3236 const char *value_name,
3237 enum winreg_Type type,
3238 uint8_t *data,
3239 uint32_t offered)
3241 NTSTATUS status;
3242 struct spoolss_SetPrinterDataEx r;
3244 r.in.handle = handle;
3245 r.in.key_name = key_name;
3246 r.in.value_name = value_name;
3247 r.in.type = type;
3248 r.in.data = data;
3249 r.in.offered = offered;
3251 torture_comment(tctx, "Testing SetPrinterDataEx(%s - %s) type: %s, offered: 0x%08x\n",
3252 r.in.key_name, r.in.value_name, str_regtype(r.in.type), r.in.offered);
3254 status = dcerpc_spoolss_SetPrinterDataEx(p, tctx, &r);
3256 torture_assert_ntstatus_ok(tctx, status, "SetPrinterDataEx failed");
3257 torture_assert_werr_ok(tctx, r.out.result, "SetPrinterDataEx failed");
3259 return true;
3262 static bool test_SetPrinterDataEx_matrix(struct torture_context *tctx,
3263 struct dcerpc_pipe *p,
3264 struct policy_handle *handle)
3266 const char *value_name = "dog";
3267 const char *keys[] = {
3268 "torturedataex",
3269 "torture data ex",
3270 #if 0
3271 /* FIXME: not working with s3 atm. */
3272 "torturedataex_with_subkey\\subkey",
3273 "torturedataex_with_subkey\\subkey:0",
3274 "torturedataex_with_subkey\\subkey:1",
3275 "torturedataex_with_subkey\\subkey\\subsubkey",
3276 "torturedataex_with_subkey\\subkey\\subsubkey:0",
3277 "torturedataex_with_subkey\\subkey\\subsubkey:1",
3278 #endif
3279 "torture,data",
3280 #if 0
3281 /* FIXME: not working with s3 atm. */
3283 "torture,data,ex",
3284 "torture,data\\ex",
3285 "torture\\data,ex"
3286 #endif
3288 enum winreg_Type types[] = {
3289 REG_SZ,
3290 REG_DWORD,
3291 REG_BINARY
3293 uint32_t value = 12345678;
3294 const char *str = "abcdefghijklmnopqrstuvwxzy";
3295 int i, t, s;
3298 for (i=0; i < ARRAY_SIZE(keys); i++) {
3299 for (t=0; t < ARRAY_SIZE(types); t++) {
3300 for (s=0; s < strlen(str); s++) {
3302 char *c;
3303 const char *key;
3304 enum winreg_Type type;
3305 const char *string = talloc_strndup(tctx, str, s);
3306 DATA_BLOB blob = data_blob_string_const(string);
3307 const char **subkeys;
3308 DATA_BLOB data;
3309 uint8_t *data_out;
3310 uint32_t needed, offered = 0;
3312 if (types[t] == REG_DWORD) {
3313 s = 0xffff;
3316 switch (types[t]) {
3317 case REG_BINARY:
3318 data = blob;
3319 offered = blob.length;
3320 break;
3321 case REG_DWORD:
3322 data = data_blob(NULL, 4);
3323 SIVAL(data.data, 0, value);
3324 offered = 4;
3325 break;
3326 case REG_SZ:
3327 torture_assert(tctx,
3328 reg_string_to_val(tctx, lp_iconv_convenience(tctx->lp_ctx),
3329 "REG_SZ", string, &type, &data), "");
3330 offered = data.length;
3331 /*strlen_m_term(data.string)*2;*/
3332 break;
3333 default:
3334 torture_fail(tctx, talloc_asprintf(tctx, "type %d untested\n", types[t]));
3337 torture_assert(tctx,
3338 test_SetPrinterDataEx(tctx, p, handle, keys[i], value_name, types[t], data.data, offered),
3339 "failed to call SetPrinterDataEx");
3341 if (!test_GetPrinterDataEx(tctx, p, handle, keys[i], value_name, &type, &data_out, &needed)) {
3342 return false;
3345 /* special case, a REG_BINARY set with 0 size returns a 0 sized
3346 * REG_NONE - gd */
3347 if ((types[t] == REG_BINARY) && (offered == 0)) {
3348 torture_assert_int_equal(tctx, REG_NONE, type, "type mismatch");
3349 } else {
3350 torture_assert_int_equal(tctx, types[t], type, "type mismatch");
3352 torture_assert_int_equal(tctx, needed, offered, "size mismatch");
3353 torture_assert_mem_equal(tctx, data_out, data.data, offered, "buffer mismatch");
3355 key = talloc_strdup(tctx, keys[i]);
3357 if (!test_EnumPrinterDataEx(tctx, p, handle, keys[i])) {
3358 return false;
3361 if (!test_DeletePrinterDataEx(tctx, p, handle, keys[i], value_name)) {
3362 return false;
3365 c = strchr(key, '\\');
3366 if (c) {
3367 int i;
3369 /* we have subkeys */
3371 *c = 0;
3373 if (!test_EnumPrinterKey(tctx, p, handle, key, &subkeys)) {
3374 return false;
3377 for (i=0; subkeys && subkeys[i]; i++) {
3379 const char *current_key = talloc_asprintf(tctx, "%s\\%s", key, subkeys[i]);
3381 if (!test_DeletePrinterKey(tctx, p, handle, current_key)) {
3382 return false;
3386 if (!test_DeletePrinterKey(tctx, p, handle, key)) {
3387 return false;
3390 } else {
3391 if (!test_DeletePrinterKey(tctx, p, handle, key)) {
3392 return false;
3399 return true;
3402 static bool test_GetChangeID_PrinterData(struct torture_context *tctx,
3403 struct dcerpc_pipe *p,
3404 struct policy_handle *handle,
3405 uint32_t *change_id)
3407 enum winreg_Type type;
3408 uint8_t *data;
3409 uint32_t needed;
3411 torture_assert(tctx,
3412 test_GetPrinterData(tctx, p, handle, "ChangeID", &type, &data, &needed),
3413 "failed to call GetPrinterData");
3415 torture_assert(tctx, type == REG_DWORD, "unexpected type");
3416 torture_assert_int_equal(tctx, needed, 4, "unexpected size");
3418 *change_id = IVAL(data, 0);
3420 return true;
3423 static bool test_GetChangeID_PrinterDataEx(struct torture_context *tctx,
3424 struct dcerpc_pipe *p,
3425 struct policy_handle *handle,
3426 uint32_t *change_id)
3428 enum winreg_Type type;
3429 uint8_t *data;
3430 uint32_t needed;
3432 torture_assert(tctx,
3433 test_GetPrinterDataEx(tctx, p, handle, "PrinterDriverData", "ChangeID", &type, &data, &needed),
3434 "failed to call GetPrinterData");
3436 torture_assert(tctx, type == REG_DWORD, "unexpected type");
3437 torture_assert_int_equal(tctx, needed, 4, "unexpected size");
3439 *change_id = IVAL(data, 0);
3441 return true;
3444 static bool test_GetChangeID_PrinterInfo(struct torture_context *tctx,
3445 struct dcerpc_pipe *p,
3446 struct policy_handle *handle,
3447 uint32_t *change_id)
3449 union spoolss_PrinterInfo info;
3451 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 0, &info),
3452 "failed to query Printer level 0");
3454 *change_id = info.info0.change_id;
3456 return true;
3459 static bool test_ChangeID(struct torture_context *tctx,
3460 struct dcerpc_pipe *p,
3461 struct policy_handle *handle)
3463 uint32_t change_id, change_id_ex, change_id_info;
3464 uint32_t change_id2, change_id_ex2, change_id_info2;
3465 union spoolss_PrinterInfo info;
3466 const char *comment;
3469 torture_comment(tctx, "Testing ChangeID: id change test #1\n");
3471 torture_assert(tctx, test_GetChangeID_PrinterData(tctx, p, handle, &change_id),
3472 "failed to query for ChangeID");
3473 torture_assert(tctx, test_GetChangeID_PrinterDataEx(tctx, p, handle, &change_id_ex),
3474 "failed to query for ChangeID");
3475 torture_assert(tctx, test_GetChangeID_PrinterInfo(tctx, p, handle, &change_id_info),
3476 "failed to query for ChangeID");
3478 torture_assert_int_equal(tctx, change_id, change_id_ex,
3479 "change_ids should all be equal");
3480 torture_assert_int_equal(tctx, change_id_ex, change_id_info,
3481 "change_ids should all be equal");
3484 torture_comment(tctx, "Testing ChangeID: id change test #2\n");
3486 torture_assert(tctx, test_GetChangeID_PrinterData(tctx, p, handle, &change_id),
3487 "failed to query for ChangeID");
3488 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 2, &info),
3489 "failed to query Printer level 2");
3490 torture_assert(tctx, test_GetChangeID_PrinterDataEx(tctx, p, handle, &change_id_ex),
3491 "failed to query for ChangeID");
3492 torture_assert(tctx, test_GetChangeID_PrinterInfo(tctx, p, handle, &change_id_info),
3493 "failed to query for ChangeID");
3494 torture_assert_int_equal(tctx, change_id, change_id_ex,
3495 "change_id should not have changed");
3496 torture_assert_int_equal(tctx, change_id_ex, change_id_info,
3497 "change_id should not have changed");
3500 torture_comment(tctx, "Testing ChangeID: id change test #3\n");
3502 torture_assert(tctx, test_GetChangeID_PrinterData(tctx, p, handle, &change_id),
3503 "failed to query for ChangeID");
3504 torture_assert(tctx, test_GetChangeID_PrinterDataEx(tctx, p, handle, &change_id_ex),
3505 "failed to query for ChangeID");
3506 torture_assert(tctx, test_GetChangeID_PrinterInfo(tctx, p, handle, &change_id_info),
3507 "failed to query for ChangeID");
3508 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 2, &info),
3509 "failed to query Printer level 2");
3510 comment = talloc_strdup(tctx, info.info2.comment);
3513 struct spoolss_SetPrinterInfoCtr info_ctr;
3514 struct spoolss_DevmodeContainer devmode_ctr;
3515 struct sec_desc_buf secdesc_ctr;
3516 struct spoolss_SetPrinterInfo2 info2;
3518 ZERO_STRUCT(info_ctr);
3519 ZERO_STRUCT(devmode_ctr);
3520 ZERO_STRUCT(secdesc_ctr);
3522 info2.servername = info.info2.servername;
3523 info2.printername = info.info2.printername;
3524 info2.sharename = info.info2.sharename;
3525 info2.portname = info.info2.portname;
3526 info2.drivername = info.info2.drivername;
3527 info2.comment = "torture_comment";
3528 info2.location = info.info2.location;
3529 info2.devmode_ptr = 0;
3530 info2.sepfile = info.info2.sepfile;
3531 info2.printprocessor = info.info2.printprocessor;
3532 info2.datatype = info.info2.datatype;
3533 info2.parameters = info.info2.parameters;
3534 info2.secdesc_ptr = 0;
3535 info2.attributes = info.info2.attributes;
3536 info2.priority = info.info2.priority;
3537 info2.defaultpriority = info.info2.defaultpriority;
3538 info2.starttime = info.info2.starttime;
3539 info2.untiltime = info.info2.untiltime;
3540 info2.status = info.info2.status;
3541 info2.cjobs = info.info2.cjobs;
3542 info2.averageppm = info.info2.averageppm;
3544 info_ctr.level = 2;
3545 info_ctr.info.info2 = &info2;
3547 torture_assert(tctx, test_SetPrinter(tctx, p, handle, &info_ctr, &devmode_ctr, &secdesc_ctr, 0),
3548 "failed to call SetPrinter");
3550 info2.comment = comment;
3552 torture_assert(tctx, test_SetPrinter(tctx, p, handle, &info_ctr, &devmode_ctr, &secdesc_ctr, 0),
3553 "failed to call SetPrinter");
3557 torture_assert(tctx, test_GetChangeID_PrinterData(tctx, p, handle, &change_id2),
3558 "failed to query for ChangeID");
3559 torture_assert(tctx, test_GetChangeID_PrinterDataEx(tctx, p, handle, &change_id_ex2),
3560 "failed to query for ChangeID");
3561 torture_assert(tctx, test_GetChangeID_PrinterInfo(tctx, p, handle, &change_id_info2),
3562 "failed to query for ChangeID");
3564 torture_assert_int_equal(tctx, change_id2, change_id_ex2,
3565 "change_ids should all be equal");
3566 torture_assert_int_equal(tctx, change_id_ex2, change_id_info2,
3567 "change_ids should all be equal");
3569 torture_assert(tctx, (change_id < change_id2),
3570 talloc_asprintf(tctx, "change_id %d needs to be larger than change_id %d",
3571 change_id2, change_id));
3572 torture_assert(tctx, (change_id_ex < change_id_ex2),
3573 talloc_asprintf(tctx, "change_id %d needs to be larger than change_id %d",
3574 change_id_ex2, change_id_ex));
3575 torture_assert(tctx, (change_id_info < change_id_info2),
3576 talloc_asprintf(tctx, "change_id %d needs to be larger than change_id %d",
3577 change_id_info2, change_id_info));
3579 return true;
3582 static bool test_SecondaryClosePrinter(struct torture_context *tctx,
3583 struct dcerpc_pipe *p,
3584 struct policy_handle *handle)
3586 NTSTATUS status;
3587 struct dcerpc_binding *b;
3588 struct dcerpc_pipe *p2;
3589 struct spoolss_ClosePrinter cp;
3591 /* only makes sense on SMB */
3592 if (p->conn->transport.transport != NCACN_NP) {
3593 return true;
3596 torture_comment(tctx, "testing close on secondary pipe\n");
3598 status = dcerpc_parse_binding(tctx, p->conn->binding_string, &b);
3599 torture_assert_ntstatus_ok(tctx, status, "Failed to parse dcerpc binding");
3601 status = dcerpc_secondary_connection(p, &p2, b);
3602 torture_assert_ntstatus_ok(tctx, status, "Failed to create secondary connection");
3604 status = dcerpc_bind_auth_none(p2, &ndr_table_spoolss);
3605 torture_assert_ntstatus_ok(tctx, status, "Failed to create bind on secondary connection");
3607 cp.in.handle = handle;
3608 cp.out.handle = handle;
3610 status = dcerpc_spoolss_ClosePrinter(p2, tctx, &cp);
3611 torture_assert_ntstatus_equal(tctx, status, NT_STATUS_NET_WRITE_FAULT,
3612 "ERROR: Allowed close on secondary connection");
3614 torture_assert_int_equal(tctx, p2->last_fault_code, DCERPC_FAULT_CONTEXT_MISMATCH,
3615 "Unexpected fault code");
3617 talloc_free(p2);
3619 return true;
3622 static bool test_OpenPrinter_badname(struct torture_context *tctx,
3623 struct dcerpc_pipe *p, const char *name)
3625 NTSTATUS status;
3626 struct spoolss_OpenPrinter op;
3627 struct spoolss_OpenPrinterEx opEx;
3628 struct policy_handle handle;
3629 bool ret = true;
3631 op.in.printername = name;
3632 op.in.datatype = NULL;
3633 op.in.devmode_ctr.devmode= NULL;
3634 op.in.access_mask = 0;
3635 op.out.handle = &handle;
3637 torture_comment(tctx, "\nTesting OpenPrinter(%s) with bad name\n", op.in.printername);
3639 status = dcerpc_spoolss_OpenPrinter(p, tctx, &op);
3640 torture_assert_ntstatus_ok(tctx, status, "OpenPrinter failed");
3641 if (!W_ERROR_EQUAL(WERR_INVALID_PRINTER_NAME,op.out.result)) {
3642 torture_comment(tctx, "OpenPrinter(%s) unexpected result[%s] should be WERR_INVALID_PRINTER_NAME\n",
3643 name, win_errstr(op.out.result));
3646 if (W_ERROR_IS_OK(op.out.result)) {
3647 ret &=test_ClosePrinter(tctx, p, &handle);
3650 opEx.in.printername = name;
3651 opEx.in.datatype = NULL;
3652 opEx.in.devmode_ctr.devmode = NULL;
3653 opEx.in.access_mask = 0;
3654 opEx.in.level = 1;
3655 opEx.in.userlevel.level1 = NULL;
3656 opEx.out.handle = &handle;
3658 torture_comment(tctx, "Testing OpenPrinterEx(%s) with bad name\n", opEx.in.printername);
3660 status = dcerpc_spoolss_OpenPrinterEx(p, tctx, &opEx);
3661 torture_assert_ntstatus_ok(tctx, status, "OpenPrinterEx failed");
3662 if (!W_ERROR_EQUAL(WERR_INVALID_PARAM,opEx.out.result)) {
3663 torture_comment(tctx, "OpenPrinterEx(%s) unexpected result[%s] should be WERR_INVALID_PARAM\n",
3664 name, win_errstr(opEx.out.result));
3667 if (W_ERROR_IS_OK(opEx.out.result)) {
3668 ret &=test_ClosePrinter(tctx, p, &handle);
3671 return ret;
3674 static bool test_OpenPrinter(struct torture_context *tctx,
3675 struct dcerpc_pipe *p,
3676 const char *name,
3677 const char *environment)
3679 NTSTATUS status;
3680 struct spoolss_OpenPrinter r;
3681 struct policy_handle handle;
3682 bool ret = true;
3684 r.in.printername = talloc_asprintf(tctx, "\\\\%s\\%s", dcerpc_server_name(p), name);
3685 r.in.datatype = NULL;
3686 r.in.devmode_ctr.devmode= NULL;
3687 r.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
3688 r.out.handle = &handle;
3690 torture_comment(tctx, "Testing OpenPrinter(%s)\n", r.in.printername);
3692 status = dcerpc_spoolss_OpenPrinter(p, tctx, &r);
3694 torture_assert_ntstatus_ok(tctx, status, "OpenPrinter failed");
3696 torture_assert_werr_ok(tctx, r.out.result, "OpenPrinter failed");
3698 if (!test_GetPrinter(tctx, p, &handle, environment)) {
3699 ret = false;
3702 if (!torture_setting_bool(tctx, "samba3", false)) {
3703 if (!test_SecondaryClosePrinter(tctx, p, &handle)) {
3704 ret = false;
3708 if (!test_ClosePrinter(tctx, p, &handle)) {
3709 ret = false;
3712 return ret;
3715 static bool call_OpenPrinterEx(struct torture_context *tctx,
3716 struct dcerpc_pipe *p,
3717 const char *name,
3718 struct spoolss_DeviceMode *devmode,
3719 struct policy_handle *handle)
3721 struct spoolss_OpenPrinterEx r;
3722 struct spoolss_UserLevel1 userlevel1;
3723 NTSTATUS status;
3725 if (name && name[0]) {
3726 r.in.printername = talloc_asprintf(tctx, "\\\\%s\\%s",
3727 dcerpc_server_name(p), name);
3728 } else {
3729 r.in.printername = talloc_asprintf(tctx, "\\\\%s",
3730 dcerpc_server_name(p));
3733 r.in.datatype = NULL;
3734 r.in.devmode_ctr.devmode= devmode;
3735 r.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
3736 r.in.level = 1;
3737 r.in.userlevel.level1 = &userlevel1;
3738 r.out.handle = handle;
3740 userlevel1.size = 1234;
3741 userlevel1.client = "hello";
3742 userlevel1.user = "spottyfoot!";
3743 userlevel1.build = 1;
3744 userlevel1.major = 2;
3745 userlevel1.minor = 3;
3746 userlevel1.processor = 4;
3748 torture_comment(tctx, "Testing OpenPrinterEx(%s)\n", r.in.printername);
3750 status = dcerpc_spoolss_OpenPrinterEx(p, tctx, &r);
3752 torture_assert_ntstatus_ok(tctx, status, "OpenPrinterEx failed");
3754 torture_assert_werr_ok(tctx, r.out.result, "OpenPrinterEx failed");
3756 return true;
3759 static bool test_OpenPrinterEx(struct torture_context *tctx,
3760 struct dcerpc_pipe *p,
3761 const char *name,
3762 const char *environment)
3764 struct policy_handle handle;
3765 bool ret = true;
3767 if (!call_OpenPrinterEx(tctx, p, name, NULL, &handle)) {
3768 return false;
3771 if (!test_PrinterInfo_SD(tctx, p, &handle)) {
3772 ret = false;
3775 if (!test_GetPrinter(tctx, p, &handle, environment)) {
3776 ret = false;
3779 if (!test_EnumForms(tctx, p, &handle, false)) {
3780 ret = false;
3783 if (!test_AddForm(tctx, p, &handle, false)) {
3784 ret = false;
3787 if (!test_EnumPrinterData(tctx, p, &handle)) {
3788 ret = false;
3791 if (!test_EnumPrinterDataEx(tctx, p, &handle, "PrinterDriverData")) {
3792 ret = false;
3795 if (!test_printer_keys(tctx, p, &handle)) {
3796 ret = false;
3799 if (!test_PausePrinter(tctx, p, &handle)) {
3800 ret = false;
3803 if (!test_DoPrintTest(tctx, p, &handle)) {
3804 ret = false;
3807 if (!test_ResumePrinter(tctx, p, &handle)) {
3808 ret = false;
3811 if (!test_SetPrinterData(tctx, p, &handle)) {
3812 ret = false;
3815 if (!test_SetPrinterDataEx_matrix(tctx, p, &handle)) {
3816 ret = false;
3819 if (!torture_setting_bool(tctx, "samba3", false)) {
3820 if (!test_SecondaryClosePrinter(tctx, p, &handle)) {
3821 ret = false;
3825 if (!test_ClosePrinter(tctx, p, &handle)) {
3826 ret = false;
3829 return ret;
3832 static bool test_EnumPrinters_old(struct torture_context *tctx,
3833 struct dcerpc_pipe *p,
3834 const char *environment)
3836 struct spoolss_EnumPrinters r;
3837 NTSTATUS status;
3838 uint16_t levels[] = {1, 2, 4, 5};
3839 int i;
3840 bool ret = true;
3842 for (i=0;i<ARRAY_SIZE(levels);i++) {
3843 union spoolss_PrinterInfo *info;
3844 int j;
3845 uint32_t needed;
3846 uint32_t count;
3848 r.in.flags = PRINTER_ENUM_LOCAL;
3849 r.in.server = "";
3850 r.in.level = levels[i];
3851 r.in.buffer = NULL;
3852 r.in.offered = 0;
3853 r.out.needed = &needed;
3854 r.out.count = &count;
3855 r.out.info = &info;
3857 torture_comment(tctx, "Testing EnumPrinters level %u\n", r.in.level);
3859 status = dcerpc_spoolss_EnumPrinters(p, tctx, &r);
3860 torture_assert_ntstatus_ok(tctx, status, "EnumPrinters failed");
3862 if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
3863 DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed);
3864 data_blob_clear(&blob);
3865 r.in.buffer = &blob;
3866 r.in.offered = needed;
3867 status = dcerpc_spoolss_EnumPrinters(p, tctx, &r);
3870 torture_assert_ntstatus_ok(tctx, status, "EnumPrinters failed");
3872 torture_assert_werr_ok(tctx, r.out.result, "EnumPrinters failed");
3874 CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumPrinters, info, r.in.level, count, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
3876 if (!info) {
3877 torture_comment(tctx, "No printers returned\n");
3878 return true;
3881 for (j=0;j<count;j++) {
3882 if (r.in.level == 1) {
3883 char *unc = talloc_strdup(tctx, info[j].info1.name);
3884 char *slash, *name;
3885 name = unc;
3886 if (unc[0] == '\\' && unc[1] == '\\') {
3887 unc +=2;
3889 slash = strchr(unc, '\\');
3890 if (slash) {
3891 slash++;
3892 name = slash;
3894 if (!test_OpenPrinter(tctx, p, name, environment)) {
3895 ret = false;
3897 if (!test_OpenPrinterEx(tctx, p, name, environment)) {
3898 ret = false;
3904 return ret;
3907 static bool test_GetPrinterDriver(struct torture_context *tctx,
3908 struct dcerpc_pipe *p,
3909 struct policy_handle *handle,
3910 const char *driver_name)
3912 struct spoolss_GetPrinterDriver r;
3913 uint32_t needed;
3915 r.in.handle = handle;
3916 r.in.architecture = "W32X86";
3917 r.in.level = 1;
3918 r.in.buffer = NULL;
3919 r.in.offered = 0;
3920 r.out.needed = &needed;
3922 torture_comment(tctx, "Testing GetPrinterDriver level %d\n", r.in.level);
3924 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_GetPrinterDriver(p, tctx, &r),
3925 "failed to call GetPrinterDriver");
3926 if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
3927 DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed);
3928 data_blob_clear(&blob);
3929 r.in.buffer = &blob;
3930 r.in.offered = needed;
3931 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_GetPrinterDriver(p, tctx, &r),
3932 "failed to call GetPrinterDriver");
3935 torture_assert_werr_ok(tctx, r.out.result,
3936 "failed to call GetPrinterDriver");
3938 CHECK_NEEDED_SIZE_LEVEL(spoolss_DriverInfo, r.out.info, r.in.level, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
3940 return true;
3943 static bool test_GetPrinterDriver2(struct torture_context *tctx,
3944 struct dcerpc_pipe *p,
3945 struct policy_handle *handle,
3946 const char *driver_name,
3947 const char *architecture)
3949 struct spoolss_GetPrinterDriver2 r;
3950 uint16_t levels[] = {1, 2, 3, 4, 5, 6, 8, 101 };
3951 uint32_t needed;
3952 uint32_t server_major_version;
3953 uint32_t server_minor_version;
3954 int i;
3956 r.in.handle = handle;
3957 r.in.architecture = architecture;
3958 r.in.client_major_version = 3;
3959 r.in.client_minor_version = 0;
3960 r.out.needed = &needed;
3961 r.out.server_major_version = &server_major_version;
3962 r.out.server_minor_version = &server_minor_version;
3964 for (i=0;i<ARRAY_SIZE(levels);i++) {
3966 r.in.buffer = NULL;
3967 r.in.offered = 0;
3968 r.in.level = levels[i];
3970 torture_comment(tctx, "Testing GetPrinterDriver2(%s) level %d\n",
3971 driver_name, r.in.level);
3973 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_GetPrinterDriver2(p, tctx, &r),
3974 "failed to call GetPrinterDriver2");
3975 if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
3976 DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed);
3977 data_blob_clear(&blob);
3978 r.in.buffer = &blob;
3979 r.in.offered = needed;
3980 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_GetPrinterDriver2(p, tctx, &r),
3981 "failed to call GetPrinterDriver2");
3984 if (W_ERROR_EQUAL(r.out.result, WERR_INVALID_LEVEL)) {
3985 switch (r.in.level) {
3986 case 101:
3987 case 8:
3988 continue;
3989 default:
3990 break;
3994 torture_assert_werr_ok(tctx, r.out.result,
3995 "failed to call GetPrinterDriver2");
3997 CHECK_NEEDED_SIZE_LEVEL(spoolss_DriverInfo, r.out.info, r.in.level, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
4000 return true;
4003 static bool test_EnumPrinterDrivers_old(struct torture_context *tctx,
4004 struct dcerpc_pipe *p,
4005 const char *environment)
4007 struct spoolss_EnumPrinterDrivers r;
4008 NTSTATUS status;
4009 uint16_t levels[] = {1, 2, 3, 4, 5, 6};
4010 int i;
4012 for (i=0;i<ARRAY_SIZE(levels);i++) {
4014 uint32_t needed;
4015 uint32_t count;
4016 union spoolss_DriverInfo *info;
4018 r.in.server = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
4019 r.in.environment = environment;
4020 r.in.level = levels[i];
4021 r.in.buffer = NULL;
4022 r.in.offered = 0;
4023 r.out.needed = &needed;
4024 r.out.count = &count;
4025 r.out.info = &info;
4027 torture_comment(tctx, "Testing EnumPrinterDrivers level %u\n", r.in.level);
4029 status = dcerpc_spoolss_EnumPrinterDrivers(p, tctx, &r);
4031 torture_assert_ntstatus_ok(tctx, status, "EnumPrinterDrivers failed");
4033 if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
4034 DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed);
4035 data_blob_clear(&blob);
4036 r.in.buffer = &blob;
4037 r.in.offered = needed;
4038 status = dcerpc_spoolss_EnumPrinterDrivers(p, tctx, &r);
4041 torture_assert_ntstatus_ok(tctx, status, "EnumPrinterDrivers failed");
4043 torture_assert_werr_ok(tctx, r.out.result, "EnumPrinterDrivers failed");
4045 if (!info) {
4046 torture_comment(tctx, "No printer drivers returned\n");
4047 break;
4050 CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumPrinterDrivers, info, r.in.level, count, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
4053 return true;
4056 static bool test_DeletePrinter(struct torture_context *tctx,
4057 struct dcerpc_pipe *p,
4058 struct policy_handle *handle)
4060 struct spoolss_DeletePrinter r;
4062 torture_comment(tctx, "Testing DeletePrinter\n");
4064 r.in.handle = handle;
4066 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_DeletePrinter(p, tctx, &r),
4067 "failed to delete printer");
4068 torture_assert_werr_ok(tctx, r.out.result,
4069 "failed to delete printer");
4071 return true;
4074 static bool test_EnumPrinters_findname(struct torture_context *tctx,
4075 struct dcerpc_pipe *p,
4076 uint32_t flags,
4077 uint32_t level,
4078 const char *name,
4079 bool *found)
4081 struct spoolss_EnumPrinters e;
4082 uint32_t count;
4083 union spoolss_PrinterInfo *info;
4084 uint32_t needed;
4085 int i;
4087 *found = false;
4089 e.in.flags = flags;
4090 e.in.server = NULL;
4091 e.in.level = level;
4092 e.in.buffer = NULL;
4093 e.in.offered = 0;
4094 e.out.count = &count;
4095 e.out.info = &info;
4096 e.out.needed = &needed;
4098 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_EnumPrinters(p, tctx, &e),
4099 "failed to enum printers");
4101 if (W_ERROR_EQUAL(e.out.result, WERR_INSUFFICIENT_BUFFER)) {
4102 DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed);
4103 data_blob_clear(&blob);
4104 e.in.buffer = &blob;
4105 e.in.offered = needed;
4107 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_EnumPrinters(p, tctx, &e),
4108 "failed to enum printers");
4111 torture_assert_werr_ok(tctx, e.out.result,
4112 "failed to enum printers");
4114 for (i=0; i < count; i++) {
4116 const char *current = NULL;
4117 const char *p;
4119 switch (level) {
4120 case 1:
4121 current = info[i].info1.name;
4122 break;
4125 if (strequal(current, name)) {
4126 *found = true;
4127 break;
4130 p = strrchr(current, '\\');
4131 if (p) {
4132 if (!e.in.server) {
4133 torture_warning(tctx,
4134 "server returns printername %s incl. servername although we did not set servername", current);
4136 p++;
4137 if (strequal(p, name)) {
4138 *found = true;
4139 break;
4144 return true;
4147 static bool test_AddPrinter_wellknown(struct torture_context *tctx,
4148 struct dcerpc_pipe *p,
4149 const char *printername,
4150 bool ex)
4152 WERROR result;
4153 struct spoolss_AddPrinter r;
4154 struct spoolss_AddPrinterEx rex;
4155 struct spoolss_SetPrinterInfoCtr info_ctr;
4156 struct spoolss_SetPrinterInfo1 info1;
4157 struct spoolss_DevmodeContainer devmode_ctr;
4158 struct sec_desc_buf secdesc_ctr;
4159 struct spoolss_UserLevelCtr userlevel_ctr;
4160 struct policy_handle handle;
4161 bool found = false;
4163 ZERO_STRUCT(devmode_ctr);
4164 ZERO_STRUCT(secdesc_ctr);
4165 ZERO_STRUCT(userlevel_ctr);
4166 ZERO_STRUCT(info1);
4168 torture_comment(tctx, "Testing AddPrinter%s level 1\n", ex ? "Ex":"");
4170 /* try to add printer to wellknown printer list (level 1) */
4172 userlevel_ctr.level = 1;
4174 info_ctr.info.info1 = &info1;
4175 info_ctr.level = 1;
4177 rex.in.server = NULL;
4178 rex.in.info_ctr = &info_ctr;
4179 rex.in.devmode_ctr = &devmode_ctr;
4180 rex.in.secdesc_ctr = &secdesc_ctr;
4181 rex.in.userlevel_ctr = &userlevel_ctr;
4182 rex.out.handle = &handle;
4184 r.in.server = NULL;
4185 r.in.info_ctr = &info_ctr;
4186 r.in.devmode_ctr = &devmode_ctr;
4187 r.in.secdesc_ctr = &secdesc_ctr;
4188 r.out.handle = &handle;
4190 torture_assert_ntstatus_ok(tctx, ex ? dcerpc_spoolss_AddPrinterEx(p, tctx, &rex) :
4191 dcerpc_spoolss_AddPrinter(p, tctx, &r),
4192 "failed to add printer");
4193 result = ex ? rex.out.result : r.out.result;
4194 torture_assert_werr_equal(tctx, result, WERR_INVALID_PRINTER_NAME,
4195 "unexpected result code");
4197 info1.name = printername;
4198 info1.flags = PRINTER_ATTRIBUTE_SHARED;
4200 torture_assert_ntstatus_ok(tctx, ex ? dcerpc_spoolss_AddPrinterEx(p, tctx, &rex) :
4201 dcerpc_spoolss_AddPrinter(p, tctx, &r),
4202 "failed to add printer");
4203 result = ex ? rex.out.result : r.out.result;
4204 torture_assert_werr_equal(tctx, result, WERR_PRINTER_ALREADY_EXISTS,
4205 "unexpected result code");
4207 /* bizarre protocol, WERR_PRINTER_ALREADY_EXISTS means success here,
4208 better do a real check to see the printer is really there */
4210 torture_assert(tctx, test_EnumPrinters_findname(tctx, p,
4211 PRINTER_ENUM_NETWORK, 1,
4212 printername,
4213 &found),
4214 "failed to enum printers");
4216 torture_assert(tctx, found, "failed to find newly added printer");
4218 info1.flags = 0;
4220 torture_assert_ntstatus_ok(tctx, ex ? dcerpc_spoolss_AddPrinterEx(p, tctx, &rex) :
4221 dcerpc_spoolss_AddPrinter(p, tctx, &r),
4222 "failed to add printer");
4223 result = ex ? rex.out.result : r.out.result;
4224 torture_assert_werr_equal(tctx, result, WERR_PRINTER_ALREADY_EXISTS,
4225 "unexpected result code");
4227 /* bizarre protocol, WERR_PRINTER_ALREADY_EXISTS means success here,
4228 better do a real check to see the printer has really been removed
4229 from the well known printer list */
4231 found = false;
4233 torture_assert(tctx, test_EnumPrinters_findname(tctx, p,
4234 PRINTER_ENUM_NETWORK, 1,
4235 printername,
4236 &found),
4237 "failed to enum printers");
4238 #if 0
4239 torture_assert(tctx, !found, "printer still in well known printer list");
4240 #endif
4241 return true;
4244 static bool test_AddPrinter_normal(struct torture_context *tctx,
4245 struct dcerpc_pipe *p,
4246 struct policy_handle *handle_p,
4247 const char *printername,
4248 const char *drivername,
4249 const char *portname,
4250 bool ex)
4252 WERROR result;
4253 struct spoolss_AddPrinter r;
4254 struct spoolss_AddPrinterEx rex;
4255 struct spoolss_SetPrinterInfoCtr info_ctr;
4256 struct spoolss_SetPrinterInfo2 info2;
4257 struct spoolss_DevmodeContainer devmode_ctr;
4258 struct sec_desc_buf secdesc_ctr;
4259 struct spoolss_UserLevelCtr userlevel_ctr;
4260 struct policy_handle handle;
4261 bool found = false;
4262 bool existing_printer_deleted = false;
4264 ZERO_STRUCT(devmode_ctr);
4265 ZERO_STRUCT(secdesc_ctr);
4266 ZERO_STRUCT(userlevel_ctr);
4268 torture_comment(tctx, "Testing AddPrinter%s level 2\n", ex ? "Ex":"");
4270 userlevel_ctr.level = 1;
4272 rex.in.server = NULL;
4273 rex.in.info_ctr = &info_ctr;
4274 rex.in.devmode_ctr = &devmode_ctr;
4275 rex.in.secdesc_ctr = &secdesc_ctr;
4276 rex.in.userlevel_ctr = &userlevel_ctr;
4277 rex.out.handle = &handle;
4279 r.in.server = NULL;
4280 r.in.info_ctr = &info_ctr;
4281 r.in.devmode_ctr = &devmode_ctr;
4282 r.in.secdesc_ctr = &secdesc_ctr;
4283 r.out.handle = &handle;
4285 again:
4287 /* try to add printer to printer list (level 2) */
4289 ZERO_STRUCT(info2);
4291 info_ctr.info.info2 = &info2;
4292 info_ctr.level = 2;
4294 torture_assert_ntstatus_ok(tctx, ex ? dcerpc_spoolss_AddPrinterEx(p, tctx, &rex) :
4295 dcerpc_spoolss_AddPrinter(p, tctx, &r),
4296 "failed to add printer");
4297 result = ex ? rex.out.result : r.out.result;
4298 torture_assert_werr_equal(tctx, result, WERR_INVALID_PRINTER_NAME,
4299 "unexpected result code");
4301 info2.printername = printername;
4303 torture_assert_ntstatus_ok(tctx, ex ? dcerpc_spoolss_AddPrinterEx(p, tctx, &rex) :
4304 dcerpc_spoolss_AddPrinter(p, tctx, &r),
4305 "failed to add printer");
4306 result = ex ? rex.out.result : r.out.result;
4308 if (W_ERROR_EQUAL(result, WERR_PRINTER_ALREADY_EXISTS)) {
4309 struct policy_handle printer_handle;
4311 if (existing_printer_deleted) {
4312 torture_fail(tctx, "already deleted printer still existing?");
4315 torture_assert(tctx, call_OpenPrinterEx(tctx, p, printername, NULL, &printer_handle),
4316 "failed to open printer handle");
4318 torture_assert(tctx, test_DeletePrinter(tctx, p, &printer_handle),
4319 "failed to delete printer");
4321 torture_assert(tctx, test_ClosePrinter(tctx, p, &printer_handle),
4322 "failed to close server handle");
4324 existing_printer_deleted = true;
4326 goto again;
4329 torture_assert_werr_equal(tctx, result, WERR_UNKNOWN_PORT,
4330 "unexpected result code");
4332 info2.portname = portname;
4334 torture_assert_ntstatus_ok(tctx, ex ? dcerpc_spoolss_AddPrinterEx(p, tctx, &rex) :
4335 dcerpc_spoolss_AddPrinter(p, tctx, &r),
4336 "failed to add printer");
4337 result = ex ? rex.out.result : r.out.result;
4338 torture_assert_werr_equal(tctx, result, WERR_UNKNOWN_PRINTER_DRIVER,
4339 "unexpected result code");
4341 info2.drivername = drivername;
4343 torture_assert_ntstatus_ok(tctx, ex ? dcerpc_spoolss_AddPrinterEx(p, tctx, &rex) :
4344 dcerpc_spoolss_AddPrinter(p, tctx, &r),
4345 "failed to add printer");
4346 result = ex ? rex.out.result : r.out.result;
4348 /* w2k8r2 allows to add printer w/o defining printprocessor */
4350 if (!W_ERROR_IS_OK(result)) {
4351 torture_assert_werr_equal(tctx, result, WERR_UNKNOWN_PRINTPROCESSOR,
4352 "unexpected result code");
4354 info2.printprocessor = "winprint";
4356 torture_assert_ntstatus_ok(tctx, ex ? dcerpc_spoolss_AddPrinterEx(p, tctx, &rex) :
4357 dcerpc_spoolss_AddPrinter(p, tctx, &r),
4358 "failed to add printer");
4359 result = ex ? rex.out.result : r.out.result;
4360 torture_assert_werr_ok(tctx, result,
4361 "failed to add printer");
4364 *handle_p = handle;
4366 /* we are paranoid, really check if the printer is there now */
4368 torture_assert(tctx, test_EnumPrinters_findname(tctx, p,
4369 PRINTER_ENUM_LOCAL, 1,
4370 printername,
4371 &found),
4372 "failed to enum printers");
4373 torture_assert(tctx, found, "failed to find newly added printer");
4375 torture_assert_ntstatus_ok(tctx, ex ? dcerpc_spoolss_AddPrinterEx(p, tctx, &rex) :
4376 dcerpc_spoolss_AddPrinter(p, tctx, &r),
4377 "failed to add printer");
4378 result = ex ? rex.out.result : r.out.result;
4379 torture_assert_werr_equal(tctx, result, WERR_PRINTER_ALREADY_EXISTS,
4380 "unexpected result code");
4382 return true;
4385 static bool test_AddPrinterEx(struct torture_context *tctx,
4386 struct dcerpc_pipe *p,
4387 struct policy_handle *handle_p,
4388 const char *printername,
4389 const char *drivername,
4390 const char *portname)
4392 bool ret = true;
4394 if (!torture_setting_bool(tctx, "samba3", false)) {
4395 if (!test_AddPrinter_wellknown(tctx, p, TORTURE_WELLKNOWN_PRINTER_EX, true)) {
4396 torture_comment(tctx, "failed to add printer to well known list\n");
4397 ret = false;
4401 if (!test_AddPrinter_normal(tctx, p, handle_p,
4402 printername, drivername, portname,
4403 true)) {
4404 torture_comment(tctx, "failed to add printer to printer list\n");
4405 ret = false;
4408 return ret;
4411 static bool test_AddPrinter(struct torture_context *tctx,
4412 struct dcerpc_pipe *p,
4413 struct policy_handle *handle_p,
4414 const char *printername,
4415 const char *drivername,
4416 const char *portname)
4418 bool ret = true;
4420 if (!torture_setting_bool(tctx, "samba3", false)) {
4421 if (!test_AddPrinter_wellknown(tctx, p, TORTURE_WELLKNOWN_PRINTER, false)) {
4422 torture_comment(tctx, "failed to add printer to well known list\n");
4423 ret = false;
4427 if (!test_AddPrinter_normal(tctx, p, handle_p,
4428 printername, drivername, portname,
4429 false)) {
4430 torture_comment(tctx, "failed to add printer to printer list\n");
4431 ret = false;
4434 return ret;
4437 static bool test_printer_info(struct torture_context *tctx,
4438 struct dcerpc_pipe *p,
4439 struct policy_handle *handle)
4441 bool ret = true;
4443 if (torture_setting_bool(tctx, "samba3", false)) {
4444 torture_skip(tctx, "skipping printer info cross tests against samba 3");
4447 if (!test_PrinterInfo(tctx, p, handle)) {
4448 ret = false;
4451 if (!test_SetPrinter_errors(tctx, p, handle)) {
4452 ret = false;
4455 return ret;
4458 static bool test_EnumPrinterKey(struct torture_context *tctx,
4459 struct dcerpc_pipe *p,
4460 struct policy_handle *handle,
4461 const char *key_name,
4462 const char ***array)
4464 struct spoolss_EnumPrinterKey r;
4465 uint32_t needed = 0;
4466 union spoolss_KeyNames key_buffer;
4467 int32_t offered[] = { 0, 1, 2, 3, 4, 5, -1, -2, -3, -4, -5, 256, 512, 1024, 2048 };
4468 uint32_t _ndr_size;
4469 int i;
4471 r.in.handle = handle;
4472 r.in.key_name = key_name;
4473 r.out.key_buffer = &key_buffer;
4474 r.out.needed = &needed;
4475 r.out._ndr_size = &_ndr_size;
4477 for (i=0; i < ARRAY_SIZE(offered); i++) {
4479 if (offered[i] < 0 && needed) {
4480 if (needed <= 4) {
4481 continue;
4483 r.in.offered = needed + offered[i];
4484 } else {
4485 r.in.offered = offered[i];
4488 ZERO_STRUCT(key_buffer);
4490 torture_comment(tctx, "Testing EnumPrinterKey(%s) with %d offered\n", r.in.key_name, r.in.offered);
4492 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_EnumPrinterKey(p, tctx, &r),
4493 "failed to call EnumPrinterKey");
4494 if (W_ERROR_EQUAL(r.out.result, WERR_MORE_DATA)) {
4496 torture_assert(tctx, (_ndr_size == r.in.offered/2),
4497 talloc_asprintf(tctx, "EnumPrinterKey size mismatch, _ndr_size %d (expected %d)",
4498 _ndr_size, r.in.offered/2));
4500 r.in.offered = needed;
4501 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_EnumPrinterKey(p, tctx, &r),
4502 "failed to call EnumPrinterKey");
4505 if (offered[i] > 0) {
4506 torture_assert_werr_ok(tctx, r.out.result,
4507 "failed to call EnumPrinterKey");
4510 torture_assert(tctx, (_ndr_size == r.in.offered/2),
4511 talloc_asprintf(tctx, "EnumPrinterKey size mismatch, _ndr_size %d (expected %d)",
4512 _ndr_size, r.in.offered/2));
4514 torture_assert(tctx, (*r.out.needed <= r.in.offered),
4515 talloc_asprintf(tctx, "EnumPrinterKey size mismatch: needed %d is not <= offered %d", *r.out.needed, r.in.offered));
4517 torture_assert(tctx, (*r.out.needed <= _ndr_size * 2),
4518 talloc_asprintf(tctx, "EnumPrinterKey size mismatch: needed %d is not <= _ndr_size %d * 2", *r.out.needed, _ndr_size));
4520 if (key_buffer.string_array) {
4521 uint32_t calc_needed = 0;
4522 int s;
4523 for (s=0; key_buffer.string_array[s]; s++) {
4524 calc_needed += strlen_m_term(key_buffer.string_array[s])*2;
4526 if (!key_buffer.string_array[0]) {
4527 calc_needed += 2;
4529 calc_needed += 2;
4531 torture_assert_int_equal(tctx, *r.out.needed, calc_needed,
4532 "EnumPrinterKey unexpected size");
4536 if (array) {
4537 *array = key_buffer.string_array;
4540 return true;
4543 bool test_printer_keys(struct torture_context *tctx,
4544 struct dcerpc_pipe *p,
4545 struct policy_handle *handle)
4547 const char **key_array = NULL;
4548 int i;
4550 torture_comment(tctx, "\nTesting Printer Keys\n");
4552 torture_assert(tctx, test_EnumPrinterKey(tctx, p, handle, "", &key_array),
4553 "failed to call test_EnumPrinterKey");
4555 for (i=0; key_array && key_array[i]; i++) {
4556 torture_assert(tctx, test_EnumPrinterKey(tctx, p, handle, key_array[i], NULL),
4557 "failed to call test_EnumPrinterKey");
4559 for (i=0; key_array && key_array[i]; i++) {
4560 torture_assert(tctx, test_EnumPrinterDataEx(tctx, p, handle, key_array[i]),
4561 "failed to call test_EnumPrinterDataEx");
4564 return true;
4567 static bool test_one_printer(struct torture_context *tctx,
4568 struct dcerpc_pipe *p,
4569 struct policy_handle *handle,
4570 const char *name)
4572 bool ret = true;
4574 if (!test_printer_info(tctx, p, handle)) {
4575 ret = false;
4578 if (!test_PrinterInfo_SD(tctx, p, handle)) {
4579 ret = false;
4582 if (!test_PrinterInfo_DevMode(tctx, p, handle, name)) {
4583 ret = false;
4586 if (!test_ChangeID(tctx, p, handle)) {
4587 ret = false;
4590 if (!test_printer_keys(tctx, p, handle)) {
4591 ret = false;
4594 if (!test_SetPrinterDataEx_matrix(tctx, p, handle)) {
4595 ret = false;
4598 return ret;
4601 static bool test_printer(struct torture_context *tctx,
4602 struct dcerpc_pipe *p)
4604 bool ret = true;
4605 struct policy_handle handle[2];
4606 bool found = false;
4607 const char *drivername = "Microsoft XPS Document Writer";
4608 const char *portname = "LPT1:";
4610 /* test printer created via AddPrinter */
4612 if (!test_AddPrinter(tctx, p, &handle[0], TORTURE_PRINTER, drivername, portname)) {
4613 return false;
4616 if (!test_one_printer(tctx, p, &handle[0], TORTURE_PRINTER)) {
4617 ret = false;
4620 if (!test_DeletePrinter(tctx, p, &handle[0])) {
4621 ret = false;
4624 if (!test_EnumPrinters_findname(tctx, p, PRINTER_ENUM_LOCAL, 1,
4625 TORTURE_PRINTER, &found)) {
4626 ret = false;
4629 torture_assert(tctx, !found, "deleted printer still there");
4631 /* test printer created via AddPrinterEx */
4633 if (!test_AddPrinterEx(tctx, p, &handle[1], TORTURE_PRINTER_EX, drivername, portname)) {
4634 return false;
4637 if (!test_one_printer(tctx, p, &handle[1], TORTURE_PRINTER_EX)) {
4638 ret = false;
4641 if (!test_DeletePrinter(tctx, p, &handle[1])) {
4642 ret = false;
4645 if (!test_EnumPrinters_findname(tctx, p, PRINTER_ENUM_LOCAL, 1,
4646 TORTURE_PRINTER_EX, &found)) {
4647 ret = false;
4650 torture_assert(tctx, !found, "deleted printer still there");
4652 return ret;
4655 static bool test_architecture_buffer(struct torture_context *tctx,
4656 struct dcerpc_pipe *p)
4658 struct spoolss_OpenPrinterEx r;
4659 struct spoolss_UserLevel1 u1;
4660 struct policy_handle handle;
4661 uint32_t architectures[] = {
4662 PROCESSOR_ARCHITECTURE_INTEL,
4663 PROCESSOR_ARCHITECTURE_IA64,
4664 PROCESSOR_ARCHITECTURE_AMD64
4666 uint32_t needed[3];
4667 int i;
4669 for (i=0; i < ARRAY_SIZE(architectures); i++) {
4671 torture_comment(tctx, "Testing OpenPrinterEx with architecture %d\n", architectures[i]);
4673 u1.size = 0;
4674 u1.client = NULL;
4675 u1.user = NULL;
4676 u1.build = 0;
4677 u1.major = 3;
4678 u1.minor = 0;
4679 u1.processor = architectures[i];
4681 r.in.printername = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
4682 r.in.datatype = NULL;
4683 r.in.devmode_ctr.devmode= NULL;
4684 r.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
4685 r.in.level = 1;
4686 r.in.userlevel.level1 = &u1;
4687 r.out.handle = &handle;
4689 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_OpenPrinterEx(p, tctx, &r), "");
4690 torture_assert_werr_ok(tctx, r.out.result, "");
4693 struct spoolss_EnumPrinters e;
4694 uint32_t count;
4695 union spoolss_PrinterInfo *info;
4697 e.in.flags = PRINTER_ENUM_LOCAL;
4698 e.in.server = NULL;
4699 e.in.level = 2;
4700 e.in.buffer = NULL;
4701 e.in.offered = 0;
4702 e.out.count = &count;
4703 e.out.info = &info;
4704 e.out.needed = &needed[i];
4706 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_EnumPrinters(p, tctx, &e), "");
4707 #if 0
4708 torture_comment(tctx, "needed was %d\n", needed[i]);
4709 #endif
4712 torture_assert(tctx, test_ClosePrinter(tctx, p, &handle), "");
4715 for (i=1; i < ARRAY_SIZE(architectures); i++) {
4716 if (needed[i-1] != needed[i]) {
4717 torture_fail(tctx,
4718 talloc_asprintf(tctx, "needed size %d for architecture %d != needed size %d for architecture %d\n",
4719 needed[i-1], architectures[i-1], needed[i], architectures[i]));
4723 return true;
4726 bool torture_rpc_spoolss(struct torture_context *torture)
4728 NTSTATUS status;
4729 struct dcerpc_pipe *p;
4730 bool ret = true;
4731 struct test_spoolss_context *ctx;
4732 const char *environment = SPOOLSS_ARCHITECTURE_NT_X86;
4734 status = torture_rpc_connection(torture, &p, &ndr_table_spoolss);
4735 if (!NT_STATUS_IS_OK(status)) {
4736 return false;
4739 ctx = talloc_zero(torture, struct test_spoolss_context);
4741 ret &= test_OpenPrinter_server(torture, p, &ctx->server_handle);
4742 ret &= test_GetPrinterData_list(torture, p, &ctx->server_handle);
4743 ret &= test_EnumForms(torture, p, &ctx->server_handle, true);
4744 ret &= test_AddForm(torture, p, &ctx->server_handle, true);
4745 ret &= test_EnumPorts(torture, p, ctx);
4746 ret &= test_GetPrinterDriverDirectory(torture, p, ctx, environment);
4747 ret &= test_GetPrintProcessorDirectory(torture, p, ctx, environment);
4748 ret &= test_EnumPrinterDrivers(torture, p, ctx, environment);
4749 ret &= test_EnumPrinterDrivers(torture, p, ctx, SPOOLSS_ARCHITECTURE_ALL);
4750 ret &= test_EnumMonitors(torture, p, ctx);
4751 ret &= test_EnumPrintProcessors(torture, p, ctx, environment);
4752 ret &= test_EnumPrintProcDataTypes(torture, p, ctx);
4753 ret &= test_EnumPrinters(torture, p, ctx);
4754 ret &= test_OpenPrinter_badname(torture, p, "__INVALID_PRINTER__");
4755 ret &= test_OpenPrinter_badname(torture, p, "\\\\__INVALID_HOST__");
4756 ret &= test_OpenPrinter_badname(torture, p, "");
4757 ret &= test_OpenPrinter_badname(torture, p, "\\\\\\");
4758 ret &= test_OpenPrinter_badname(torture, p, "\\\\\\__INVALID_PRINTER__");
4759 ret &= test_OpenPrinter_badname(torture, p, talloc_asprintf(torture, "\\\\%s\\", dcerpc_server_name(p)));
4760 ret &= test_OpenPrinter_badname(torture, p,
4761 talloc_asprintf(torture, "\\\\%s\\__INVALID_PRINTER__", dcerpc_server_name(p)));
4764 ret &= test_AddPort(torture, p);
4765 ret &= test_EnumPorts_old(torture, p);
4766 ret &= test_EnumPrinters_old(torture, p, environment);
4767 ret &= test_EnumPrinterDrivers_old(torture, p, environment);
4768 ret &= test_architecture_buffer(torture, p);
4770 return ret;
4773 struct torture_suite *torture_rpc_spoolss_printer(TALLOC_CTX *mem_ctx)
4775 struct torture_suite *suite = torture_suite_create(mem_ctx, "SPOOLSS-PRINTER");
4777 struct torture_rpc_tcase *tcase = torture_suite_add_rpc_iface_tcase(suite,
4778 "printer", &ndr_table_spoolss);
4780 torture_rpc_tcase_add_test(tcase, "printer", test_printer);
4782 return suite;