s4-smbtorture: add simple printer rename test to RPC-SPOOLSS-PRINTER.
[Samba/nascimento.git] / source4 / torture / rpc / spoolss.c
blob728ecd1089c123d0f86c88167a02143d10794288
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_winreg_c.h"
30 #include "librpc/gen_ndr/ndr_security.h"
31 #include "libcli/security/security.h"
32 #include "torture/rpc/rpc.h"
33 #include "param/param.h"
34 #include "lib/registry/registry.h"
36 #define TORTURE_WELLKNOWN_PRINTER "torture_wkn_printer"
37 #define TORTURE_PRINTER "torture_printer"
38 #define TORTURE_WELLKNOWN_PRINTER_EX "torture_wkn_printer_ex"
39 #define TORTURE_PRINTER_EX "torture_printer_ex"
41 #define TOP_LEVEL_PRINTER_KEY "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Print\\Printers"
43 struct test_spoolss_context {
44 /* print server handle */
45 struct policy_handle server_handle;
47 /* for EnumPorts */
48 uint32_t port_count[3];
49 union spoolss_PortInfo *ports[3];
51 /* for EnumPrinterDrivers */
52 uint32_t driver_count[8];
53 union spoolss_DriverInfo *drivers[8];
55 /* for EnumMonitors */
56 uint32_t monitor_count[3];
57 union spoolss_MonitorInfo *monitors[3];
59 /* for EnumPrintProcessors */
60 uint32_t print_processor_count[2];
61 union spoolss_PrintProcessorInfo *print_processors[2];
63 /* for EnumPrinters */
64 uint32_t printer_count[6];
65 union spoolss_PrinterInfo *printers[6];
68 #define COMPARE_STRING(tctx, c,r,e) \
69 torture_assert_str_equal(tctx, c.e, r.e, "invalid value")
71 /* not every compiler supports __typeof__() */
72 #if (__GNUC__ >= 3)
73 #define _CHECK_FIELD_SIZE(c,r,e,type) do {\
74 if (sizeof(__typeof__(c.e)) != sizeof(type)) { \
75 torture_fail(tctx, #c "." #e "field is not " #type "\n"); \
77 if (sizeof(__typeof__(r.e)) != sizeof(type)) { \
78 torture_fail(tctx, #r "." #e "field is not " #type "\n"); \
80 } while(0)
81 #else
82 #define _CHECK_FIELD_SIZE(c,r,e,type) do {} while(0)
83 #endif
85 #define COMPARE_UINT32(tctx, c, r, e) do {\
86 _CHECK_FIELD_SIZE(c, r, e, uint32_t); \
87 torture_assert_int_equal(tctx, c.e, r.e, "invalid value"); \
88 } while(0)
90 #define COMPARE_UINT64(tctx, c, r, e) do {\
91 _CHECK_FIELD_SIZE(c, r, e, uint64_t); \
92 torture_assert_int_equal(tctx, c.e, r.e, "invalid value"); \
93 } while(0)
96 #define COMPARE_NTTIME(tctx, c, r, e) do {\
97 _CHECK_FIELD_SIZE(c, r, e, NTTIME); \
98 torture_assert_int_equal(tctx, c.e, r.e, "invalid value"); \
99 } while(0)
101 #define COMPARE_STRING_ARRAY(tctx, c,r,e) do {\
102 int __i; \
103 if (!c.e && !r.e) { \
104 break; \
106 if (c.e && !r.e) { \
107 torture_fail(tctx, #r "." #e " field is NULL and " #c "." #e " is not\n"); \
109 if (!c.e && r.e) { \
110 torture_fail(tctx, #c "." #e " field is NULL and " #r "." #e " is not\n"); \
112 for (__i=0;c.e[__i] != NULL; __i++) { \
113 torture_assert_str_equal(tctx, c.e[__i], r.e[__i], "invalid value"); \
115 } while(0)
117 #define CHECK_ALIGN(size, n) do {\
118 if (size % n) {\
119 torture_warning(tctx, "%d is *NOT* %d byte aligned, should be %d",\
120 size, n, size + n - (size % n));\
122 } while(0)
124 #define DO_ROUND(size, n) (((size)+((n)-1)) & ~((n)-1))
126 #define CHECK_NEEDED_SIZE_ENUM_LEVEL(fn, info, level, count, ic, needed, align) do { \
127 if (torture_setting_bool(tctx, "spoolss_check_size", false)) {\
128 uint32_t size = ndr_size_##fn##_info(tctx, ic, level, count, info);\
129 uint32_t round_size = DO_ROUND(size, align);\
130 if (round_size != needed) {\
131 torture_warning(tctx, __location__": "#fn" level %d (count: %d) got unexpected needed size: %d, we calculated: %d", level, count, needed, round_size);\
132 CHECK_ALIGN(size, align);\
135 } while(0)
137 #define CHECK_NEEDED_SIZE_ENUM(fn, info, count, ic, needed, align) do { \
138 if (torture_setting_bool(tctx, "spoolss_check_size", false)) {\
139 uint32_t size = ndr_size_##fn##_info(tctx, ic, count, info);\
140 uint32_t round_size = DO_ROUND(size, align);\
141 if (round_size != needed) {\
142 torture_warning(tctx, __location__": "#fn" (count: %d) got unexpected needed size: %d, we calculated: %d", count, needed, round_size);\
143 CHECK_ALIGN(size, align);\
146 } while(0)
148 #define CHECK_NEEDED_SIZE_LEVEL(fn, info, level, ic, needed, align) do { \
149 if (torture_setting_bool(tctx, "spoolss_check_size", false)) {\
150 uint32_t size = ndr_size_##fn(info, level, ic, 0);\
151 uint32_t round_size = DO_ROUND(size, align);\
152 if (round_size != needed) {\
153 torture_warning(tctx, __location__": "#fn" level %d got unexpected needed size: %d, we calculated: %d", level, needed, round_size);\
154 CHECK_ALIGN(size, align);\
157 } while(0)
159 static bool PrinterInfo_to_SetPrinterInfo(struct torture_context *tctx,
160 const union spoolss_PrinterInfo *i,
161 uint32_t level,
162 union spoolss_SetPrinterInfo *s)
164 switch (level) {
165 case 0:
166 s->info0 = talloc(tctx, struct spoolss_SetPrinterInfo0);
167 break;
168 case 2:
169 s->info2 = talloc(tctx, struct spoolss_SetPrinterInfo2);
170 s->info2->servername = i->info2.servername;
171 s->info2->printername = i->info2.printername;
172 s->info2->sharename = i->info2.sharename;
173 s->info2->portname = i->info2.portname;
174 s->info2->drivername = i->info2.drivername;
175 s->info2->comment = i->info2.comment;
176 s->info2->location = i->info2.location;
177 s->info2->devmode_ptr = 0;
178 s->info2->sepfile = i->info2.sepfile;
179 s->info2->printprocessor = i->info2.printprocessor;
180 s->info2->datatype = i->info2.datatype;
181 s->info2->parameters = i->info2.parameters;
182 s->info2->secdesc_ptr = 0;
183 s->info2->attributes = i->info2.attributes;
184 s->info2->priority = i->info2.priority;
185 s->info2->defaultpriority = i->info2.defaultpriority;
186 s->info2->starttime = i->info2.starttime;
187 s->info2->untiltime = i->info2.untiltime;
188 s->info2->status = i->info2.status;
189 s->info2->cjobs = i->info2.cjobs;
190 s->info2->averageppm = i->info2.averageppm;
191 break;
192 case 3:
193 case 4:
194 case 5:
195 case 6:
196 case 7:
197 case 8:
198 case 9:
199 default:
200 return false;
203 return true;
206 static bool test_OpenPrinter_server(struct torture_context *tctx,
207 struct dcerpc_pipe *p,
208 struct policy_handle *server_handle)
210 NTSTATUS status;
211 struct spoolss_OpenPrinter op;
213 op.in.printername = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
214 op.in.datatype = NULL;
215 op.in.devmode_ctr.devmode= NULL;
216 op.in.access_mask = 0;
217 op.out.handle = server_handle;
219 torture_comment(tctx, "Testing OpenPrinter(%s)\n", op.in.printername);
221 status = dcerpc_spoolss_OpenPrinter(p, tctx, &op);
222 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_OpenPrinter failed");
223 torture_assert_werr_ok(tctx, op.out.result, "dcerpc_spoolss_OpenPrinter failed");
225 return true;
228 static bool test_EnumPorts(struct torture_context *tctx,
229 struct dcerpc_pipe *p,
230 struct test_spoolss_context *ctx)
232 NTSTATUS status;
233 struct spoolss_EnumPorts r;
234 uint16_t levels[] = { 1, 2 };
235 int i, j;
237 for (i=0;i<ARRAY_SIZE(levels);i++) {
238 int level = levels[i];
239 DATA_BLOB blob;
240 uint32_t needed;
241 uint32_t count;
242 union spoolss_PortInfo *info;
244 r.in.servername = "";
245 r.in.level = level;
246 r.in.buffer = NULL;
247 r.in.offered = 0;
248 r.out.needed = &needed;
249 r.out.count = &count;
250 r.out.info = &info;
252 torture_comment(tctx, "Testing EnumPorts level %u\n", r.in.level);
254 status = dcerpc_spoolss_EnumPorts(p, ctx, &r);
255 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EnumPorts failed");
256 if (W_ERROR_IS_OK(r.out.result)) {
257 /* TODO: do some more checks here */
258 continue;
260 torture_assert_werr_equal(tctx, r.out.result, WERR_INSUFFICIENT_BUFFER,
261 "EnumPorts unexpected return code");
263 blob = data_blob_talloc(ctx, NULL, needed);
264 data_blob_clear(&blob);
265 r.in.buffer = &blob;
266 r.in.offered = needed;
268 status = dcerpc_spoolss_EnumPorts(p, ctx, &r);
269 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EnumPorts failed");
271 torture_assert_werr_ok(tctx, r.out.result, "EnumPorts failed");
273 torture_assert(tctx, info, "EnumPorts returned no info");
275 CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumPorts, info, r.in.level, count, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
277 ctx->port_count[level] = count;
278 ctx->ports[level] = info;
281 for (i=1;i<ARRAY_SIZE(levels);i++) {
282 int level = levels[i];
283 int old_level = levels[i-1];
284 torture_assert_int_equal(tctx, ctx->port_count[level], ctx->port_count[old_level],
285 "EnumPorts invalid value");
287 /* if the array sizes are not the same we would maybe segfault in the following code */
289 for (i=0;i<ARRAY_SIZE(levels);i++) {
290 int level = levels[i];
291 for (j=0;j<ctx->port_count[level];j++) {
292 union spoolss_PortInfo *cur = &ctx->ports[level][j];
293 union spoolss_PortInfo *ref = &ctx->ports[2][j];
294 switch (level) {
295 case 1:
296 COMPARE_STRING(tctx, cur->info1, ref->info2, port_name);
297 break;
298 case 2:
299 /* level 2 is our reference, and it makes no sense to compare it to itself */
300 break;
305 return true;
308 static bool test_GetPrintProcessorDirectory(struct torture_context *tctx,
309 struct dcerpc_pipe *p,
310 struct test_spoolss_context *ctx,
311 const char *environment)
313 NTSTATUS status;
314 struct spoolss_GetPrintProcessorDirectory r;
315 struct {
316 uint16_t level;
317 const char *server;
318 } levels[] = {{
319 .level = 1,
320 .server = NULL
322 .level = 1,
323 .server = ""
325 .level = 78,
326 .server = ""
328 .level = 1,
329 .server = talloc_asprintf(ctx, "\\\\%s", dcerpc_server_name(p))
331 .level = 1024,
332 .server = talloc_asprintf(ctx, "\\\\%s", dcerpc_server_name(p))
335 int i;
336 uint32_t needed;
338 for (i=0;i<ARRAY_SIZE(levels);i++) {
339 int level = levels[i].level;
340 DATA_BLOB blob;
342 r.in.server = levels[i].server;
343 r.in.environment = environment;
344 r.in.level = level;
345 r.in.buffer = NULL;
346 r.in.offered = 0;
347 r.out.needed = &needed;
349 torture_comment(tctx, "Testing GetPrintProcessorDirectory level %u\n", r.in.level);
351 status = dcerpc_spoolss_GetPrintProcessorDirectory(p, ctx, &r);
352 torture_assert_ntstatus_ok(tctx, status,
353 "dcerpc_spoolss_GetPrintProcessorDirectory failed");
354 torture_assert_werr_equal(tctx, r.out.result, WERR_INSUFFICIENT_BUFFER,
355 "GetPrintProcessorDirectory unexpected return code");
357 blob = data_blob_talloc(ctx, NULL, needed);
358 data_blob_clear(&blob);
359 r.in.buffer = &blob;
360 r.in.offered = needed;
362 status = dcerpc_spoolss_GetPrintProcessorDirectory(p, ctx, &r);
363 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_GetPrintProcessorDirectory failed");
365 torture_assert_werr_ok(tctx, r.out.result, "GetPrintProcessorDirectory failed");
367 CHECK_NEEDED_SIZE_LEVEL(spoolss_PrintProcessorDirectoryInfo, r.out.info, r.in.level, lp_iconv_convenience(tctx->lp_ctx), needed, 2);
370 return true;
374 static bool test_GetPrinterDriverDirectory(struct torture_context *tctx,
375 struct dcerpc_pipe *p,
376 struct test_spoolss_context *ctx,
377 const char *environment)
379 NTSTATUS status;
380 struct spoolss_GetPrinterDriverDirectory r;
381 struct {
382 uint16_t level;
383 const char *server;
384 } levels[] = {{
385 .level = 1,
386 .server = NULL
388 .level = 1,
389 .server = ""
391 .level = 78,
392 .server = ""
394 .level = 1,
395 .server = talloc_asprintf(ctx, "\\\\%s", dcerpc_server_name(p))
397 .level = 1024,
398 .server = talloc_asprintf(ctx, "\\\\%s", dcerpc_server_name(p))
401 int i;
402 uint32_t needed;
404 for (i=0;i<ARRAY_SIZE(levels);i++) {
405 int level = levels[i].level;
406 DATA_BLOB blob;
408 r.in.server = levels[i].server;
409 r.in.environment = environment;
410 r.in.level = level;
411 r.in.buffer = NULL;
412 r.in.offered = 0;
413 r.out.needed = &needed;
415 torture_comment(tctx, "Testing GetPrinterDriverDirectory level %u\n", r.in.level);
417 status = dcerpc_spoolss_GetPrinterDriverDirectory(p, ctx, &r);
418 torture_assert_ntstatus_ok(tctx, status,
419 "dcerpc_spoolss_GetPrinterDriverDirectory failed");
420 torture_assert_werr_equal(tctx, r.out.result, WERR_INSUFFICIENT_BUFFER,
421 "GetPrinterDriverDirectory unexpected return code");
423 blob = data_blob_talloc(ctx, NULL, needed);
424 data_blob_clear(&blob);
425 r.in.buffer = &blob;
426 r.in.offered = needed;
428 status = dcerpc_spoolss_GetPrinterDriverDirectory(p, ctx, &r);
429 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_GetPrinterDriverDirectory failed");
431 torture_assert_werr_ok(tctx, r.out.result, "GetPrinterDriverDirectory failed");
433 CHECK_NEEDED_SIZE_LEVEL(spoolss_DriverDirectoryInfo, r.out.info, r.in.level, lp_iconv_convenience(tctx->lp_ctx), needed, 2);
436 return true;
439 static bool test_EnumPrinterDrivers(struct torture_context *tctx,
440 struct dcerpc_pipe *p,
441 struct test_spoolss_context *ctx,
442 const char *architecture)
444 NTSTATUS status;
445 struct spoolss_EnumPrinterDrivers r;
446 uint16_t levels[] = { 1, 2, 3, 4, 5, 6, 8 };
447 int i, j;
449 for (i=0;i<ARRAY_SIZE(levels);i++) {
450 int level = levels[i];
451 DATA_BLOB blob;
452 uint32_t needed;
453 uint32_t count;
454 union spoolss_DriverInfo *info;
456 /* FIXME: gd, come back and fix "" as server, and handle
457 * priority of returned error codes in torture test and samba 3
458 * server */
460 r.in.server = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
461 r.in.environment = architecture;
462 r.in.level = level;
463 r.in.buffer = NULL;
464 r.in.offered = 0;
465 r.out.needed = &needed;
466 r.out.count = &count;
467 r.out.info = &info;
469 torture_comment(tctx, "Testing EnumPrinterDrivers level %u (%s)\n", r.in.level, r.in.environment);
471 status = dcerpc_spoolss_EnumPrinterDrivers(p, ctx, &r);
472 torture_assert_ntstatus_ok(tctx, status,
473 "dcerpc_spoolss_EnumPrinterDrivers failed");
474 if (W_ERROR_IS_OK(r.out.result)) {
475 /* TODO: do some more checks here */
476 continue;
478 if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
479 blob = data_blob_talloc(ctx, NULL, needed);
480 data_blob_clear(&blob);
481 r.in.buffer = &blob;
482 r.in.offered = needed;
484 status = dcerpc_spoolss_EnumPrinterDrivers(p, ctx, &r);
485 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EnumPrinterDrivers failed");
488 torture_assert_werr_ok(tctx, r.out.result, "EnumPrinterDrivers failed");
490 CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumPrinterDrivers, info, r.in.level, count, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
492 ctx->driver_count[level] = count;
493 ctx->drivers[level] = info;
496 for (i=1;i<ARRAY_SIZE(levels);i++) {
497 int level = levels[i];
498 int old_level = levels[i-1];
500 torture_assert_int_equal(tctx, ctx->driver_count[level], ctx->driver_count[old_level],
501 "EnumPrinterDrivers invalid value");
504 for (i=0;i<ARRAY_SIZE(levels);i++) {
505 int level = levels[i];
507 for (j=0;j<ctx->driver_count[level];j++) {
508 union spoolss_DriverInfo *cur = &ctx->drivers[level][j];
509 union spoolss_DriverInfo *ref = &ctx->drivers[8][j];
511 switch (level) {
512 case 1:
513 COMPARE_STRING(tctx, cur->info1, ref->info8, driver_name);
514 break;
515 case 2:
516 COMPARE_UINT32(tctx, cur->info2, ref->info8, version);
517 COMPARE_STRING(tctx, cur->info2, ref->info8, driver_name);
518 COMPARE_STRING(tctx, cur->info2, ref->info8, architecture);
519 COMPARE_STRING(tctx, cur->info2, ref->info8, driver_path);
520 COMPARE_STRING(tctx, cur->info2, ref->info8, data_file);
521 COMPARE_STRING(tctx, cur->info2, ref->info8, config_file);
522 break;
523 case 3:
524 COMPARE_UINT32(tctx, cur->info3, ref->info8, version);
525 COMPARE_STRING(tctx, cur->info3, ref->info8, driver_name);
526 COMPARE_STRING(tctx, cur->info3, ref->info8, architecture);
527 COMPARE_STRING(tctx, cur->info3, ref->info8, driver_path);
528 COMPARE_STRING(tctx, cur->info3, ref->info8, data_file);
529 COMPARE_STRING(tctx, cur->info3, ref->info8, config_file);
530 COMPARE_STRING(tctx, cur->info3, ref->info8, help_file);
531 COMPARE_STRING_ARRAY(tctx, cur->info3, ref->info8, dependent_files);
532 COMPARE_STRING(tctx, cur->info3, ref->info8, monitor_name);
533 COMPARE_STRING(tctx, cur->info3, ref->info8, default_datatype);
534 break;
535 case 4:
536 COMPARE_UINT32(tctx, cur->info4, ref->info8, version);
537 COMPARE_STRING(tctx, cur->info4, ref->info8, driver_name);
538 COMPARE_STRING(tctx, cur->info4, ref->info8, architecture);
539 COMPARE_STRING(tctx, cur->info4, ref->info8, driver_path);
540 COMPARE_STRING(tctx, cur->info4, ref->info8, data_file);
541 COMPARE_STRING(tctx, cur->info4, ref->info8, config_file);
542 COMPARE_STRING(tctx, cur->info4, ref->info8, help_file);
543 COMPARE_STRING_ARRAY(tctx, cur->info4, ref->info8, dependent_files);
544 COMPARE_STRING(tctx, cur->info4, ref->info8, monitor_name);
545 COMPARE_STRING(tctx, cur->info4, ref->info8, default_datatype);
546 COMPARE_STRING_ARRAY(tctx, cur->info4, ref->info8, previous_names);
547 break;
548 case 5:
549 COMPARE_UINT32(tctx, cur->info5, ref->info8, version);
550 COMPARE_STRING(tctx, cur->info5, ref->info8, driver_name);
551 COMPARE_STRING(tctx, cur->info5, ref->info8, architecture);
552 COMPARE_STRING(tctx, cur->info5, ref->info8, driver_path);
553 COMPARE_STRING(tctx, cur->info5, ref->info8, data_file);
554 COMPARE_STRING(tctx, cur->info5, ref->info8, config_file);
555 /*COMPARE_UINT32(tctx, cur->info5, ref->info8, driver_attributes);*/
556 /*COMPARE_UINT32(tctx, cur->info5, ref->info8, config_version);*/
557 /*TODO: ! COMPARE_UINT32(tctx, cur->info5, ref->info8, driver_version); */
558 break;
559 case 6:
560 COMPARE_UINT32(tctx, cur->info6, ref->info8, version);
561 COMPARE_STRING(tctx, cur->info6, ref->info8, driver_name);
562 COMPARE_STRING(tctx, cur->info6, ref->info8, architecture);
563 COMPARE_STRING(tctx, cur->info6, ref->info8, driver_path);
564 COMPARE_STRING(tctx, cur->info6, ref->info8, data_file);
565 COMPARE_STRING(tctx, cur->info6, ref->info8, config_file);
566 COMPARE_STRING(tctx, cur->info6, ref->info8, help_file);
567 COMPARE_STRING_ARRAY(tctx, cur->info6, ref->info8, dependent_files);
568 COMPARE_STRING(tctx, cur->info6, ref->info8, monitor_name);
569 COMPARE_STRING(tctx, cur->info6, ref->info8, default_datatype);
570 COMPARE_STRING_ARRAY(tctx, cur->info6, ref->info8, previous_names);
571 COMPARE_NTTIME(tctx, cur->info6, ref->info8, driver_date);
572 COMPARE_UINT64(tctx, cur->info6, ref->info8, driver_version);
573 COMPARE_STRING(tctx, cur->info6, ref->info8, manufacturer_name);
574 COMPARE_STRING(tctx, cur->info6, ref->info8, manufacturer_url);
575 COMPARE_STRING(tctx, cur->info6, ref->info8, hardware_id);
576 COMPARE_STRING(tctx, cur->info6, ref->info8, provider);
577 break;
578 case 8:
579 /* level 8 is our reference, and it makes no sense to compare it to itself */
580 break;
585 return true;
588 static bool test_EnumMonitors(struct torture_context *tctx,
589 struct dcerpc_pipe *p,
590 struct test_spoolss_context *ctx)
592 NTSTATUS status;
593 struct spoolss_EnumMonitors r;
594 uint16_t levels[] = { 1, 2 };
595 int i, j;
597 for (i=0;i<ARRAY_SIZE(levels);i++) {
598 int level = levels[i];
599 DATA_BLOB blob;
600 uint32_t needed;
601 uint32_t count;
602 union spoolss_MonitorInfo *info;
604 r.in.servername = "";
605 r.in.level = level;
606 r.in.buffer = NULL;
607 r.in.offered = 0;
608 r.out.needed = &needed;
609 r.out.count = &count;
610 r.out.info = &info;
612 torture_comment(tctx, "Testing EnumMonitors level %u\n", r.in.level);
614 status = dcerpc_spoolss_EnumMonitors(p, ctx, &r);
615 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EnumMonitors failed");
616 if (W_ERROR_IS_OK(r.out.result)) {
617 /* TODO: do some more checks here */
618 continue;
620 torture_assert_werr_equal(tctx, r.out.result, WERR_INSUFFICIENT_BUFFER,
621 "EnumMonitors failed");
623 blob = data_blob_talloc(ctx, NULL, needed);
624 data_blob_clear(&blob);
625 r.in.buffer = &blob;
626 r.in.offered = needed;
628 status = dcerpc_spoolss_EnumMonitors(p, ctx, &r);
629 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EnumMonitors failed");
631 torture_assert_werr_ok(tctx, r.out.result, "EnumMonitors failed");
633 CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumMonitors, info, r.in.level, count, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
635 ctx->monitor_count[level] = count;
636 ctx->monitors[level] = info;
639 for (i=1;i<ARRAY_SIZE(levels);i++) {
640 int level = levels[i];
641 int old_level = levels[i-1];
642 torture_assert_int_equal(tctx, ctx->monitor_count[level], ctx->monitor_count[old_level],
643 "EnumMonitors invalid value");
646 for (i=0;i<ARRAY_SIZE(levels);i++) {
647 int level = levels[i];
648 for (j=0;j<ctx->monitor_count[level];j++) {
649 union spoolss_MonitorInfo *cur = &ctx->monitors[level][j];
650 union spoolss_MonitorInfo *ref = &ctx->monitors[2][j];
651 switch (level) {
652 case 1:
653 COMPARE_STRING(tctx, cur->info1, ref->info2, monitor_name);
654 break;
655 case 2:
656 /* level 2 is our reference, and it makes no sense to compare it to itself */
657 break;
662 return true;
665 static bool test_EnumPrintProcessors(struct torture_context *tctx,
666 struct dcerpc_pipe *p,
667 struct test_spoolss_context *ctx,
668 const char *environment)
670 NTSTATUS status;
671 struct spoolss_EnumPrintProcessors r;
672 uint16_t levels[] = { 1 };
673 int i, j;
675 for (i=0;i<ARRAY_SIZE(levels);i++) {
676 int level = levels[i];
677 DATA_BLOB blob;
678 uint32_t needed;
679 uint32_t count;
680 union spoolss_PrintProcessorInfo *info;
682 r.in.servername = "";
683 r.in.environment = environment;
684 r.in.level = level;
685 r.in.buffer = NULL;
686 r.in.offered = 0;
687 r.out.needed = &needed;
688 r.out.count = &count;
689 r.out.info = &info;
691 torture_comment(tctx, "Testing EnumPrintProcessors level %u\n", r.in.level);
693 status = dcerpc_spoolss_EnumPrintProcessors(p, ctx, &r);
694 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EnumPrintProcessors failed");
695 if (W_ERROR_IS_OK(r.out.result)) {
696 /* TODO: do some more checks here */
697 continue;
699 torture_assert_werr_equal(tctx, r.out.result, WERR_INSUFFICIENT_BUFFER,
700 "EnumPrintProcessors unexpected return code");
702 blob = data_blob_talloc(ctx, NULL, needed);
703 data_blob_clear(&blob);
704 r.in.buffer = &blob;
705 r.in.offered = needed;
707 status = dcerpc_spoolss_EnumPrintProcessors(p, ctx, &r);
708 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EnumPrintProcessors failed");
710 torture_assert_werr_ok(tctx, r.out.result, "EnumPrintProcessors failed");
712 CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumPrintProcessors, info, r.in.level, count, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
714 ctx->print_processor_count[level] = count;
715 ctx->print_processors[level] = info;
718 for (i=1;i<ARRAY_SIZE(levels);i++) {
719 int level = levels[i];
720 int old_level = levels[i-1];
721 torture_assert_int_equal(tctx, ctx->print_processor_count[level], ctx->print_processor_count[old_level],
722 "EnumPrintProcessors failed");
725 for (i=0;i<ARRAY_SIZE(levels);i++) {
726 int level = levels[i];
727 for (j=0;j<ctx->print_processor_count[level];j++) {
728 #if 0
729 union spoolss_PrintProcessorInfo *cur = &ctx->print_processors[level][j];
730 union spoolss_PrintProcessorInfo *ref = &ctx->print_processors[1][j];
731 #endif
732 switch (level) {
733 case 1:
734 /* level 1 is our reference, and it makes no sense to compare it to itself */
735 break;
740 return true;
743 static bool test_EnumPrintProcDataTypes(struct torture_context *tctx,
744 struct dcerpc_pipe *p,
745 struct test_spoolss_context *ctx)
747 NTSTATUS status;
748 struct spoolss_EnumPrintProcDataTypes r;
749 uint16_t levels[] = { 1 };
750 int i;
752 for (i=0;i<ARRAY_SIZE(levels);i++) {
753 int level = levels[i];
754 DATA_BLOB blob;
755 uint32_t needed;
756 uint32_t count;
757 union spoolss_PrintProcDataTypesInfo *info;
759 r.in.servername = "";
760 r.in.print_processor_name = "winprint";
761 r.in.level = level;
762 r.in.buffer = NULL;
763 r.in.offered = 0;
764 r.out.needed = &needed;
765 r.out.count = &count;
766 r.out.info = &info;
768 torture_comment(tctx, "Testing EnumPrintProcDataTypes level %u\n", r.in.level);
770 status = dcerpc_spoolss_EnumPrintProcDataTypes(p, ctx, &r);
771 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EnumPrintProcDataType failed");
772 if (W_ERROR_IS_OK(r.out.result)) {
773 /* TODO: do some more checks here */
774 continue;
776 torture_assert_werr_equal(tctx, r.out.result, WERR_INSUFFICIENT_BUFFER,
777 "EnumPrintProcDataTypes unexpected return code");
779 blob = data_blob_talloc(ctx, NULL, needed);
780 data_blob_clear(&blob);
781 r.in.buffer = &blob;
782 r.in.offered = needed;
784 status = dcerpc_spoolss_EnumPrintProcDataTypes(p, ctx, &r);
785 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EnumPrintProcDataTypes failed");
787 torture_assert_werr_ok(tctx, r.out.result, "EnumPrintProcDataTypes failed");
789 CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumPrintProcDataTypes, info, r.in.level, count, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
793 return true;
797 static bool test_EnumPrinters(struct torture_context *tctx,
798 struct dcerpc_pipe *p,
799 struct test_spoolss_context *ctx)
801 struct spoolss_EnumPrinters r;
802 NTSTATUS status;
803 uint16_t levels[] = { 0, 1, 2, 4, 5 };
804 int i, j;
806 for (i=0;i<ARRAY_SIZE(levels);i++) {
807 int level = levels[i];
808 DATA_BLOB blob;
809 uint32_t needed;
810 uint32_t count;
811 union spoolss_PrinterInfo *info;
813 r.in.flags = PRINTER_ENUM_LOCAL;
814 r.in.server = "";
815 r.in.level = level;
816 r.in.buffer = NULL;
817 r.in.offered = 0;
818 r.out.needed = &needed;
819 r.out.count = &count;
820 r.out.info = &info;
822 torture_comment(tctx, "Testing EnumPrinters level %u\n", r.in.level);
824 status = dcerpc_spoolss_EnumPrinters(p, ctx, &r);
825 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EnumPrinters failed");
826 if (W_ERROR_IS_OK(r.out.result)) {
827 /* TODO: do some more checks here */
828 continue;
830 torture_assert_werr_equal(tctx, r.out.result, WERR_INSUFFICIENT_BUFFER,
831 "EnumPrinters unexpected return code");
833 blob = data_blob_talloc(ctx, NULL, needed);
834 data_blob_clear(&blob);
835 r.in.buffer = &blob;
836 r.in.offered = needed;
838 status = dcerpc_spoolss_EnumPrinters(p, ctx, &r);
839 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EnumPrinters failed");
841 torture_assert_werr_ok(tctx, r.out.result, "EnumPrinters failed");
843 CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumPrinters, info, r.in.level, count, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
845 ctx->printer_count[level] = count;
846 ctx->printers[level] = info;
849 for (i=1;i<ARRAY_SIZE(levels);i++) {
850 int level = levels[i];
851 int old_level = levels[i-1];
852 torture_assert_int_equal(tctx, ctx->printer_count[level], ctx->printer_count[old_level],
853 "EnumPrinters invalid value");
856 for (i=0;i<ARRAY_SIZE(levels);i++) {
857 int level = levels[i];
858 for (j=0;j<ctx->printer_count[level];j++) {
859 union spoolss_PrinterInfo *cur = &ctx->printers[level][j];
860 union spoolss_PrinterInfo *ref = &ctx->printers[2][j];
861 switch (level) {
862 case 0:
863 COMPARE_STRING(tctx, cur->info0, ref->info2, printername);
864 COMPARE_STRING(tctx, cur->info0, ref->info2, servername);
865 COMPARE_UINT32(tctx, cur->info0, ref->info2, cjobs);
866 /*COMPARE_UINT32(tctx, cur->info0, ref->info2, total_jobs);
867 COMPARE_UINT32(tctx, cur->info0, ref->info2, total_bytes);
868 COMPARE_SPOOLSS_TIME(cur->info0, ref->info2, spoolss_Time time);
869 COMPARE_UINT32(tctx, cur->info0, ref->info2, global_counter);
870 COMPARE_UINT32(tctx, cur->info0, ref->info2, total_pages);
871 COMPARE_UINT32(tctx, cur->info0, ref->info2, version);
872 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown10);
873 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown11);
874 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown12);
875 COMPARE_UINT32(tctx, cur->info0, ref->info2, session_counter);
876 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown14);
877 COMPARE_UINT32(tctx, cur->info0, ref->info2, printer_errors);
878 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown16);
879 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown17);
880 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown18);
881 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown19);
882 COMPARE_UINT32(tctx, cur->info0, ref->info2, change_id);
883 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown21);*/
884 COMPARE_UINT32(tctx, cur->info0, ref->info2, status);
885 /*COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown23);
886 COMPARE_UINT32(tctx, cur->info0, ref->info2, c_setprinter);
887 COMPARE_UINT16(cur->info0, ref->info2, unknown25);
888 COMPARE_UINT16(cur->info0, ref->info2, unknown26);
889 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown27);
890 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown28);
891 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown29);*/
892 break;
893 case 1:
894 /*COMPARE_UINT32(tctx, cur->info1, ref->info2, flags);*/
895 /*COMPARE_STRING(tctx, cur->info1, ref->info2, name);*/
896 /*COMPARE_STRING(tctx, cur->info1, ref->info2, description);*/
897 COMPARE_STRING(tctx, cur->info1, ref->info2, comment);
898 break;
899 case 2:
900 /* level 2 is our reference, and it makes no sense to compare it to itself */
901 break;
902 case 4:
903 COMPARE_STRING(tctx, cur->info4, ref->info2, printername);
904 COMPARE_STRING(tctx, cur->info4, ref->info2, servername);
905 COMPARE_UINT32(tctx, cur->info4, ref->info2, attributes);
906 break;
907 case 5:
908 COMPARE_STRING(tctx, cur->info5, ref->info2, printername);
909 COMPARE_STRING(tctx, cur->info5, ref->info2, portname);
910 COMPARE_UINT32(tctx, cur->info5, ref->info2, attributes);
911 /*COMPARE_UINT32(tctx, cur->info5, ref->info2, device_not_selected_timeout);
912 COMPARE_UINT32(tctx, cur->info5, ref->info2, transmission_retry_timeout);*/
913 break;
918 /* TODO:
919 * - verify that the port of a printer was in the list returned by EnumPorts
922 return true;
925 static bool test_GetPrinterDriver2(struct torture_context *tctx,
926 struct dcerpc_pipe *p,
927 struct policy_handle *handle,
928 const char *driver_name,
929 const char *environment);
931 bool test_GetPrinter_level(struct torture_context *tctx,
932 struct dcerpc_pipe *p,
933 struct policy_handle *handle,
934 uint32_t level,
935 union spoolss_PrinterInfo *info)
937 struct spoolss_GetPrinter r;
938 uint32_t needed;
940 r.in.handle = handle;
941 r.in.level = level;
942 r.in.buffer = NULL;
943 r.in.offered = 0;
944 r.out.needed = &needed;
946 torture_comment(tctx, "Testing GetPrinter level %u\n", r.in.level);
948 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_GetPrinter(p, tctx, &r),
949 "GetPrinter failed");
951 if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
952 DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed);
953 data_blob_clear(&blob);
954 r.in.buffer = &blob;
955 r.in.offered = needed;
957 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_GetPrinter(p, tctx, &r),
958 "GetPrinter failed");
961 torture_assert_werr_ok(tctx, r.out.result, "GetPrinter failed");
963 CHECK_NEEDED_SIZE_LEVEL(spoolss_PrinterInfo, r.out.info, r.in.level, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
965 if (info && r.out.info) {
966 *info = *r.out.info;
969 return true;
973 static bool test_GetPrinter(struct torture_context *tctx,
974 struct dcerpc_pipe *p,
975 struct policy_handle *handle,
976 const char *environment)
978 uint32_t levels[] = {0, 1, 2, 3, 4, 5, 6, 7, 8};
979 int i;
981 for (i=0;i<ARRAY_SIZE(levels);i++) {
983 union spoolss_PrinterInfo info;
985 ZERO_STRUCT(info);
987 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, levels[i], &info),
988 "failed to call GetPrinter");
990 if ((levels[i] == 2) && info.info2.drivername && strlen(info.info2.drivername)) {
991 torture_assert(tctx,
992 test_GetPrinterDriver2(tctx, p, handle, info.info2.drivername, environment),
993 "failed to call test_GetPrinterDriver2");
997 return true;
1000 static bool test_SetPrinter(struct torture_context *tctx,
1001 struct dcerpc_pipe *p,
1002 struct policy_handle *handle,
1003 struct spoolss_SetPrinterInfoCtr *info_ctr,
1004 struct spoolss_DevmodeContainer *devmode_ctr,
1005 struct sec_desc_buf *secdesc_ctr,
1006 enum spoolss_PrinterControl command)
1008 struct spoolss_SetPrinter r;
1010 r.in.handle = handle;
1011 r.in.info_ctr = info_ctr;
1012 r.in.devmode_ctr = devmode_ctr;
1013 r.in.secdesc_ctr = secdesc_ctr;
1014 r.in.command = command;
1016 torture_comment(tctx, "Testing SetPrinter level %d\n", r.in.info_ctr->level);
1018 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_SetPrinter(p, tctx, &r),
1019 "failed to call SetPrinter");
1020 torture_assert_werr_ok(tctx, r.out.result,
1021 "failed to call SetPrinter");
1023 return true;
1026 static bool test_SetPrinter_errors(struct torture_context *tctx,
1027 struct dcerpc_pipe *p,
1028 struct policy_handle *handle)
1030 struct spoolss_SetPrinter r;
1031 uint16_t levels[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
1032 int i;
1034 struct spoolss_SetPrinterInfoCtr info_ctr;
1035 struct spoolss_DevmodeContainer devmode_ctr;
1036 struct sec_desc_buf secdesc_ctr;
1038 info_ctr.level = 0;
1039 info_ctr.info.info0 = NULL;
1041 ZERO_STRUCT(devmode_ctr);
1042 ZERO_STRUCT(secdesc_ctr);
1044 r.in.handle = handle;
1045 r.in.info_ctr = &info_ctr;
1046 r.in.devmode_ctr = &devmode_ctr;
1047 r.in.secdesc_ctr = &secdesc_ctr;
1048 r.in.command = 0;
1050 torture_comment(tctx, "Testing SetPrinter all zero\n");
1052 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_SetPrinter(p, tctx, &r),
1053 "failed to call SetPrinter");
1054 torture_assert_werr_equal(tctx, r.out.result, WERR_INVALID_PARAM,
1055 "failed to call SetPrinter");
1057 again:
1058 for (i=0; i < ARRAY_SIZE(levels); i++) {
1060 struct spoolss_SetPrinterInfo0 info0;
1061 struct spoolss_SetPrinterInfo1 info1;
1062 struct spoolss_SetPrinterInfo2 info2;
1063 struct spoolss_SetPrinterInfo3 info3;
1064 struct spoolss_SetPrinterInfo4 info4;
1065 struct spoolss_SetPrinterInfo5 info5;
1066 struct spoolss_SetPrinterInfo6 info6;
1067 struct spoolss_SetPrinterInfo7 info7;
1068 struct spoolss_SetPrinterInfo8 info8;
1069 struct spoolss_SetPrinterInfo9 info9;
1072 info_ctr.level = levels[i];
1073 switch (levels[i]) {
1074 case 0:
1075 ZERO_STRUCT(info0);
1076 info_ctr.info.info0 = &info0;
1077 break;
1078 case 1:
1079 ZERO_STRUCT(info1);
1080 info_ctr.info.info1 = &info1;
1081 break;
1082 case 2:
1083 ZERO_STRUCT(info2);
1084 info_ctr.info.info2 = &info2;
1085 break;
1086 case 3:
1087 ZERO_STRUCT(info3);
1088 info_ctr.info.info3 = &info3;
1089 break;
1090 case 4:
1091 ZERO_STRUCT(info4);
1092 info_ctr.info.info4 = &info4;
1093 break;
1094 case 5:
1095 ZERO_STRUCT(info5);
1096 info_ctr.info.info5 = &info5;
1097 break;
1098 case 6:
1099 ZERO_STRUCT(info6);
1100 info_ctr.info.info6 = &info6;
1101 break;
1102 case 7:
1103 ZERO_STRUCT(info7);
1104 info_ctr.info.info7 = &info7;
1105 break;
1106 case 8:
1107 ZERO_STRUCT(info8);
1108 info_ctr.info.info8 = &info8;
1109 break;
1110 case 9:
1111 ZERO_STRUCT(info9);
1112 info_ctr.info.info9 = &info9;
1113 break;
1116 torture_comment(tctx, "Testing SetPrinter level %d, command %d\n",
1117 info_ctr.level, r.in.command);
1119 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_SetPrinter(p, tctx, &r),
1120 "failed to call SetPrinter");
1122 switch (r.in.command) {
1123 case SPOOLSS_PRINTER_CONTROL_UNPAUSE: /* 0 */
1124 /* is ignored for all levels other then 0 */
1125 if (info_ctr.level > 0) {
1126 /* ignored then */
1127 break;
1129 case SPOOLSS_PRINTER_CONTROL_PAUSE: /* 1 */
1130 case SPOOLSS_PRINTER_CONTROL_RESUME: /* 2 */
1131 case SPOOLSS_PRINTER_CONTROL_PURGE: /* 3 */
1132 if (info_ctr.level > 0) {
1133 /* is invalid for all levels other then 0 */
1134 torture_assert_werr_equal(tctx, r.out.result, WERR_INVALID_PRINTER_COMMAND,
1135 "unexpected error code returned");
1136 continue;
1137 } else {
1138 torture_assert_werr_ok(tctx, r.out.result,
1139 "failed to call SetPrinter with non 0 command");
1140 continue;
1142 break;
1144 case SPOOLSS_PRINTER_CONTROL_SET_STATUS: /* 4 */
1145 /* FIXME: gd needs further investigation */
1146 default:
1147 torture_assert_werr_equal(tctx, r.out.result, WERR_INVALID_PRINTER_COMMAND,
1148 "unexpected error code returned");
1149 continue;
1152 switch (info_ctr.level) {
1153 case 1:
1154 torture_assert_werr_equal(tctx, r.out.result, WERR_UNKNOWN_LEVEL,
1155 "unexpected error code returned");
1156 break;
1157 case 2:
1158 torture_assert_werr_equal(tctx, r.out.result, WERR_UNKNOWN_PRINTER_DRIVER,
1159 "unexpected error code returned");
1160 break;
1161 case 3:
1162 case 4:
1163 case 5:
1164 case 7:
1165 torture_assert_werr_equal(tctx, r.out.result, WERR_INVALID_PARAM,
1166 "unexpected error code returned");
1167 break;
1168 case 9:
1169 torture_assert_werr_equal(tctx, r.out.result, WERR_NOT_SUPPORTED,
1170 "unexpected error code returned");
1171 break;
1172 default:
1173 torture_assert_werr_ok(tctx, r.out.result,
1174 "failed to call SetPrinter");
1175 break;
1179 if (r.in.command < 5) {
1180 r.in.command++;
1181 goto again;
1184 return true;
1187 static void clear_info2(struct spoolss_SetPrinterInfoCtr *r)
1189 if ((r->level == 2) && (r->info.info2)) {
1190 r->info.info2->secdesc_ptr = 0;
1191 r->info.info2->devmode_ptr = 0;
1195 static bool test_PrinterInfo(struct torture_context *tctx,
1196 struct dcerpc_pipe *p,
1197 struct policy_handle *handle)
1199 NTSTATUS status;
1200 struct spoolss_SetPrinter s;
1201 struct spoolss_GetPrinter q;
1202 struct spoolss_GetPrinter q0;
1203 struct spoolss_SetPrinterInfoCtr info_ctr;
1204 union spoolss_PrinterInfo info;
1205 struct spoolss_DevmodeContainer devmode_ctr;
1206 struct sec_desc_buf secdesc_ctr;
1207 uint32_t needed;
1208 bool ret = true;
1209 int i;
1211 uint32_t status_list[] = {
1212 /* these do not stick
1213 PRINTER_STATUS_PAUSED,
1214 PRINTER_STATUS_ERROR,
1215 PRINTER_STATUS_PENDING_DELETION, */
1216 PRINTER_STATUS_PAPER_JAM,
1217 PRINTER_STATUS_PAPER_OUT,
1218 PRINTER_STATUS_MANUAL_FEED,
1219 PRINTER_STATUS_PAPER_PROBLEM,
1220 PRINTER_STATUS_OFFLINE,
1221 PRINTER_STATUS_IO_ACTIVE,
1222 PRINTER_STATUS_BUSY,
1223 PRINTER_STATUS_PRINTING,
1224 PRINTER_STATUS_OUTPUT_BIN_FULL,
1225 PRINTER_STATUS_NOT_AVAILABLE,
1226 PRINTER_STATUS_WAITING,
1227 PRINTER_STATUS_PROCESSING,
1228 PRINTER_STATUS_INITIALIZING,
1229 PRINTER_STATUS_WARMING_UP,
1230 PRINTER_STATUS_TONER_LOW,
1231 PRINTER_STATUS_NO_TONER,
1232 PRINTER_STATUS_PAGE_PUNT,
1233 PRINTER_STATUS_USER_INTERVENTION,
1234 PRINTER_STATUS_OUT_OF_MEMORY,
1235 PRINTER_STATUS_DOOR_OPEN,
1236 PRINTER_STATUS_SERVER_UNKNOWN,
1237 PRINTER_STATUS_POWER_SAVE,
1238 /* these do not stick
1239 0x02000000,
1240 0x04000000,
1241 0x08000000,
1242 0x10000000,
1243 0x20000000,
1244 0x40000000,
1245 0x80000000 */
1247 uint32_t default_attribute = PRINTER_ATTRIBUTE_LOCAL;
1248 uint32_t attribute_list[] = {
1249 PRINTER_ATTRIBUTE_QUEUED,
1250 /* fails with WERR_INVALID_DATATYPE:
1251 PRINTER_ATTRIBUTE_DIRECT, */
1252 /* does not stick
1253 PRINTER_ATTRIBUTE_DEFAULT, */
1254 PRINTER_ATTRIBUTE_SHARED,
1255 /* does not stick
1256 PRINTER_ATTRIBUTE_NETWORK, */
1257 PRINTER_ATTRIBUTE_HIDDEN,
1258 PRINTER_ATTRIBUTE_LOCAL,
1259 PRINTER_ATTRIBUTE_ENABLE_DEVQ,
1260 PRINTER_ATTRIBUTE_KEEPPRINTEDJOBS,
1261 PRINTER_ATTRIBUTE_DO_COMPLETE_FIRST,
1262 PRINTER_ATTRIBUTE_WORK_OFFLINE,
1263 /* does not stick
1264 PRINTER_ATTRIBUTE_ENABLE_BIDI, */
1265 /* fails with WERR_INVALID_DATATYPE:
1266 PRINTER_ATTRIBUTE_RAW_ONLY, */
1267 /* these do not stick
1268 PRINTER_ATTRIBUTE_PUBLISHED,
1269 PRINTER_ATTRIBUTE_FAX,
1270 PRINTER_ATTRIBUTE_TS,
1271 0x00010000,
1272 0x00020000,
1273 0x00040000,
1274 0x00080000,
1275 0x00100000,
1276 0x00200000,
1277 0x00400000,
1278 0x00800000,
1279 0x01000000,
1280 0x02000000,
1281 0x04000000,
1282 0x08000000,
1283 0x10000000,
1284 0x20000000,
1285 0x40000000,
1286 0x80000000 */
1289 ZERO_STRUCT(devmode_ctr);
1290 ZERO_STRUCT(secdesc_ctr);
1292 s.in.handle = handle;
1293 s.in.command = 0;
1294 s.in.info_ctr = &info_ctr;
1295 s.in.devmode_ctr = &devmode_ctr;
1296 s.in.secdesc_ctr = &secdesc_ctr;
1298 q.in.handle = handle;
1299 q.out.info = &info;
1300 q0 = q;
1302 #define TESTGETCALL(call, r) \
1303 r.in.buffer = NULL; \
1304 r.in.offered = 0;\
1305 r.out.needed = &needed; \
1306 status = dcerpc_spoolss_ ##call(p, tctx, &r); \
1307 if (!NT_STATUS_IS_OK(status)) { \
1308 torture_comment(tctx, #call " level %u failed - %s (%s)\n", \
1309 r.in.level, nt_errstr(status), __location__); \
1310 ret = false; \
1311 break; \
1313 if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {\
1314 DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed); \
1315 data_blob_clear(&blob); \
1316 r.in.buffer = &blob; \
1317 r.in.offered = needed; \
1319 status = dcerpc_spoolss_ ##call(p, tctx, &r); \
1320 if (!NT_STATUS_IS_OK(status)) { \
1321 torture_comment(tctx, #call " level %u failed - %s (%s)\n", \
1322 r.in.level, nt_errstr(status), __location__); \
1323 ret = false; \
1324 break; \
1326 if (!W_ERROR_IS_OK(r.out.result)) { \
1327 torture_comment(tctx, #call " level %u failed - %s (%s)\n", \
1328 r.in.level, win_errstr(r.out.result), __location__); \
1329 ret = false; \
1330 break; \
1334 #define TESTSETCALL_EXP(call, r, err) \
1335 clear_info2(&info_ctr);\
1336 status = dcerpc_spoolss_ ##call(p, tctx, &r); \
1337 if (!NT_STATUS_IS_OK(status)) { \
1338 torture_comment(tctx, #call " level %u failed - %s (%s)\n", \
1339 r.in.info_ctr->level, nt_errstr(status), __location__); \
1340 ret = false; \
1341 break; \
1343 if (!W_ERROR_IS_OK(err)) { \
1344 if (!W_ERROR_EQUAL(err, r.out.result)) { \
1345 torture_comment(tctx, #call " level %u failed - %s, expected %s (%s)\n", \
1346 r.in.info_ctr->level, win_errstr(r.out.result), win_errstr(err), __location__); \
1347 ret = false; \
1349 break; \
1351 if (!W_ERROR_IS_OK(r.out.result)) { \
1352 torture_comment(tctx, #call " level %u failed - %s (%s)\n", \
1353 r.in.info_ctr->level, win_errstr(r.out.result), __location__); \
1354 ret = false; \
1355 break; \
1358 #define TESTSETCALL(call, r) \
1359 TESTSETCALL_EXP(call, r, WERR_OK)
1361 #define STRING_EQUAL(s1, s2, field) \
1362 if ((s1 && !s2) || (s2 && !s1) || strcmp(s1, s2)) { \
1363 torture_comment(tctx, "Failed to set %s to '%s' (%s)\n", \
1364 #field, s2, __location__); \
1365 ret = false; \
1366 break; \
1369 #define MEM_EQUAL(s1, s2, length, field) \
1370 if ((s1 && !s2) || (s2 && !s1) || memcmp(s1, s2, length)) { \
1371 torture_comment(tctx, "Failed to set %s to '%s' (%s)\n", \
1372 #field, (const char *)s2, __location__); \
1373 ret = false; \
1374 break; \
1377 #define INT_EQUAL(i1, i2, field) \
1378 if (i1 != i2) { \
1379 torture_comment(tctx, "Failed to set %s to 0x%llx - got 0x%llx (%s)\n", \
1380 #field, (unsigned long long)i2, (unsigned long long)i1, __location__); \
1381 ret = false; \
1382 break; \
1385 #define SD_EQUAL(sd1, sd2, field) \
1386 if (!security_descriptor_equal(sd1, sd2)) { \
1387 torture_comment(tctx, "Failed to set %s (%s)\n", \
1388 #field, __location__); \
1389 ret = false; \
1390 break; \
1393 #define TEST_PRINTERINFO_STRING_EXP_ERR(lvl1, field1, lvl2, field2, value, err) do { \
1394 torture_comment(tctx, "field test %d/%s vs %d/%s\n", lvl1, #field1, lvl2, #field2); \
1395 q.in.level = lvl1; \
1396 TESTGETCALL(GetPrinter, q) \
1397 info_ctr.level = lvl1; \
1398 info_ctr.info.info ## lvl1 = (struct spoolss_SetPrinterInfo ## lvl1 *)&q.out.info->info ## lvl1; \
1399 info_ctr.info.info ## lvl1->field1 = value;\
1400 TESTSETCALL_EXP(SetPrinter, s, err) \
1401 info_ctr.info.info ## lvl1->field1 = ""; \
1402 TESTGETCALL(GetPrinter, q) \
1403 info_ctr.info.info ## lvl1->field1 = value; \
1404 STRING_EQUAL(info_ctr.info.info ## lvl1->field1, value, field1); \
1405 q.in.level = lvl2; \
1406 TESTGETCALL(GetPrinter, q) \
1407 info_ctr.info.info ## lvl2 = (struct spoolss_SetPrinterInfo ## lvl2 *)&q.out.info->info ## lvl2; \
1408 STRING_EQUAL(info_ctr.info.info ## lvl2->field2, value, field2); \
1409 } while (0)
1411 #define TEST_PRINTERINFO_STRING(lvl1, field1, lvl2, field2, value) do { \
1412 TEST_PRINTERINFO_STRING_EXP_ERR(lvl1, field1, lvl2, field2, value, WERR_OK); \
1413 } while (0);
1415 #define TEST_PRINTERINFO_INT_EXP(lvl1, field1, lvl2, field2, value, exp_value) do { \
1416 torture_comment(tctx, "field test %d/%s vs %d/%s\n", lvl1, #field1, lvl2, #field2); \
1417 q.in.level = lvl1; \
1418 TESTGETCALL(GetPrinter, q) \
1419 info_ctr.level = lvl1; \
1420 info_ctr.info.info ## lvl1 = (struct spoolss_SetPrinterInfo ## lvl1 *)&q.out.info->info ## lvl1; \
1421 info_ctr.info.info ## lvl1->field1 = value; \
1422 TESTSETCALL(SetPrinter, s) \
1423 info_ctr.info.info ## lvl1->field1 = 0; \
1424 TESTGETCALL(GetPrinter, q) \
1425 info_ctr.info.info ## lvl1 = (struct spoolss_SetPrinterInfo ## lvl1 *)&q.out.info->info ## lvl1; \
1426 INT_EQUAL(info_ctr.info.info ## lvl1->field1, exp_value, field1); \
1427 q.in.level = lvl2; \
1428 TESTGETCALL(GetPrinter, q) \
1429 info_ctr.info.info ## lvl2 = (struct spoolss_SetPrinterInfo ## lvl2 *)&q.out.info->info ## lvl2; \
1430 INT_EQUAL(info_ctr.info.info ## lvl2->field2, exp_value, field1); \
1431 } while (0)
1433 #define TEST_PRINTERINFO_INT(lvl1, field1, lvl2, field2, value) do { \
1434 TEST_PRINTERINFO_INT_EXP(lvl1, field1, lvl2, field2, value, value); \
1435 } while (0)
1437 q0.in.level = 0;
1438 do { TESTGETCALL(GetPrinter, q0) } while (0);
1440 TEST_PRINTERINFO_STRING(2, comment, 1, comment, "xx2-1 comment");
1441 TEST_PRINTERINFO_STRING(2, comment, 2, comment, "xx2-2 comment");
1443 /* level 0 printername does not stick */
1444 /* TEST_PRINTERINFO_STRING(2, printername, 0, printername, "xx2-0 printer"); */
1445 TEST_PRINTERINFO_STRING(2, printername, 1, name, "xx2-1 printer");
1446 TEST_PRINTERINFO_STRING(2, printername, 2, printername, "xx2-2 printer");
1447 TEST_PRINTERINFO_STRING(2, printername, 4, printername, "xx2-4 printer");
1448 TEST_PRINTERINFO_STRING(2, printername, 5, printername, "xx2-5 printer");
1449 /* TEST_PRINTERINFO_STRING(4, printername, 0, printername, "xx4-0 printer"); */
1450 TEST_PRINTERINFO_STRING(4, printername, 1, name, "xx4-1 printer");
1451 TEST_PRINTERINFO_STRING(4, printername, 2, printername, "xx4-2 printer");
1452 TEST_PRINTERINFO_STRING(4, printername, 4, printername, "xx4-4 printer");
1453 TEST_PRINTERINFO_STRING(4, printername, 5, printername, "xx4-5 printer");
1454 /* TEST_PRINTERINFO_STRING(5, printername, 0, printername, "xx5-0 printer"); */
1455 TEST_PRINTERINFO_STRING(5, printername, 1, name, "xx5-1 printer");
1456 TEST_PRINTERINFO_STRING(5, printername, 2, printername, "xx5-2 printer");
1457 TEST_PRINTERINFO_STRING(5, printername, 4, printername, "xx5-4 printer");
1458 TEST_PRINTERINFO_STRING(5, printername, 5, printername, "xx5-5 printer");
1460 /* servername can be set but does not stick
1461 TEST_PRINTERINFO_STRING(2, servername, 0, servername, "xx2-0 servername");
1462 TEST_PRINTERINFO_STRING(2, servername, 2, servername, "xx2-2 servername");
1463 TEST_PRINTERINFO_STRING(2, servername, 4, servername, "xx2-4 servername");
1466 /* passing an invalid port will result in WERR_UNKNOWN_PORT */
1467 TEST_PRINTERINFO_STRING_EXP_ERR(2, portname, 2, portname, "xx2-2 portname", WERR_UNKNOWN_PORT);
1468 TEST_PRINTERINFO_STRING_EXP_ERR(2, portname, 5, portname, "xx2-5 portname", WERR_UNKNOWN_PORT);
1469 TEST_PRINTERINFO_STRING_EXP_ERR(5, portname, 2, portname, "xx5-2 portname", WERR_UNKNOWN_PORT);
1470 TEST_PRINTERINFO_STRING_EXP_ERR(5, portname, 5, portname, "xx5-5 portname", WERR_UNKNOWN_PORT);
1472 TEST_PRINTERINFO_STRING(2, sharename, 2, sharename, "xx2-2 sharename");
1473 /* passing an invalid driver will result in WERR_UNKNOWN_PRINTER_DRIVER */
1474 TEST_PRINTERINFO_STRING_EXP_ERR(2, drivername, 2, drivername, "xx2-2 drivername", WERR_UNKNOWN_PRINTER_DRIVER);
1475 TEST_PRINTERINFO_STRING(2, location, 2, location, "xx2-2 location");
1476 /* passing an invalid sepfile will result in WERR_INVALID_SEPARATOR_FILE */
1477 TEST_PRINTERINFO_STRING_EXP_ERR(2, sepfile, 2, sepfile, "xx2-2 sepfile", WERR_INVALID_SEPARATOR_FILE);
1478 /* passing an invalid printprocessor will result in WERR_UNKNOWN_PRINTPROCESSOR */
1479 TEST_PRINTERINFO_STRING_EXP_ERR(2, printprocessor, 2, printprocessor, "xx2-2 printprocessor", WERR_UNKNOWN_PRINTPROCESSOR);
1480 TEST_PRINTERINFO_STRING(2, datatype, 2, datatype, "xx2-2 datatype");
1481 TEST_PRINTERINFO_STRING(2, parameters, 2, parameters, "xx2-2 parameters");
1483 for (i=0; i < ARRAY_SIZE(attribute_list); i++) {
1484 /* TEST_PRINTERINFO_INT_EXP(2, attributes, 1, flags,
1485 attribute_list[i],
1486 (attribute_list[i] | default_attribute)
1487 ); */
1488 TEST_PRINTERINFO_INT_EXP(2, attributes, 2, attributes,
1489 attribute_list[i],
1490 (attribute_list[i] | default_attribute)
1492 TEST_PRINTERINFO_INT_EXP(2, attributes, 4, attributes,
1493 attribute_list[i],
1494 (attribute_list[i] | default_attribute)
1496 TEST_PRINTERINFO_INT_EXP(2, attributes, 5, attributes,
1497 attribute_list[i],
1498 (attribute_list[i] | default_attribute)
1500 /* TEST_PRINTERINFO_INT_EXP(4, attributes, 1, flags,
1501 attribute_list[i],
1502 (attribute_list[i] | default_attribute)
1503 ); */
1504 TEST_PRINTERINFO_INT_EXP(4, attributes, 2, attributes,
1505 attribute_list[i],
1506 (attribute_list[i] | default_attribute)
1508 TEST_PRINTERINFO_INT_EXP(4, attributes, 4, attributes,
1509 attribute_list[i],
1510 (attribute_list[i] | default_attribute)
1512 TEST_PRINTERINFO_INT_EXP(4, attributes, 5, attributes,
1513 attribute_list[i],
1514 (attribute_list[i] | default_attribute)
1516 /* TEST_PRINTERINFO_INT_EXP(5, attributes, 1, flags,
1517 attribute_list[i],
1518 (attribute_list[i] | default_attribute)
1519 ); */
1520 TEST_PRINTERINFO_INT_EXP(5, attributes, 2, attributes,
1521 attribute_list[i],
1522 (attribute_list[i] | default_attribute)
1524 TEST_PRINTERINFO_INT_EXP(5, attributes, 4, attributes,
1525 attribute_list[i],
1526 (attribute_list[i] | default_attribute)
1528 TEST_PRINTERINFO_INT_EXP(5, attributes, 5, attributes,
1529 attribute_list[i],
1530 (attribute_list[i] | default_attribute)
1534 for (i=0; i < ARRAY_SIZE(status_list); i++) {
1535 /* level 2 sets do not stick
1536 TEST_PRINTERINFO_INT(2, status, 0, status, status_list[i]);
1537 TEST_PRINTERINFO_INT(2, status, 2, status, status_list[i]);
1538 TEST_PRINTERINFO_INT(2, status, 6, status, status_list[i]); */
1539 TEST_PRINTERINFO_INT(6, status, 0, status, status_list[i]);
1540 TEST_PRINTERINFO_INT(6, status, 2, status, status_list[i]);
1541 TEST_PRINTERINFO_INT(6, status, 6, status, status_list[i]);
1544 /* priorities need to be between 0 and 99
1545 passing an invalid priority will result in WERR_INVALID_PRIORITY */
1546 TEST_PRINTERINFO_INT(2, priority, 2, priority, 0);
1547 TEST_PRINTERINFO_INT(2, priority, 2, priority, 1);
1548 TEST_PRINTERINFO_INT(2, priority, 2, priority, 99);
1549 /* TEST_PRINTERINFO_INT(2, priority, 2, priority, 100); */
1550 TEST_PRINTERINFO_INT(2, defaultpriority,2, defaultpriority, 0);
1551 TEST_PRINTERINFO_INT(2, defaultpriority,2, defaultpriority, 1);
1552 TEST_PRINTERINFO_INT(2, defaultpriority,2, defaultpriority, 99);
1553 /* TEST_PRINTERINFO_INT(2, defaultpriority,2, defaultpriority, 100); */
1555 TEST_PRINTERINFO_INT(2, starttime, 2, starttime, __LINE__);
1556 TEST_PRINTERINFO_INT(2, untiltime, 2, untiltime, __LINE__);
1558 /* does not stick
1559 TEST_PRINTERINFO_INT(2, cjobs, 2, cjobs, __LINE__);
1560 TEST_PRINTERINFO_INT(2, averageppm, 2, averageppm, __LINE__); */
1562 /* does not stick
1563 TEST_PRINTERINFO_INT(5, device_not_selected_timeout, 5, device_not_selected_timeout, __LINE__);
1564 TEST_PRINTERINFO_INT(5, transmission_retry_timeout, 5, transmission_retry_timeout, __LINE__); */
1566 /* FIXME: gd also test devmode and secdesc behavior */
1569 /* verify composition of level 1 description field */
1570 const char *description;
1571 const char *tmp;
1573 q0.in.level = 1;
1574 do { TESTGETCALL(GetPrinter, q0) } while (0);
1576 description = talloc_strdup(tctx, q0.out.info->info1.description);
1578 q0.in.level = 2;
1579 do { TESTGETCALL(GetPrinter, q0) } while (0);
1581 tmp = talloc_asprintf(tctx, "%s,%s,%s",
1582 q0.out.info->info2.printername,
1583 q0.out.info->info2.drivername,
1584 q0.out.info->info2.location);
1586 do { STRING_EQUAL(description, tmp, "description")} while (0);
1589 return ret;
1592 #define torture_assert_sid_equal(torture_ctx,got,expected,cmt)\
1593 do { struct dom_sid *__got = (got), *__expected = (expected); \
1594 if (!dom_sid_equal(__got, __expected)) { \
1595 torture_result(torture_ctx, TORTURE_FAIL, \
1596 __location__": "#got" was %s, expected %s: %s", \
1597 dom_sid_string(torture_ctx, __got), dom_sid_string(torture_ctx, __expected), cmt); \
1598 return false; \
1600 } while(0)
1602 static bool test_security_descriptor_equal(struct torture_context *tctx,
1603 const struct security_descriptor *sd1,
1604 const struct security_descriptor *sd2)
1606 if (sd1 == sd2) {
1607 return true;
1610 if (!sd1 || !sd2) {
1611 torture_comment(tctx, "%s\n", __location__);
1612 return false;
1615 torture_assert_int_equal(tctx, sd1->revision, sd2->revision, "revision mismatch");
1616 torture_assert_int_equal(tctx, sd1->type, sd2->type, "type mismatch");
1618 torture_assert_sid_equal(tctx, sd1->owner_sid, sd2->owner_sid, "owner mismatch");
1619 torture_assert_sid_equal(tctx, sd1->group_sid, sd2->group_sid, "group mismatch");
1621 if (!security_acl_equal(sd1->sacl, sd2->sacl)) {
1622 torture_comment(tctx, "%s: sacl mismatch\n", __location__);
1623 NDR_PRINT_DEBUG(security_acl, sd1->sacl);
1624 NDR_PRINT_DEBUG(security_acl, sd2->sacl);
1625 return false;
1627 if (!security_acl_equal(sd1->dacl, sd2->dacl)) {
1628 torture_comment(tctx, "%s: dacl mismatch\n", __location__);
1629 NDR_PRINT_DEBUG(security_acl, sd1->dacl);
1630 NDR_PRINT_DEBUG(security_acl, sd2->dacl);
1631 return false;
1634 return true;
1637 static bool test_sd_set_level(struct torture_context *tctx,
1638 struct dcerpc_pipe *p,
1639 struct policy_handle *handle,
1640 uint32_t level,
1641 struct security_descriptor *sd)
1643 struct spoolss_SetPrinterInfoCtr info_ctr;
1644 struct spoolss_DevmodeContainer devmode_ctr;
1645 struct sec_desc_buf secdesc_ctr;
1646 union spoolss_SetPrinterInfo sinfo;
1648 ZERO_STRUCT(devmode_ctr);
1649 ZERO_STRUCT(secdesc_ctr);
1651 switch (level) {
1652 case 2: {
1653 union spoolss_PrinterInfo info;
1654 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 2, &info), "");
1655 torture_assert(tctx, PrinterInfo_to_SetPrinterInfo(tctx, &info, 2, &sinfo), "");
1657 info_ctr.level = 2;
1658 info_ctr.info = sinfo;
1660 break;
1662 case 3: {
1663 struct spoolss_SetPrinterInfo3 info3;
1665 info3.sec_desc_ptr = 0;
1667 info_ctr.level = 3;
1668 info_ctr.info.info3 = &info3;
1670 break;
1672 default:
1673 return false;
1676 secdesc_ctr.sd = sd;
1678 torture_assert(tctx,
1679 test_SetPrinter(tctx, p, handle, &info_ctr, &devmode_ctr, &secdesc_ctr, 0), "");
1681 return true;
1684 static bool test_PrinterInfo_SDs(struct torture_context *tctx,
1685 struct dcerpc_pipe *p,
1686 struct policy_handle *handle)
1688 union spoolss_PrinterInfo info;
1689 struct security_descriptor *sd1, *sd2;
1690 int i;
1692 /* just compare level 2 and level 3 */
1694 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 2, &info), "");
1696 sd1 = info.info2.secdesc;
1698 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 3, &info), "");
1700 sd2 = info.info3.secdesc;
1702 torture_assert(tctx, test_security_descriptor_equal(tctx, sd1, sd2),
1703 "SD level 2 != SD level 3");
1706 /* query level 2, set level 2, query level 2 */
1708 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 2, &info), "");
1710 sd1 = info.info2.secdesc;
1712 torture_assert(tctx, test_sd_set_level(tctx, p, handle, 2, sd1), "");
1714 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 2, &info), "");
1716 sd2 = info.info2.secdesc;
1717 if (sd1->type & SEC_DESC_DACL_DEFAULTED) {
1718 torture_comment(tctx, "removing SEC_DESC_DACL_DEFAULTED\n");
1719 sd1->type &= ~SEC_DESC_DACL_DEFAULTED;
1722 torture_assert(tctx, test_security_descriptor_equal(tctx, sd1, sd2),
1723 "SD level 2 != SD level 2 after SD has been set via level 2");
1726 /* query level 2, set level 3, query level 2 */
1728 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 2, &info), "");
1730 sd1 = info.info2.secdesc;
1732 torture_assert(tctx, test_sd_set_level(tctx, p, handle, 3, sd1), "");
1734 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 2, &info), "");
1736 sd2 = info.info2.secdesc;
1738 torture_assert(tctx, test_security_descriptor_equal(tctx, sd1, sd2),
1739 "SD level 2 != SD level 2 after SD has been set via level 3");
1741 /* set modified sd level 3, query level 2 */
1743 for (i=0; i < 93; i++) {
1744 struct security_ace a;
1745 const char *sid_string = talloc_asprintf(tctx, "S-1-5-32-9999%i", i);
1746 a.type = SEC_ACE_TYPE_ACCESS_ALLOWED;
1747 a.flags = 0;
1748 a.size = 0; /* autogenerated */
1749 a.access_mask = 0;
1750 a.trustee = *dom_sid_parse_talloc(tctx, sid_string);
1751 torture_assert_ntstatus_ok(tctx, security_descriptor_dacl_add(sd1, &a), "");
1754 torture_assert(tctx, test_sd_set_level(tctx, p, handle, 3, sd1), "");
1756 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 2, &info), "");
1757 sd2 = info.info2.secdesc;
1759 if (sd1->type & SEC_DESC_DACL_DEFAULTED) {
1760 torture_comment(tctx, "removing SEC_DESC_DACL_DEFAULTED\n");
1761 sd1->type &= ~SEC_DESC_DACL_DEFAULTED;
1764 torture_assert(tctx, test_security_descriptor_equal(tctx, sd1, sd2),
1765 "modified SD level 2 != SD level 2 after SD has been set via level 3");
1768 return true;
1772 * wrapper call that saves original sd, runs tests, and restores sd
1775 static bool test_PrinterInfo_SD(struct torture_context *tctx,
1776 struct dcerpc_pipe *p,
1777 struct policy_handle *handle)
1779 union spoolss_PrinterInfo info;
1780 struct security_descriptor *sd;
1781 bool ret = true;
1783 torture_comment(tctx, "\nTesting Printer Security Descriptors\n");
1785 /* save original sd */
1787 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 2, &info),
1788 "failed to get initial security descriptor");
1790 sd = security_descriptor_copy(tctx, info.info2.secdesc);
1792 /* run tests */
1794 ret = test_PrinterInfo_SDs(tctx, p, handle);
1796 /* restore original sd */
1798 torture_assert(tctx, test_sd_set_level(tctx, p, handle, 3, sd),
1799 "failed to restore initial security descriptor");
1801 torture_comment(tctx, "Printer Security Descriptors test %s\n",
1802 ret ? "succeeded" : "failed");
1805 return ret;
1808 static bool test_devmode_set_level(struct torture_context *tctx,
1809 struct dcerpc_pipe *p,
1810 struct policy_handle *handle,
1811 uint32_t level,
1812 struct spoolss_DeviceMode *devmode)
1814 struct spoolss_SetPrinterInfoCtr info_ctr;
1815 struct spoolss_DevmodeContainer devmode_ctr;
1816 struct sec_desc_buf secdesc_ctr;
1817 union spoolss_SetPrinterInfo sinfo;
1819 ZERO_STRUCT(devmode_ctr);
1820 ZERO_STRUCT(secdesc_ctr);
1822 switch (level) {
1823 case 2: {
1824 union spoolss_PrinterInfo info;
1825 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 2, &info), "");
1826 torture_assert(tctx, PrinterInfo_to_SetPrinterInfo(tctx, &info, 2, &sinfo), "");
1828 info_ctr.level = 2;
1829 info_ctr.info = sinfo;
1831 break;
1833 case 8: {
1834 struct spoolss_SetPrinterInfo8 info8;
1836 info8.devmode_ptr = 0;
1838 info_ctr.level = 8;
1839 info_ctr.info.info8 = &info8;
1841 break;
1843 default:
1844 return false;
1847 devmode_ctr.devmode = devmode;
1849 torture_assert(tctx,
1850 test_SetPrinter(tctx, p, handle, &info_ctr, &devmode_ctr, &secdesc_ctr, 0), "");
1852 return true;
1856 static bool test_devicemode_equal(struct torture_context *tctx,
1857 const struct spoolss_DeviceMode *d1,
1858 const struct spoolss_DeviceMode *d2)
1860 if (d1 == d2) {
1861 return true;
1864 if (!d1 || !d2) {
1865 torture_comment(tctx, "%s\n", __location__);
1866 return false;
1868 torture_assert_str_equal(tctx, d1->devicename, d2->devicename, "devicename mismatch");
1869 torture_assert_int_equal(tctx, d1->specversion, d2->specversion, "specversion mismatch");
1870 torture_assert_int_equal(tctx, d1->driverversion, d2->driverversion, "driverversion mismatch");
1871 torture_assert_int_equal(tctx, d1->size, d2->size, "size mismatch");
1872 torture_assert_int_equal(tctx, d1->__driverextra_length, d2->__driverextra_length, "__driverextra_length mismatch");
1873 torture_assert_int_equal(tctx, d1->fields, d2->fields, "fields mismatch");
1874 torture_assert_int_equal(tctx, d1->orientation, d2->orientation, "orientation mismatch");
1875 torture_assert_int_equal(tctx, d1->papersize, d2->papersize, "papersize mismatch");
1876 torture_assert_int_equal(tctx, d1->paperlength, d2->paperlength, "paperlength mismatch");
1877 torture_assert_int_equal(tctx, d1->paperwidth, d2->paperwidth, "paperwidth mismatch");
1878 torture_assert_int_equal(tctx, d1->scale, d2->scale, "scale mismatch");
1879 torture_assert_int_equal(tctx, d1->copies, d2->copies, "copies mismatch");
1880 torture_assert_int_equal(tctx, d1->defaultsource, d2->defaultsource, "defaultsource mismatch");
1881 torture_assert_int_equal(tctx, d1->printquality, d2->printquality, "printquality mismatch");
1882 torture_assert_int_equal(tctx, d1->color, d2->color, "color mismatch");
1883 torture_assert_int_equal(tctx, d1->duplex, d2->duplex, "duplex mismatch");
1884 torture_assert_int_equal(tctx, d1->yresolution, d2->yresolution, "yresolution mismatch");
1885 torture_assert_int_equal(tctx, d1->ttoption, d2->ttoption, "ttoption mismatch");
1886 torture_assert_int_equal(tctx, d1->collate, d2->collate, "collate mismatch");
1887 torture_assert_str_equal(tctx, d1->formname, d2->formname, "formname mismatch");
1888 torture_assert_int_equal(tctx, d1->logpixels, d2->logpixels, "logpixels mismatch");
1889 torture_assert_int_equal(tctx, d1->bitsperpel, d2->bitsperpel, "bitsperpel mismatch");
1890 torture_assert_int_equal(tctx, d1->pelswidth, d2->pelswidth, "pelswidth mismatch");
1891 torture_assert_int_equal(tctx, d1->pelsheight, d2->pelsheight, "pelsheight mismatch");
1892 torture_assert_int_equal(tctx, d1->displayflags, d2->displayflags, "displayflags mismatch");
1893 torture_assert_int_equal(tctx, d1->displayfrequency, d2->displayfrequency, "displayfrequency mismatch");
1894 torture_assert_int_equal(tctx, d1->icmmethod, d2->icmmethod, "icmmethod mismatch");
1895 torture_assert_int_equal(tctx, d1->icmintent, d2->icmintent, "icmintent mismatch");
1896 torture_assert_int_equal(tctx, d1->mediatype, d2->mediatype, "mediatype mismatch");
1897 torture_assert_int_equal(tctx, d1->dithertype, d2->dithertype, "dithertype mismatch");
1898 torture_assert_int_equal(tctx, d1->reserved1, d2->reserved1, "reserved1 mismatch");
1899 torture_assert_int_equal(tctx, d1->reserved2, d2->reserved2, "reserved2 mismatch");
1900 torture_assert_int_equal(tctx, d1->panningwidth, d2->panningwidth, "panningwidth mismatch");
1901 torture_assert_int_equal(tctx, d1->panningheight, d2->panningheight, "panningheight mismatch");
1902 torture_assert_data_blob_equal(tctx, d1->driverextra_data, d2->driverextra_data, "driverextra_data mismatch");
1904 return true;
1907 static bool test_devicemode_full(struct torture_context *tctx,
1908 struct dcerpc_pipe *p,
1909 struct policy_handle *handle)
1911 struct spoolss_SetPrinter s;
1912 struct spoolss_GetPrinter q;
1913 struct spoolss_GetPrinter q0;
1914 struct spoolss_SetPrinterInfoCtr info_ctr;
1915 struct spoolss_SetPrinterInfo8 info8;
1916 union spoolss_PrinterInfo info;
1917 struct spoolss_DevmodeContainer devmode_ctr;
1918 struct sec_desc_buf secdesc_ctr;
1919 uint32_t needed;
1920 bool ret = true;
1921 NTSTATUS status;
1923 #define TEST_DEVMODE_INT_EXP(lvl1, field1, lvl2, field2, value, exp_value) do { \
1924 torture_comment(tctx, "field test %d/%s vs %d/%s\n", lvl1, #field1, lvl2, #field2); \
1925 q.in.level = lvl1; \
1926 TESTGETCALL(GetPrinter, q) \
1927 info_ctr.level = lvl1; \
1928 if (lvl1 == 2) {\
1929 info_ctr.info.info ## lvl1 = (struct spoolss_SetPrinterInfo ## lvl1 *)&q.out.info->info ## lvl1; \
1930 } else if (lvl1 == 8) {\
1931 info_ctr.info.info ## lvl1 = &info8; \
1933 devmode_ctr.devmode = q.out.info->info ## lvl1.devmode; \
1934 devmode_ctr.devmode->field1 = value; \
1935 TESTSETCALL(SetPrinter, s) \
1936 TESTGETCALL(GetPrinter, q) \
1937 INT_EQUAL(q.out.info->info ## lvl1.devmode->field1, exp_value, field1); \
1938 q.in.level = lvl2; \
1939 TESTGETCALL(GetPrinter, q) \
1940 INT_EQUAL(q.out.info->info ## lvl2.devmode->field2, exp_value, field1); \
1941 } while (0)
1943 #define TEST_DEVMODE_INT(lvl1, field1, lvl2, field2, value) do { \
1944 TEST_DEVMODE_INT_EXP(lvl1, field1, lvl2, field2, value, value); \
1945 } while (0)
1947 ZERO_STRUCT(devmode_ctr);
1948 ZERO_STRUCT(secdesc_ctr);
1949 ZERO_STRUCT(info8);
1951 s.in.handle = handle;
1952 s.in.command = 0;
1953 s.in.info_ctr = &info_ctr;
1954 s.in.devmode_ctr = &devmode_ctr;
1955 s.in.secdesc_ctr = &secdesc_ctr;
1957 q.in.handle = handle;
1958 q.out.info = &info;
1959 q0 = q;
1961 #if 0
1962 const char *devicename;/* [charset(UTF16)] */
1963 enum spoolss_DeviceModeSpecVersion specversion;
1964 uint16_t driverversion;
1965 uint16_t size;
1966 uint16_t __driverextra_length;/* [value(r->driverextra_data.length)] */
1967 uint32_t fields;
1968 #endif
1970 TEST_DEVMODE_INT(8, orientation, 8, orientation, __LINE__);
1971 TEST_DEVMODE_INT(8, papersize, 8, papersize, __LINE__);
1972 TEST_DEVMODE_INT(8, paperlength, 8, paperlength, __LINE__);
1973 TEST_DEVMODE_INT(8, paperwidth, 8, paperwidth, __LINE__);
1974 TEST_DEVMODE_INT(8, scale, 8, scale, __LINE__);
1975 TEST_DEVMODE_INT(8, copies, 8, copies, __LINE__);
1976 TEST_DEVMODE_INT(8, defaultsource, 8, defaultsource, __LINE__);
1977 TEST_DEVMODE_INT(8, printquality, 8, printquality, __LINE__);
1978 TEST_DEVMODE_INT(8, color, 8, color, __LINE__);
1979 TEST_DEVMODE_INT(8, duplex, 8, duplex, __LINE__);
1980 TEST_DEVMODE_INT(8, yresolution, 8, yresolution, __LINE__);
1981 TEST_DEVMODE_INT(8, ttoption, 8, ttoption, __LINE__);
1982 TEST_DEVMODE_INT(8, collate, 8, collate, __LINE__);
1983 #if 0
1984 const char *formname;/* [charset(UTF16)] */
1985 #endif
1986 TEST_DEVMODE_INT(8, logpixels, 8, logpixels, __LINE__);
1987 TEST_DEVMODE_INT(8, bitsperpel, 8, bitsperpel, __LINE__);
1988 TEST_DEVMODE_INT(8, pelswidth, 8, pelswidth, __LINE__);
1989 TEST_DEVMODE_INT(8, pelsheight, 8, pelsheight, __LINE__);
1990 TEST_DEVMODE_INT(8, displayflags, 8, displayflags, __LINE__);
1991 TEST_DEVMODE_INT(8, displayfrequency, 8, displayfrequency, __LINE__);
1992 TEST_DEVMODE_INT(8, icmmethod, 8, icmmethod, __LINE__);
1993 TEST_DEVMODE_INT(8, icmintent, 8, icmintent, __LINE__);
1994 TEST_DEVMODE_INT(8, mediatype, 8, mediatype, __LINE__);
1995 TEST_DEVMODE_INT(8, dithertype, 8, dithertype, __LINE__);
1996 TEST_DEVMODE_INT(8, reserved1, 8, reserved1, __LINE__);
1997 TEST_DEVMODE_INT(8, reserved2, 8, reserved2, __LINE__);
1998 TEST_DEVMODE_INT(8, panningwidth, 8, panningwidth, __LINE__);
1999 TEST_DEVMODE_INT(8, panningheight, 8, panningheight, __LINE__);
2001 return ret;
2004 static bool call_OpenPrinterEx(struct torture_context *tctx,
2005 struct dcerpc_pipe *p,
2006 const char *name,
2007 struct spoolss_DeviceMode *devmode,
2008 struct policy_handle *handle);
2010 static bool test_ClosePrinter(struct torture_context *tctx,
2011 struct dcerpc_pipe *p,
2012 struct policy_handle *handle);
2014 static bool test_PrinterInfo_DevModes(struct torture_context *tctx,
2015 struct dcerpc_pipe *p,
2016 struct policy_handle *handle,
2017 const char *name)
2019 union spoolss_PrinterInfo info;
2020 struct spoolss_DeviceMode *devmode;
2021 struct spoolss_DeviceMode *devmode2;
2022 struct policy_handle handle_devmode;
2024 /* simply compare level8 and level2 devmode */
2026 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 8, &info), "");
2028 devmode = info.info8.devmode;
2030 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 2, &info), "");
2032 devmode2 = info.info2.devmode;
2034 torture_assert(tctx, test_devicemode_equal(tctx, devmode, devmode2),
2035 "DM level 8 != DM level 2");
2038 /* set devicemode level 8 and see if it persists */
2040 devmode->copies = 93;
2041 devmode->formname = talloc_strdup(tctx, "Legal");
2043 torture_assert(tctx, test_devmode_set_level(tctx, p, handle, 8, devmode), "");
2045 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 8, &info), "");
2047 devmode2 = info.info8.devmode;
2049 torture_assert(tctx, test_devicemode_equal(tctx, devmode, devmode2),
2050 "modified DM level 8 != DM level 8 after DM has been set via level 8");
2052 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 2, &info), "");
2054 devmode2 = info.info2.devmode;
2056 torture_assert(tctx, test_devicemode_equal(tctx, devmode, devmode2),
2057 "modified DM level 8 != DM level 2");
2060 /* set devicemode level 2 and see if it persists */
2062 devmode->copies = 39;
2063 devmode->formname = talloc_strdup(tctx, "Executive");
2065 torture_assert(tctx, test_devmode_set_level(tctx, p, handle, 2, devmode), "");
2067 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 8, &info), "");
2069 devmode2 = info.info8.devmode;
2071 torture_assert(tctx, test_devicemode_equal(tctx, devmode, devmode2),
2072 "modified DM level 8 != DM level 8 after DM has been set via level 2");
2074 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 2, &info), "");
2076 devmode2 = info.info2.devmode;
2078 torture_assert(tctx, test_devicemode_equal(tctx, devmode, devmode2),
2079 "modified DM level 8 != DM level 2");
2082 /* check every single bit in public part of devicemode */
2084 torture_assert(tctx, test_devicemode_full(tctx, p, handle),
2085 "failed to set every single devicemode component");
2088 /* change formname upon open and see if it persists in getprinter calls */
2090 devmode->formname = talloc_strdup(tctx, "A4");
2091 devmode->copies = 42;
2093 torture_assert(tctx, call_OpenPrinterEx(tctx, p, name, devmode, &handle_devmode),
2094 "failed to open printer handle");
2096 torture_assert(tctx, test_GetPrinter_level(tctx, p, &handle_devmode, 8, &info), "");
2098 devmode2 = info.info8.devmode;
2100 if (strequal(devmode->devicename, devmode2->devicename)) {
2101 torture_warning(tctx, "devicenames are the same\n");
2102 } else {
2103 torture_comment(tctx, "devicename passed in for open: %s\n", devmode->devicename);
2104 torture_comment(tctx, "devicename after level 8 get: %s\n", devmode2->devicename);
2107 if (strequal(devmode->formname, devmode2->formname)) {
2108 torture_warning(tctx, "formname are the same\n");
2109 } else {
2110 torture_comment(tctx, "formname passed in for open: %s\n", devmode->formname);
2111 torture_comment(tctx, "formname after level 8 get: %s\n", devmode2->formname);
2114 if (devmode->copies == devmode2->copies) {
2115 torture_warning(tctx, "copies are the same\n");
2116 } else {
2117 torture_comment(tctx, "copies passed in for open: %d\n", devmode->copies);
2118 torture_comment(tctx, "copies after level 8 get: %d\n", devmode2->copies);
2121 torture_assert(tctx, test_GetPrinter_level(tctx, p, &handle_devmode, 2, &info), "");
2123 devmode2 = info.info2.devmode;
2125 if (strequal(devmode->devicename, devmode2->devicename)) {
2126 torture_warning(tctx, "devicenames are the same\n");
2127 } else {
2128 torture_comment(tctx, "devicename passed in for open: %s\n", devmode->devicename);
2129 torture_comment(tctx, "devicename after level 2 get: %s\n", devmode2->devicename);
2132 if (strequal(devmode->formname, devmode2->formname)) {
2133 torture_warning(tctx, "formname is the same\n");
2134 } else {
2135 torture_comment(tctx, "formname passed in for open: %s\n", devmode->formname);
2136 torture_comment(tctx, "formname after level 2 get: %s\n", devmode2->formname);
2139 if (devmode->copies == devmode2->copies) {
2140 torture_warning(tctx, "copies are the same\n");
2141 } else {
2142 torture_comment(tctx, "copies passed in for open: %d\n", devmode->copies);
2143 torture_comment(tctx, "copies after level 2 get: %d\n", devmode2->copies);
2146 test_ClosePrinter(tctx, p, &handle_devmode);
2148 return true;
2152 * wrapper call that saves original devmode, runs tests, and restores devmode
2155 static bool test_PrinterInfo_DevMode(struct torture_context *tctx,
2156 struct dcerpc_pipe *p,
2157 struct policy_handle *handle,
2158 const char *name)
2160 union spoolss_PrinterInfo info;
2161 struct spoolss_DeviceMode *devmode;
2162 bool ret = true;
2164 torture_comment(tctx, "\nTesting Printer Devicemodes\n");
2166 /* save original devmode */
2168 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 8, &info),
2169 "failed to get initial global devicemode");
2171 devmode = info.info8.devmode;
2173 /* run tests */
2175 ret = test_PrinterInfo_DevModes(tctx, p, handle, name);
2177 /* restore original devmode */
2179 torture_assert(tctx, test_devmode_set_level(tctx, p, handle, 8, devmode),
2180 "failed to restore initial global device mode");
2182 torture_comment(tctx, "Printer Devicemodes test %s\n",
2183 ret ? "succeeded" : "failed");
2186 return ret;
2189 static bool test_ClosePrinter(struct torture_context *tctx,
2190 struct dcerpc_pipe *p,
2191 struct policy_handle *handle)
2193 NTSTATUS status;
2194 struct spoolss_ClosePrinter r;
2196 r.in.handle = handle;
2197 r.out.handle = handle;
2199 torture_comment(tctx, "Testing ClosePrinter\n");
2201 status = dcerpc_spoolss_ClosePrinter(p, tctx, &r);
2202 torture_assert_ntstatus_ok(tctx, status, "ClosePrinter failed");
2203 torture_assert_werr_ok(tctx, r.out.result, "ClosePrinter failed");
2205 return true;
2208 static bool test_GetForm(struct torture_context *tctx,
2209 struct dcerpc_pipe *p,
2210 struct policy_handle *handle,
2211 const char *form_name,
2212 uint32_t level)
2214 NTSTATUS status;
2215 struct spoolss_GetForm r;
2216 uint32_t needed;
2218 r.in.handle = handle;
2219 r.in.form_name = form_name;
2220 r.in.level = level;
2221 r.in.buffer = NULL;
2222 r.in.offered = 0;
2223 r.out.needed = &needed;
2225 torture_comment(tctx, "Testing GetForm level %d\n", r.in.level);
2227 status = dcerpc_spoolss_GetForm(p, tctx, &r);
2228 torture_assert_ntstatus_ok(tctx, status, "GetForm failed");
2230 if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
2231 DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed);
2232 data_blob_clear(&blob);
2233 r.in.buffer = &blob;
2234 r.in.offered = needed;
2235 status = dcerpc_spoolss_GetForm(p, tctx, &r);
2236 torture_assert_ntstatus_ok(tctx, status, "GetForm failed");
2238 torture_assert_werr_ok(tctx, r.out.result, "GetForm failed");
2240 torture_assert(tctx, r.out.info, "No form info returned");
2243 torture_assert_werr_ok(tctx, r.out.result, "GetForm failed");
2245 CHECK_NEEDED_SIZE_LEVEL(spoolss_FormInfo, r.out.info, r.in.level, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
2247 return true;
2250 static bool test_EnumForms(struct torture_context *tctx,
2251 struct dcerpc_pipe *p,
2252 struct policy_handle *handle, bool print_server)
2254 NTSTATUS status;
2255 struct spoolss_EnumForms r;
2256 bool ret = true;
2257 uint32_t needed;
2258 uint32_t count;
2259 uint32_t levels[] = { 1, 2 };
2260 int i;
2262 for (i=0; i<ARRAY_SIZE(levels); i++) {
2264 union spoolss_FormInfo *info;
2266 r.in.handle = handle;
2267 r.in.level = levels[i];
2268 r.in.buffer = NULL;
2269 r.in.offered = 0;
2270 r.out.needed = &needed;
2271 r.out.count = &count;
2272 r.out.info = &info;
2274 torture_comment(tctx, "Testing EnumForms level %d\n", levels[i]);
2276 status = dcerpc_spoolss_EnumForms(p, tctx, &r);
2277 torture_assert_ntstatus_ok(tctx, status, "EnumForms failed");
2279 if ((r.in.level == 2) && (W_ERROR_EQUAL(r.out.result, WERR_UNKNOWN_LEVEL))) {
2280 break;
2283 if (print_server && W_ERROR_EQUAL(r.out.result, WERR_BADFID))
2284 torture_fail(tctx, "EnumForms on the PrintServer isn't supported by test server (NT4)");
2286 if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
2287 int j;
2288 DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed);
2289 data_blob_clear(&blob);
2290 r.in.buffer = &blob;
2291 r.in.offered = needed;
2293 status = dcerpc_spoolss_EnumForms(p, tctx, &r);
2295 torture_assert(tctx, info, "No forms returned");
2297 for (j = 0; j < count; j++) {
2298 if (!print_server)
2299 ret &= test_GetForm(tctx, p, handle, info[j].info1.form_name, levels[i]);
2303 torture_assert_ntstatus_ok(tctx, status, "EnumForms failed");
2305 torture_assert_werr_ok(tctx, r.out.result, "EnumForms failed");
2307 CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumForms, info, r.in.level, count, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
2310 return true;
2313 static bool test_DeleteForm(struct torture_context *tctx,
2314 struct dcerpc_pipe *p,
2315 struct policy_handle *handle,
2316 const char *form_name)
2318 NTSTATUS status;
2319 struct spoolss_DeleteForm r;
2321 r.in.handle = handle;
2322 r.in.form_name = form_name;
2324 status = dcerpc_spoolss_DeleteForm(p, tctx, &r);
2326 torture_assert_ntstatus_ok(tctx, status, "DeleteForm failed");
2328 torture_assert_werr_ok(tctx, r.out.result, "DeleteForm failed");
2330 return true;
2333 static bool test_AddForm(struct torture_context *tctx,
2334 struct dcerpc_pipe *p,
2335 struct policy_handle *handle, bool print_server)
2337 struct spoolss_AddForm r;
2338 struct spoolss_AddFormInfo1 addform;
2339 const char *form_name = "testform3";
2340 NTSTATUS status;
2341 bool ret = true;
2343 r.in.handle = handle;
2344 r.in.level = 1;
2345 r.in.info.info1 = &addform;
2346 addform.flags = SPOOLSS_FORM_USER;
2347 addform.form_name = form_name;
2348 addform.size.width = 50;
2349 addform.size.height = 25;
2350 addform.area.left = 5;
2351 addform.area.top = 10;
2352 addform.area.right = 45;
2353 addform.area.bottom = 15;
2355 status = dcerpc_spoolss_AddForm(p, tctx, &r);
2357 torture_assert_ntstatus_ok(tctx, status, "AddForm failed");
2359 torture_assert_werr_ok(tctx, r.out.result, "AddForm failed");
2361 if (!print_server) ret &= test_GetForm(tctx, p, handle, form_name, 1);
2364 struct spoolss_SetForm sf;
2365 struct spoolss_AddFormInfo1 setform;
2367 sf.in.handle = handle;
2368 sf.in.form_name = form_name;
2369 sf.in.level = 1;
2370 sf.in.info.info1= &setform;
2371 setform.flags = addform.flags;
2372 setform.form_name = addform.form_name;
2373 setform.size = addform.size;
2374 setform.area = addform.area;
2376 setform.size.width = 1234;
2378 status = dcerpc_spoolss_SetForm(p, tctx, &sf);
2380 torture_assert_ntstatus_ok(tctx, status, "SetForm failed");
2382 torture_assert_werr_ok(tctx, r.out.result, "SetForm failed");
2385 if (!print_server) ret &= test_GetForm(tctx, p, handle, form_name, 1);
2388 struct spoolss_EnumForms e;
2389 union spoolss_FormInfo *info;
2390 uint32_t needed;
2391 uint32_t count;
2392 bool found = false;
2394 e.in.handle = handle;
2395 e.in.level = 1;
2396 e.in.buffer = NULL;
2397 e.in.offered = 0;
2398 e.out.needed = &needed;
2399 e.out.count = &count;
2400 e.out.info = &info;
2402 torture_comment(tctx, "Testing EnumForms level 1\n");
2404 status = dcerpc_spoolss_EnumForms(p, tctx, &e);
2405 torture_assert_ntstatus_ok(tctx, status, "EnumForms failed");
2407 if (print_server && W_ERROR_EQUAL(e.out.result, WERR_BADFID))
2408 torture_fail(tctx, "EnumForms on the PrintServer isn't supported by test server (NT4)");
2410 if (W_ERROR_EQUAL(e.out.result, WERR_INSUFFICIENT_BUFFER)) {
2411 int j;
2412 DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed);
2413 data_blob_clear(&blob);
2414 e.in.buffer = &blob;
2415 e.in.offered = needed;
2417 status = dcerpc_spoolss_EnumForms(p, tctx, &e);
2419 torture_assert(tctx, info, "No forms returned");
2421 for (j = 0; j < count; j++) {
2422 if (strequal(form_name, info[j].info1.form_name)) {
2423 found = true;
2424 break;
2428 torture_assert(tctx, found, "Newly added form not found in enum call");
2431 if (!test_DeleteForm(tctx, p, handle, form_name)) {
2432 ret = false;
2435 return ret;
2438 static bool test_EnumPorts_old(struct torture_context *tctx,
2439 struct dcerpc_pipe *p)
2441 NTSTATUS status;
2442 struct spoolss_EnumPorts r;
2443 uint32_t needed;
2444 uint32_t count;
2445 union spoolss_PortInfo *info;
2447 r.in.servername = talloc_asprintf(tctx, "\\\\%s",
2448 dcerpc_server_name(p));
2449 r.in.level = 2;
2450 r.in.buffer = NULL;
2451 r.in.offered = 0;
2452 r.out.needed = &needed;
2453 r.out.count = &count;
2454 r.out.info = &info;
2456 torture_comment(tctx, "Testing EnumPorts\n");
2458 status = dcerpc_spoolss_EnumPorts(p, tctx, &r);
2460 torture_assert_ntstatus_ok(tctx, status, "EnumPorts failed");
2462 if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
2463 DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed);
2464 data_blob_clear(&blob);
2465 r.in.buffer = &blob;
2466 r.in.offered = needed;
2468 status = dcerpc_spoolss_EnumPorts(p, tctx, &r);
2469 torture_assert_ntstatus_ok(tctx, status, "EnumPorts failed");
2470 torture_assert_werr_ok(tctx, r.out.result, "EnumPorts failed");
2472 torture_assert(tctx, info, "No ports returned");
2475 torture_assert_werr_ok(tctx, r.out.result, "EnumPorts failed");
2477 CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumPorts, info, 2, count, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
2479 return true;
2482 static bool test_AddPort(struct torture_context *tctx,
2483 struct dcerpc_pipe *p)
2485 NTSTATUS status;
2486 struct spoolss_AddPort r;
2488 r.in.server_name = talloc_asprintf(tctx, "\\\\%s",
2489 dcerpc_server_name(p));
2490 r.in.unknown = 0;
2491 r.in.monitor_name = "foo";
2493 torture_comment(tctx, "Testing AddPort\n");
2495 status = dcerpc_spoolss_AddPort(p, tctx, &r);
2497 torture_assert_ntstatus_ok(tctx, status, "AddPort failed");
2499 /* win2k3 returns WERR_NOT_SUPPORTED */
2501 #if 0
2503 if (!W_ERROR_IS_OK(r.out.result)) {
2504 printf("AddPort failed - %s\n", win_errstr(r.out.result));
2505 return false;
2508 #endif
2510 return true;
2513 static bool test_GetJob(struct torture_context *tctx,
2514 struct dcerpc_pipe *p,
2515 struct policy_handle *handle, uint32_t job_id)
2517 NTSTATUS status;
2518 struct spoolss_GetJob r;
2519 union spoolss_JobInfo info;
2520 uint32_t needed;
2521 uint32_t levels[] = {1, 2 /* 3, 4 */};
2522 uint32_t i;
2524 r.in.handle = handle;
2525 r.in.job_id = job_id;
2526 r.in.level = 0;
2527 r.in.buffer = NULL;
2528 r.in.offered = 0;
2529 r.out.needed = &needed;
2530 r.out.info = &info;
2532 torture_comment(tctx, "Testing GetJob level %d\n", r.in.level);
2534 status = dcerpc_spoolss_GetJob(p, tctx, &r);
2535 torture_assert_werr_equal(tctx, r.out.result, WERR_UNKNOWN_LEVEL, "Unexpected return code");
2537 for (i = 0; i < ARRAY_SIZE(levels); i++) {
2539 torture_comment(tctx, "Testing GetJob level %d\n", r.in.level);
2541 needed = 0;
2543 r.in.level = levels[i];
2544 r.in.offered = 0;
2545 r.in.buffer = NULL;
2547 status = dcerpc_spoolss_GetJob(p, tctx, &r);
2548 torture_assert_ntstatus_ok(tctx, status, "GetJob failed");
2550 if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
2551 DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed);
2552 data_blob_clear(&blob);
2553 r.in.buffer = &blob;
2554 r.in.offered = needed;
2556 status = dcerpc_spoolss_GetJob(p, tctx, &r);
2557 torture_assert_ntstatus_ok(tctx, status, "GetJob failed");
2560 torture_assert(tctx, r.out.info, "No job info returned");
2561 torture_assert_werr_ok(tctx, r.out.result, "GetJob failed");
2563 CHECK_NEEDED_SIZE_LEVEL(spoolss_JobInfo, r.out.info, r.in.level, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
2566 return true;
2569 static bool test_SetJob(struct torture_context *tctx,
2570 struct dcerpc_pipe *p,
2571 struct policy_handle *handle, uint32_t job_id,
2572 enum spoolss_JobControl command)
2574 NTSTATUS status;
2575 struct spoolss_SetJob r;
2577 r.in.handle = handle;
2578 r.in.job_id = job_id;
2579 r.in.ctr = NULL;
2580 r.in.command = command;
2582 switch (command) {
2583 case SPOOLSS_JOB_CONTROL_PAUSE:
2584 torture_comment(tctx, "Testing SetJob: SPOOLSS_JOB_CONTROL_PAUSE\n");
2585 break;
2586 case SPOOLSS_JOB_CONTROL_RESUME:
2587 torture_comment(tctx, "Testing SetJob: SPOOLSS_JOB_CONTROL_RESUME\n");
2588 break;
2589 case SPOOLSS_JOB_CONTROL_CANCEL:
2590 torture_comment(tctx, "Testing SetJob: SPOOLSS_JOB_CONTROL_CANCEL\n");
2591 break;
2592 case SPOOLSS_JOB_CONTROL_RESTART:
2593 torture_comment(tctx, "Testing SetJob: SPOOLSS_JOB_CONTROL_RESTART\n");
2594 break;
2595 case SPOOLSS_JOB_CONTROL_DELETE:
2596 torture_comment(tctx, "Testing SetJob: SPOOLSS_JOB_CONTROL_DELETE\n");
2597 break;
2598 case SPOOLSS_JOB_CONTROL_SEND_TO_PRINTER:
2599 torture_comment(tctx, "Testing SetJob: SPOOLSS_JOB_CONTROL_SEND_TO_PRINTER\n");
2600 break;
2601 case SPOOLSS_JOB_CONTROL_LAST_PAGE_EJECTED:
2602 torture_comment(tctx, "Testing SetJob: SPOOLSS_JOB_CONTROL_LAST_PAGE_EJECTED\n");
2603 break;
2604 case SPOOLSS_JOB_CONTROL_RETAIN:
2605 torture_comment(tctx, "Testing SetJob: SPOOLSS_JOB_CONTROL_RETAIN\n");
2606 break;
2607 case SPOOLSS_JOB_CONTROL_RELEASE:
2608 torture_comment(tctx, "Testing SetJob: SPOOLSS_JOB_CONTROL_RELEASE\n");
2609 break;
2610 default:
2611 torture_comment(tctx, "Testing SetJob\n");
2612 break;
2615 status = dcerpc_spoolss_SetJob(p, tctx, &r);
2616 torture_assert_ntstatus_ok(tctx, status, "SetJob failed");
2617 torture_assert_werr_ok(tctx, r.out.result, "SetJob failed");
2619 return true;
2622 static bool test_AddJob(struct torture_context *tctx,
2623 struct dcerpc_pipe *p,
2624 struct policy_handle *handle)
2626 NTSTATUS status;
2627 struct spoolss_AddJob r;
2628 uint32_t needed;
2630 r.in.level = 0;
2631 r.in.handle = handle;
2632 r.in.offered = 0;
2633 r.out.needed = &needed;
2634 r.in.buffer = r.out.buffer = NULL;
2636 torture_comment(tctx, "Testing AddJob\n");
2638 status = dcerpc_spoolss_AddJob(p, tctx, &r);
2639 torture_assert_werr_equal(tctx, r.out.result, WERR_UNKNOWN_LEVEL, "AddJob failed");
2641 r.in.level = 1;
2643 status = dcerpc_spoolss_AddJob(p, tctx, &r);
2644 torture_assert_werr_equal(tctx, r.out.result, WERR_INVALID_PARAM, "AddJob failed");
2646 return true;
2650 static bool test_EnumJobs(struct torture_context *tctx,
2651 struct dcerpc_pipe *p,
2652 struct policy_handle *handle)
2654 NTSTATUS status;
2655 struct spoolss_EnumJobs r;
2656 uint32_t needed;
2657 uint32_t count;
2658 union spoolss_JobInfo *info;
2660 r.in.handle = handle;
2661 r.in.firstjob = 0;
2662 r.in.numjobs = 0xffffffff;
2663 r.in.level = 1;
2664 r.in.buffer = NULL;
2665 r.in.offered = 0;
2666 r.out.needed = &needed;
2667 r.out.count = &count;
2668 r.out.info = &info;
2670 torture_comment(tctx, "Testing EnumJobs\n");
2672 status = dcerpc_spoolss_EnumJobs(p, tctx, &r);
2674 torture_assert_ntstatus_ok(tctx, status, "EnumJobs failed");
2676 if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
2677 int j;
2678 DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed);
2679 data_blob_clear(&blob);
2680 r.in.buffer = &blob;
2681 r.in.offered = needed;
2683 status = dcerpc_spoolss_EnumJobs(p, tctx, &r);
2685 torture_assert_ntstatus_ok(tctx, status, "EnumJobs failed");
2686 torture_assert_werr_ok(tctx, r.out.result, "EnumJobs failed");
2687 torture_assert(tctx, info, "No jobs returned");
2689 CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumJobs, *r.out.info, r.in.level, count, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
2691 for (j = 0; j < count; j++) {
2693 torture_assert(tctx, test_GetJob(tctx, p, handle, info[j].info1.job_id),
2694 "failed to call test_GetJob");
2696 /* FIXME - gd */
2697 if (!torture_setting_bool(tctx, "samba3", false)) {
2698 test_SetJob(tctx, p, handle, info[j].info1.job_id, SPOOLSS_JOB_CONTROL_PAUSE);
2699 test_SetJob(tctx, p, handle, info[j].info1.job_id, SPOOLSS_JOB_CONTROL_RESUME);
2703 } else {
2704 torture_assert_werr_ok(tctx, r.out.result, "EnumJobs failed");
2707 return true;
2710 static bool test_DoPrintTest(struct torture_context *tctx,
2711 struct dcerpc_pipe *p,
2712 struct policy_handle *handle)
2714 bool ret = true;
2715 NTSTATUS status;
2716 struct spoolss_StartDocPrinter s;
2717 struct spoolss_DocumentInfo1 info1;
2718 struct spoolss_StartPagePrinter sp;
2719 struct spoolss_WritePrinter w;
2720 struct spoolss_EndPagePrinter ep;
2721 struct spoolss_EndDocPrinter e;
2722 int i;
2723 uint32_t job_id;
2724 uint32_t num_written;
2726 torture_comment(tctx, "Testing StartDocPrinter\n");
2728 s.in.handle = handle;
2729 s.in.level = 1;
2730 s.in.info.info1 = &info1;
2731 s.out.job_id = &job_id;
2732 info1.document_name = "TorturePrintJob";
2733 info1.output_file = NULL;
2734 info1.datatype = "RAW";
2736 status = dcerpc_spoolss_StartDocPrinter(p, tctx, &s);
2737 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_StartDocPrinter failed");
2738 torture_assert_werr_ok(tctx, s.out.result, "StartDocPrinter failed");
2740 for (i=1; i < 4; i++) {
2741 torture_comment(tctx, "Testing StartPagePrinter: Page[%d]\n", i);
2743 sp.in.handle = handle;
2745 status = dcerpc_spoolss_StartPagePrinter(p, tctx, &sp);
2746 torture_assert_ntstatus_ok(tctx, status,
2747 "dcerpc_spoolss_StartPagePrinter failed");
2748 torture_assert_werr_ok(tctx, sp.out.result, "StartPagePrinter failed");
2750 torture_comment(tctx, "Testing WritePrinter: Page[%d]\n", i);
2752 w.in.handle = handle;
2753 w.in.data = data_blob_string_const(talloc_asprintf(tctx,"TortureTestPage: %d\nData\n",i));
2754 w.out.num_written = &num_written;
2756 status = dcerpc_spoolss_WritePrinter(p, tctx, &w);
2757 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_WritePrinter failed");
2758 torture_assert_werr_ok(tctx, w.out.result, "WritePrinter failed");
2760 torture_comment(tctx, "Testing EndPagePrinter: Page[%d]\n", i);
2762 ep.in.handle = handle;
2764 status = dcerpc_spoolss_EndPagePrinter(p, tctx, &ep);
2765 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EndPagePrinter failed");
2766 torture_assert_werr_ok(tctx, ep.out.result, "EndPagePrinter failed");
2769 torture_comment(tctx, "Testing EndDocPrinter\n");
2771 e.in.handle = handle;
2773 status = dcerpc_spoolss_EndDocPrinter(p, tctx, &e);
2774 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EndDocPrinter failed");
2775 torture_assert_werr_ok(tctx, e.out.result, "EndDocPrinter failed");
2777 ret &= test_AddJob(tctx, p, handle);
2778 ret &= test_EnumJobs(tctx, p, handle);
2780 ret &= test_SetJob(tctx, p, handle, job_id, SPOOLSS_JOB_CONTROL_DELETE);
2782 return ret;
2785 static bool test_PausePrinter(struct torture_context *tctx,
2786 struct dcerpc_pipe *p,
2787 struct policy_handle *handle)
2789 NTSTATUS status;
2790 struct spoolss_SetPrinter r;
2791 struct spoolss_SetPrinterInfoCtr info_ctr;
2792 struct spoolss_DevmodeContainer devmode_ctr;
2793 struct sec_desc_buf secdesc_ctr;
2795 info_ctr.level = 0;
2796 info_ctr.info.info0 = NULL;
2798 ZERO_STRUCT(devmode_ctr);
2799 ZERO_STRUCT(secdesc_ctr);
2801 r.in.handle = handle;
2802 r.in.info_ctr = &info_ctr;
2803 r.in.devmode_ctr = &devmode_ctr;
2804 r.in.secdesc_ctr = &secdesc_ctr;
2805 r.in.command = SPOOLSS_PRINTER_CONTROL_PAUSE;
2807 torture_comment(tctx, "Testing SetPrinter: SPOOLSS_PRINTER_CONTROL_PAUSE\n");
2809 status = dcerpc_spoolss_SetPrinter(p, tctx, &r);
2811 torture_assert_ntstatus_ok(tctx, status, "SetPrinter failed");
2813 torture_assert_werr_ok(tctx, r.out.result, "SetPrinter failed");
2815 return true;
2818 static bool test_ResumePrinter(struct torture_context *tctx,
2819 struct dcerpc_pipe *p,
2820 struct policy_handle *handle)
2822 NTSTATUS status;
2823 struct spoolss_SetPrinter r;
2824 struct spoolss_SetPrinterInfoCtr info_ctr;
2825 struct spoolss_DevmodeContainer devmode_ctr;
2826 struct sec_desc_buf secdesc_ctr;
2828 info_ctr.level = 0;
2829 info_ctr.info.info0 = NULL;
2831 ZERO_STRUCT(devmode_ctr);
2832 ZERO_STRUCT(secdesc_ctr);
2834 r.in.handle = handle;
2835 r.in.info_ctr = &info_ctr;
2836 r.in.devmode_ctr = &devmode_ctr;
2837 r.in.secdesc_ctr = &secdesc_ctr;
2838 r.in.command = SPOOLSS_PRINTER_CONTROL_RESUME;
2840 torture_comment(tctx, "Testing SetPrinter: SPOOLSS_PRINTER_CONTROL_RESUME\n");
2842 status = dcerpc_spoolss_SetPrinter(p, tctx, &r);
2844 torture_assert_ntstatus_ok(tctx, status, "SetPrinter failed");
2846 torture_assert_werr_ok(tctx, r.out.result, "SetPrinter failed");
2848 return true;
2851 static bool test_GetPrinterData(struct torture_context *tctx,
2852 struct dcerpc_pipe *p,
2853 struct policy_handle *handle,
2854 const char *value_name,
2855 enum winreg_Type *type_p,
2856 uint8_t **data_p,
2857 uint32_t *needed_p)
2859 NTSTATUS status;
2860 struct spoolss_GetPrinterData r;
2861 uint32_t needed;
2862 enum winreg_Type type;
2863 union spoolss_PrinterData data;
2865 r.in.handle = handle;
2866 r.in.value_name = value_name;
2867 r.in.offered = 0;
2868 r.out.needed = &needed;
2869 r.out.type = &type;
2870 r.out.data = talloc_zero_array(tctx, uint8_t, r.in.offered);
2872 torture_comment(tctx, "Testing GetPrinterData(%s)\n", r.in.value_name);
2874 status = dcerpc_spoolss_GetPrinterData(p, tctx, &r);
2875 torture_assert_ntstatus_ok(tctx, status, "GetPrinterData failed");
2877 if (W_ERROR_EQUAL(r.out.result, WERR_MORE_DATA)) {
2878 r.in.offered = needed;
2879 r.out.data = talloc_zero_array(tctx, uint8_t, r.in.offered);
2880 status = dcerpc_spoolss_GetPrinterData(p, tctx, &r);
2881 torture_assert_ntstatus_ok(tctx, status, "GetPrinterData failed");
2884 torture_assert_werr_ok(tctx, r.out.result,
2885 talloc_asprintf(tctx, "GetPrinterData(%s) failed", r.in.value_name));
2887 CHECK_NEEDED_SIZE_LEVEL(spoolss_PrinterData, &data, type, lp_iconv_convenience(tctx->lp_ctx), needed, 1);
2889 if (type_p) {
2890 *type_p = type;
2893 if (data_p) {
2894 *data_p = r.out.data;
2897 if (needed_p) {
2898 *needed_p = needed;
2901 return true;
2904 static bool test_GetPrinterDataEx(struct torture_context *tctx,
2905 struct dcerpc_pipe *p,
2906 struct policy_handle *handle,
2907 const char *key_name,
2908 const char *value_name,
2909 enum winreg_Type *type_p,
2910 uint8_t **data_p,
2911 uint32_t *needed_p)
2913 NTSTATUS status;
2914 struct spoolss_GetPrinterDataEx r;
2915 enum winreg_Type type;
2916 uint32_t needed;
2917 union spoolss_PrinterData data;
2919 r.in.handle = handle;
2920 r.in.key_name = key_name;
2921 r.in.value_name = value_name;
2922 r.in.offered = 0;
2923 r.out.type = &type;
2924 r.out.needed = &needed;
2925 r.out.data = talloc_zero_array(tctx, uint8_t, r.in.offered);
2927 torture_comment(tctx, "Testing GetPrinterDataEx(%s - %s)\n",
2928 r.in.key_name, r.in.value_name);
2930 status = dcerpc_spoolss_GetPrinterDataEx(p, tctx, &r);
2931 if (!NT_STATUS_IS_OK(status)) {
2932 if (NT_STATUS_EQUAL(status,NT_STATUS_NET_WRITE_FAULT) &&
2933 p->last_fault_code == DCERPC_FAULT_OP_RNG_ERROR) {
2934 torture_skip(tctx, "GetPrinterDataEx not supported by server\n");
2936 torture_assert_ntstatus_ok(tctx, status, "GetPrinterDataEx failed");
2939 if (W_ERROR_EQUAL(r.out.result, WERR_MORE_DATA)) {
2940 r.in.offered = needed;
2941 r.out.data = talloc_zero_array(tctx, uint8_t, r.in.offered);
2942 status = dcerpc_spoolss_GetPrinterDataEx(p, tctx, &r);
2943 torture_assert_ntstatus_ok(tctx, status, "GetPrinterDataEx failed");
2946 torture_assert_werr_ok(tctx, r.out.result,
2947 talloc_asprintf(tctx, "GetPrinterDataEx(%s - %s) failed", r.in.key_name, r.in.value_name));
2949 CHECK_NEEDED_SIZE_LEVEL(spoolss_PrinterData, &data, type, lp_iconv_convenience(tctx->lp_ctx), needed, 1);
2951 if (type_p) {
2952 *type_p = type;
2955 if (data_p) {
2956 *data_p = r.out.data;
2959 if (needed_p) {
2960 *needed_p = needed;
2963 return true;
2966 static bool test_GetPrinterData_list(struct torture_context *tctx,
2967 struct dcerpc_pipe *p,
2968 struct policy_handle *handle,
2969 const char **architecture)
2971 const char *list[] = {
2972 "W3SvcInstalled",
2973 "BeepEnabled",
2974 "EventLog",
2975 /* "NetPopup", not on w2k8 */
2976 /* "NetPopupToComputer", not on w2k8 */
2977 "MajorVersion",
2978 "MinorVersion",
2979 "DefaultSpoolDirectory",
2980 "Architecture",
2981 "DsPresent",
2982 "OSVersion",
2983 /* "OSVersionEx", not on s3 */
2984 "DNSMachineName"
2986 int i;
2988 for (i=0; i < ARRAY_SIZE(list); i++) {
2989 enum winreg_Type type, type_ex;
2990 uint8_t *data, *data_ex;
2991 uint32_t needed, needed_ex;
2993 torture_assert(tctx, test_GetPrinterData(tctx, p, handle, list[i], &type, &data, &needed),
2994 talloc_asprintf(tctx, "GetPrinterData failed on %s\n", list[i]));
2995 torture_assert(tctx, test_GetPrinterDataEx(tctx, p, handle, "random_string", list[i], &type_ex, &data_ex, &needed_ex),
2996 talloc_asprintf(tctx, "GetPrinterDataEx failed on %s\n", list[i]));
2997 torture_assert_int_equal(tctx, type, type_ex, "type mismatch");
2998 torture_assert_int_equal(tctx, needed, needed_ex, "needed mismatch");
2999 torture_assert_mem_equal(tctx, data, data_ex, needed, "data mismatch");
3001 if (strequal(list[i], "Architecture")) {
3002 if (architecture) {
3003 DATA_BLOB blob = data_blob_const(data, needed);
3004 *architecture = reg_val_data_string(tctx, lp_iconv_convenience(tctx->lp_ctx), REG_SZ, blob);
3009 return true;
3012 static bool test_EnumPrinterData(struct torture_context *tctx,
3013 struct dcerpc_pipe *p,
3014 struct policy_handle *handle,
3015 uint32_t enum_index,
3016 uint32_t value_offered,
3017 uint32_t data_offered,
3018 enum winreg_Type *type_p,
3019 uint32_t *value_needed_p,
3020 uint32_t *data_needed_p,
3021 const char **value_name_p,
3022 uint8_t **data_p,
3023 WERROR *result_p)
3025 struct spoolss_EnumPrinterData r;
3026 uint32_t data_needed;
3027 uint32_t value_needed;
3028 enum winreg_Type type;
3030 r.in.handle = handle;
3031 r.in.enum_index = enum_index;
3032 r.in.value_offered = value_offered;
3033 r.in.data_offered = data_offered;
3034 r.out.data_needed = &data_needed;
3035 r.out.value_needed = &value_needed;
3036 r.out.type = &type;
3037 r.out.data = talloc_zero_array(tctx, uint8_t, r.in.data_offered);
3038 r.out.value_name = talloc_zero_array(tctx, const char, r.in.value_offered);
3040 torture_comment(tctx, "Testing EnumPrinterData(%d)\n", enum_index);
3042 torture_assert_ntstatus_ok(tctx,
3043 dcerpc_spoolss_EnumPrinterData(p, tctx, &r),
3044 "EnumPrinterData failed");
3046 if (type_p) {
3047 *type_p = type;
3049 if (value_needed_p) {
3050 *value_needed_p = value_needed;
3052 if (data_needed_p) {
3053 *data_needed_p = data_needed;
3055 if (value_name_p) {
3056 *value_name_p = r.out.value_name;
3058 if (data_p) {
3059 *data_p = r.out.data;
3061 if (result_p) {
3062 *result_p = r.out.result;
3065 return true;
3069 static bool test_EnumPrinterData_all(struct torture_context *tctx,
3070 struct dcerpc_pipe *p,
3071 struct policy_handle *handle)
3073 uint32_t enum_index = 0;
3074 enum winreg_Type type;
3075 uint32_t value_needed;
3076 uint32_t data_needed;
3077 uint8_t *data;
3078 const char *value_name;
3079 WERROR result;
3081 do {
3082 torture_assert(tctx,
3083 test_EnumPrinterData(tctx, p, handle, enum_index, 0, 0,
3084 &type, &value_needed, &data_needed,
3085 &value_name, &data, &result),
3086 "EnumPrinterData failed");
3088 if (W_ERROR_EQUAL(result, WERR_NO_MORE_ITEMS)) {
3089 break;
3092 torture_assert(tctx,
3093 test_EnumPrinterData(tctx, p, handle, enum_index, value_needed, data_needed,
3094 &type, &value_needed, &data_needed,
3095 &value_name, &data, &result),
3096 "EnumPrinterData failed");
3098 if (W_ERROR_EQUAL(result, WERR_NO_MORE_ITEMS)) {
3099 break;
3102 enum_index++;
3104 } while (W_ERROR_IS_OK(result));
3106 return true;
3109 static bool test_EnumPrinterDataEx(struct torture_context *tctx,
3110 struct dcerpc_pipe *p,
3111 struct policy_handle *handle,
3112 const char *key_name,
3113 uint32_t *count_p,
3114 struct spoolss_PrinterEnumValues **info_p)
3116 struct spoolss_EnumPrinterDataEx r;
3117 struct spoolss_PrinterEnumValues *info;
3118 uint32_t needed;
3119 uint32_t count;
3121 r.in.handle = handle;
3122 r.in.key_name = key_name;
3123 r.in.offered = 0;
3124 r.out.needed = &needed;
3125 r.out.count = &count;
3126 r.out.info = &info;
3128 torture_comment(tctx, "Testing EnumPrinterDataEx(%s)\n", key_name);
3130 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_EnumPrinterDataEx(p, tctx, &r),
3131 "EnumPrinterDataEx failed");
3132 if (W_ERROR_EQUAL(r.out.result, WERR_MORE_DATA)) {
3133 r.in.offered = needed;
3134 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_EnumPrinterDataEx(p, tctx, &r),
3135 "EnumPrinterDataEx failed");
3138 torture_assert_werr_ok(tctx, r.out.result, "EnumPrinterDataEx failed");
3140 CHECK_NEEDED_SIZE_ENUM(spoolss_EnumPrinterDataEx, info, count, lp_iconv_convenience(tctx->lp_ctx), needed, 1);
3142 if (count_p) {
3143 *count_p = count;
3145 if (info_p) {
3146 *info_p = info;
3149 return true;
3152 static bool test_SetPrinterData(struct torture_context *tctx,
3153 struct dcerpc_pipe *p,
3154 struct policy_handle *handle,
3155 const char *value_name,
3156 enum winreg_Type type,
3157 uint8_t *data,
3158 uint32_t offered);
3159 static bool test_DeletePrinterData(struct torture_context *tctx,
3160 struct dcerpc_pipe *p,
3161 struct policy_handle *handle,
3162 const char *value_name);
3164 static bool test_EnumPrinterData_consistency(struct torture_context *tctx,
3165 struct dcerpc_pipe *p,
3166 struct policy_handle *handle)
3168 uint32_t count;
3169 struct spoolss_PrinterEnumValues *info;
3170 int i;
3171 uint32_t value_needed, data_needed;
3172 uint32_t value_offered, data_offered;
3173 WERROR result;
3175 enum winreg_Type type;
3176 DATA_BLOB blob;
3178 torture_comment(tctx, "Testing EnumPrinterData vs EnumPrinterDataEx consistency\n");
3180 torture_assert(tctx,
3181 reg_string_to_val(tctx, lp_iconv_convenience(tctx->lp_ctx),
3182 "REG_SZ", "torture_data1", &type, &blob), "");
3184 torture_assert(tctx,
3185 test_SetPrinterData(tctx, p, handle, "torture_value1", type, blob.data, blob.length),
3186 "SetPrinterData failed");
3188 blob = data_blob_string_const("torture_data2");
3190 torture_assert(tctx,
3191 test_SetPrinterData(tctx, p, handle, "torture_value2", REG_BINARY, blob.data, blob.length),
3192 "SetPrinterData failed");
3194 blob = data_blob_talloc(tctx, NULL, 4);
3195 SIVAL(blob.data, 0, 0x11223344);
3197 torture_assert(tctx,
3198 test_SetPrinterData(tctx, p, handle, "torture_value3", type, blob.data, blob.length),
3199 "SetPrinterData failed");
3201 torture_assert(tctx,
3202 test_EnumPrinterDataEx(tctx, p, handle, "PrinterDriverData", &count, &info),
3203 "failed to call EnumPrinterDataEx");
3205 /* get the max sizes for value and data */
3207 torture_assert(tctx,
3208 test_EnumPrinterData(tctx, p, handle, 0, 0, 0,
3209 NULL, &value_needed, &data_needed,
3210 NULL, NULL, &result),
3211 "EnumPrinterData failed");
3212 torture_assert_werr_ok(tctx, result, "unexpected result");
3214 /* check if the reply from the EnumPrinterData really matches max values */
3216 for (i=0; i < count; i++) {
3217 if (info[i].value_name_len > value_needed) {
3218 torture_fail(tctx,
3219 talloc_asprintf(tctx,
3220 "EnumPrinterDataEx gave a reply with value length %d which is larger then expected max value length %d from EnumPrinterData",
3221 info[i].value_name_len, value_needed));
3223 if (info[i].data_length > data_needed) {
3224 torture_fail(tctx,
3225 talloc_asprintf(tctx,
3226 "EnumPrinterDataEx gave a reply with data length %d which is larger then expected max data length %d from EnumPrinterData",
3227 info[i].data_length, data_needed));
3231 /* assuming that both EnumPrinterData and EnumPrinterDataEx do either
3232 * sort or not sort the replies by value name, we should be able to do
3233 * the following entry comparison */
3235 data_offered = data_needed;
3236 value_offered = value_needed;
3238 for (i=0; i < count; i++) {
3240 enum winreg_Type type;
3241 const char *value_name;
3242 uint8_t *data;
3244 torture_assert(tctx,
3245 test_EnumPrinterData(tctx, p, handle, i, value_offered, data_offered,
3246 &type, &value_needed, &data_needed,
3247 &value_name, &data, &result),
3248 "EnumPrinterData failed");
3250 if (i -1 == count) {
3251 torture_assert_werr_equal(tctx, result, WERR_NO_MORE_ITEMS,
3252 "unexpected result");
3253 break;
3254 } else {
3255 torture_assert_werr_ok(tctx, result, "unexpected result");
3258 torture_assert_int_equal(tctx, type, info[i].type, "type mismatch");
3259 torture_assert_int_equal(tctx, value_needed, info[i].value_name_len, "value name length mismatch");
3260 torture_assert_str_equal(tctx, value_name, info[i].value_name, "value name mismatch");
3261 torture_assert_int_equal(tctx, data_needed, info[i].data_length, "data length mismatch");
3262 torture_assert_mem_equal(tctx, data, info[i].data->data, info[i].data_length, "data mismatch");
3265 torture_assert(tctx,
3266 test_DeletePrinterData(tctx, p, handle, "torture_value1"),
3267 "DeletePrinterData failed");
3268 torture_assert(tctx,
3269 test_DeletePrinterData(tctx, p, handle, "torture_value2"),
3270 "DeletePrinterData failed");
3271 torture_assert(tctx,
3272 test_DeletePrinterData(tctx, p, handle, "torture_value3"),
3273 "DeletePrinterData failed");
3275 torture_comment(tctx, "EnumPrinterData vs EnumPrinterDataEx consistency test succeeded\n\n");
3277 return true;
3280 static bool test_DeletePrinterData(struct torture_context *tctx,
3281 struct dcerpc_pipe *p,
3282 struct policy_handle *handle,
3283 const char *value_name)
3285 NTSTATUS status;
3286 struct spoolss_DeletePrinterData r;
3288 r.in.handle = handle;
3289 r.in.value_name = value_name;
3291 torture_comment(tctx, "Testing DeletePrinterData(%s)\n",
3292 r.in.value_name);
3294 status = dcerpc_spoolss_DeletePrinterData(p, tctx, &r);
3296 torture_assert_ntstatus_ok(tctx, status, "DeletePrinterData failed");
3297 torture_assert_werr_ok(tctx, r.out.result, "DeletePrinterData failed");
3299 return true;
3302 static bool test_DeletePrinterDataEx(struct torture_context *tctx,
3303 struct dcerpc_pipe *p,
3304 struct policy_handle *handle,
3305 const char *key_name,
3306 const char *value_name)
3308 struct spoolss_DeletePrinterDataEx r;
3310 r.in.handle = handle;
3311 r.in.key_name = key_name;
3312 r.in.value_name = value_name;
3314 torture_comment(tctx, "Testing DeletePrinterDataEx(%s - %s)\n",
3315 r.in.key_name, r.in.value_name);
3317 torture_assert_ntstatus_ok(tctx,
3318 dcerpc_spoolss_DeletePrinterDataEx(p, tctx, &r),
3319 "DeletePrinterDataEx failed");
3320 torture_assert_werr_ok(tctx, r.out.result,
3321 "DeletePrinterDataEx failed");
3323 return true;
3326 static bool test_DeletePrinterKey(struct torture_context *tctx,
3327 struct dcerpc_pipe *p,
3328 struct policy_handle *handle,
3329 const char *key_name)
3331 struct spoolss_DeletePrinterKey r;
3333 r.in.handle = handle;
3334 r.in.key_name = key_name;
3336 torture_comment(tctx, "Testing DeletePrinterKey(%s)\n", r.in.key_name);
3338 if (strequal(key_name, "") && !torture_setting_bool(tctx, "dangerous", false)) {
3339 torture_skip(tctx, "not wiping out printer registry - enable dangerous tests to use\n");
3340 return true;
3343 torture_assert_ntstatus_ok(tctx,
3344 dcerpc_spoolss_DeletePrinterKey(p, tctx, &r),
3345 "DeletePrinterKey failed");
3346 torture_assert_werr_ok(tctx, r.out.result,
3347 "DeletePrinterKey failed");
3349 return true;
3352 static bool test_winreg_OpenHKLM(struct torture_context *tctx,
3353 struct dcerpc_pipe *p,
3354 struct policy_handle *handle)
3356 struct winreg_OpenHKLM r;
3358 r.in.system_name = NULL;
3359 r.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
3360 r.out.handle = handle;
3362 torture_comment(tctx, "Testing winreg_OpenHKLM\n");
3364 torture_assert_ntstatus_ok(tctx, dcerpc_winreg_OpenHKLM(p, tctx, &r), "OpenHKLM failed");
3365 torture_assert_werr_ok(tctx, r.out.result, "OpenHKLM failed");
3367 return true;
3370 static void init_winreg_String(struct winreg_String *name, const char *s)
3372 name->name = s;
3373 if (s) {
3374 name->name_len = 2 * (strlen_m(s) + 1);
3375 name->name_size = name->name_len;
3376 } else {
3377 name->name_len = 0;
3378 name->name_size = 0;
3382 static bool test_winreg_OpenKey(struct torture_context *tctx,
3383 struct dcerpc_pipe *p,
3384 struct policy_handle *hive_handle,
3385 const char *keyname,
3386 struct policy_handle *key_handle)
3388 struct winreg_OpenKey r;
3390 r.in.parent_handle = hive_handle;
3391 init_winreg_String(&r.in.keyname, keyname);
3392 r.in.options = REG_KEYTYPE_NON_VOLATILE;
3393 r.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
3394 r.out.handle = key_handle;
3396 torture_comment(tctx, "Testing winreg_OpenKey(%s)\n", keyname);
3398 torture_assert_ntstatus_ok(tctx, dcerpc_winreg_OpenKey(p, tctx, &r), "OpenKey failed");
3399 torture_assert_werr_ok(tctx, r.out.result, "OpenKey failed");
3401 return true;
3404 static bool test_winreg_CloseKey(struct torture_context *tctx,
3405 struct dcerpc_pipe *p,
3406 struct policy_handle *handle)
3408 struct winreg_CloseKey r;
3410 r.in.handle = handle;
3411 r.out.handle = handle;
3413 torture_comment(tctx, "Testing winreg_CloseKey\n");
3415 torture_assert_ntstatus_ok(tctx, dcerpc_winreg_CloseKey(p, tctx, &r), "CloseKey failed");
3416 torture_assert_werr_ok(tctx, r.out.result, "CloseKey failed");
3418 return true;
3421 bool test_winreg_QueryValue(struct torture_context *tctx,
3422 struct dcerpc_pipe *p,
3423 struct policy_handle *handle,
3424 const char *value_name,
3425 enum winreg_Type *type_p,
3426 uint32_t *data_size_p,
3427 uint32_t *data_length_p,
3428 uint8_t **data_p)
3430 struct winreg_QueryValue r;
3431 enum winreg_Type type = REG_NONE;
3432 uint32_t data_size = 0;
3433 uint32_t data_length = 0;
3434 struct winreg_String valuename;
3435 uint8_t *data = NULL;
3437 init_winreg_String(&valuename, value_name);
3439 data = talloc_zero_array(tctx, uint8_t, 0);
3441 r.in.handle = handle;
3442 r.in.value_name = &valuename;
3443 r.in.type = &type;
3444 r.in.data_size = &data_size;
3445 r.in.data_length = &data_length;
3446 r.in.data = data;
3447 r.out.type = &type;
3448 r.out.data = data;
3449 r.out.data_size = &data_size;
3450 r.out.data_length = &data_length;
3452 torture_comment(tctx, "Testing winreg_QueryValue(%s)\n", value_name);
3454 torture_assert_ntstatus_ok(tctx, dcerpc_winreg_QueryValue(p, tctx, &r), "QueryValue failed");
3455 if (W_ERROR_EQUAL(r.out.result, WERR_MORE_DATA)) {
3456 *r.in.data_size = *r.out.data_size;
3457 data = talloc_zero_array(tctx, uint8_t, *r.in.data_size);
3458 r.in.data = data;
3459 r.out.data = data;
3460 torture_assert_ntstatus_ok(tctx, dcerpc_winreg_QueryValue(p, tctx, &r), "QueryValue failed");
3462 torture_assert_werr_ok(tctx, r.out.result, "QueryValue failed");
3464 if (type_p) {
3465 *type_p = *r.out.type;
3467 if (data_size_p) {
3468 *data_size_p = *r.out.data_size;
3470 if (data_length_p) {
3471 *data_length_p = *r.out.data_length;
3473 if (data_p) {
3474 *data_p = r.out.data;
3477 return true;
3480 static bool test_winreg_query_printerdata(struct torture_context *tctx,
3481 struct dcerpc_pipe *p,
3482 struct policy_handle *handle,
3483 const char *printer_name,
3484 const char *key_name,
3485 const char *value_name,
3486 enum winreg_Type *w_type,
3487 uint32_t *w_size,
3488 uint32_t *w_length,
3489 uint8_t **w_data)
3491 const char *printer_key;
3492 struct policy_handle key_handle;
3494 printer_key = talloc_asprintf(tctx, "%s\\%s\\%s",
3495 TOP_LEVEL_PRINTER_KEY, printer_name, key_name);
3497 torture_assert(tctx,
3498 test_winreg_OpenKey(tctx, p, handle, printer_key, &key_handle), "");
3500 torture_assert(tctx,
3501 test_winreg_QueryValue(tctx, p, &key_handle, value_name, w_type, w_size, w_length, w_data), "");
3503 torture_assert(tctx,
3504 test_winreg_CloseKey(tctx, p, &key_handle), "");
3506 return true;
3509 static bool test_SetPrinterData(struct torture_context *tctx,
3510 struct dcerpc_pipe *p,
3511 struct policy_handle *handle,
3512 const char *value_name,
3513 enum winreg_Type type,
3514 uint8_t *data,
3515 uint32_t offered)
3517 struct spoolss_SetPrinterData r;
3519 r.in.handle = handle;
3520 r.in.value_name = value_name;
3521 r.in.type = type;
3522 r.in.data = data;
3523 r.in.offered = offered;
3525 torture_comment(tctx, "Testing SetPrinterData(%s)\n",
3526 r.in.value_name);
3528 torture_assert_ntstatus_ok(tctx,
3529 dcerpc_spoolss_SetPrinterData(p, tctx, &r),
3530 "SetPrinterData failed");
3531 torture_assert_werr_ok(tctx, r.out.result,
3532 "SetPrinterData failed");
3534 return true;
3537 static bool test_SetPrinterData_matrix(struct torture_context *tctx,
3538 struct dcerpc_pipe *p,
3539 struct policy_handle *handle,
3540 const char *printer_name,
3541 struct dcerpc_pipe *winreg_pipe,
3542 struct policy_handle *hive_handle)
3544 const char *values[] = {
3545 "spootyfoot",
3546 "spooty\\foot",
3547 #if 0
3548 /* FIXME: not working with s3 atm. */
3549 "spooty,foot",
3550 "spooty,fo,ot",
3551 #endif
3552 "spooty foot",
3553 #if 0
3554 /* FIXME: not working with s3 atm. */
3555 "spooty\\fo,ot",
3556 "spooty,fo\\ot"
3557 #endif
3559 int i;
3561 for (i=0; i < ARRAY_SIZE(values); i++) {
3563 enum winreg_Type type;
3564 DATA_BLOB blob;
3565 uint8_t *data;
3566 uint32_t needed;
3568 torture_assert(tctx,
3569 reg_string_to_val(tctx, lp_iconv_convenience(tctx->lp_ctx),
3570 "REG_SZ", "dog", &type, &blob), "");
3572 torture_assert(tctx,
3573 test_SetPrinterData(tctx, p, handle, values[i], REG_SZ, blob.data, blob.length),
3574 "SetPrinterData failed");
3576 torture_assert(tctx,
3577 test_GetPrinterData(tctx, p, handle, values[i], &type, &data, &needed),
3578 "GetPrinterData failed");
3580 torture_assert_int_equal(tctx, type, REG_SZ, "type mismatch");
3581 torture_assert_int_equal(tctx, needed, blob.length, "size mismatch");
3582 torture_assert_mem_equal(tctx, data, blob.data, blob.length, "buffer mismatch");
3584 if (winreg_pipe && hive_handle) {
3586 enum winreg_Type w_type;
3587 uint32_t w_size;
3588 uint32_t w_length;
3589 uint8_t *w_data;
3591 torture_assert(tctx,
3592 test_winreg_query_printerdata(tctx, winreg_pipe, hive_handle,
3593 printer_name, "PrinterDriverData", values[i],
3594 &w_type, &w_size, &w_length, &w_data), "");
3596 torture_assert_int_equal(tctx, w_type, REG_SZ, "winreg type mismatch");
3597 torture_assert_int_equal(tctx, w_size, blob.length, "winreg size mismatch");
3598 torture_assert_int_equal(tctx, w_length, blob.length, "winreg length mismatch");
3599 torture_assert_mem_equal(tctx, w_data, blob.data, blob.length, "winreg buffer mismatch");
3602 torture_assert(tctx,
3603 test_DeletePrinterData(tctx, p, handle, values[i]),
3604 "DeletePrinterData failed");
3607 return true;
3611 static bool test_EnumPrinterKey(struct torture_context *tctx,
3612 struct dcerpc_pipe *p,
3613 struct policy_handle *handle,
3614 const char *key_name,
3615 const char ***array);
3617 static bool test_SetPrinterDataEx(struct torture_context *tctx,
3618 struct dcerpc_pipe *p,
3619 struct policy_handle *handle,
3620 const char *key_name,
3621 const char *value_name,
3622 enum winreg_Type type,
3623 uint8_t *data,
3624 uint32_t offered)
3626 NTSTATUS status;
3627 struct spoolss_SetPrinterDataEx r;
3629 r.in.handle = handle;
3630 r.in.key_name = key_name;
3631 r.in.value_name = value_name;
3632 r.in.type = type;
3633 r.in.data = data;
3634 r.in.offered = offered;
3636 torture_comment(tctx, "Testing SetPrinterDataEx(%s - %s) type: %s, offered: 0x%08x\n",
3637 r.in.key_name, r.in.value_name, str_regtype(r.in.type), r.in.offered);
3639 status = dcerpc_spoolss_SetPrinterDataEx(p, tctx, &r);
3641 torture_assert_ntstatus_ok(tctx, status, "SetPrinterDataEx failed");
3642 torture_assert_werr_ok(tctx, r.out.result, "SetPrinterDataEx failed");
3644 return true;
3647 static bool test_SetPrinterDataEx_matrix(struct torture_context *tctx,
3648 struct dcerpc_pipe *p,
3649 struct policy_handle *handle,
3650 const char *printername,
3651 struct dcerpc_pipe *winreg_pipe,
3652 struct policy_handle *hive_handle)
3654 const char *value_name = "dog";
3655 const char *keys[] = {
3656 "torturedataex",
3657 "torture data ex",
3658 #if 0
3659 /* FIXME: not working with s3 atm. */
3660 "torturedataex_with_subkey\\subkey",
3661 "torturedataex_with_subkey\\subkey:0",
3662 "torturedataex_with_subkey\\subkey:1",
3663 "torturedataex_with_subkey\\subkey\\subsubkey",
3664 "torturedataex_with_subkey\\subkey\\subsubkey:0",
3665 "torturedataex_with_subkey\\subkey\\subsubkey:1",
3666 #endif
3667 "torture,data",
3668 #if 0
3669 /* FIXME: not working with s3 atm. */
3671 "torture,data,ex",
3672 "torture,data\\ex",
3673 "torture\\data,ex"
3674 #endif
3676 enum winreg_Type types[] = {
3677 REG_SZ,
3678 REG_DWORD,
3679 REG_BINARY
3681 const char *str = "abcdefghijklmnopqrstuvwxzy";
3682 int i, t, s;
3685 for (i=0; i < ARRAY_SIZE(keys); i++) {
3686 for (t=0; t < ARRAY_SIZE(types); t++) {
3687 for (s=0; s < strlen(str); s++) {
3689 char *c;
3690 const char *key;
3691 enum winreg_Type type;
3692 const char *string = talloc_strndup(tctx, str, s);
3693 DATA_BLOB blob = data_blob_string_const(string);
3694 const char **subkeys;
3695 DATA_BLOB data;
3696 uint8_t *data_out;
3697 uint32_t needed, offered = 0;
3698 uint32_t ecount;
3699 struct spoolss_PrinterEnumValues *einfo;
3701 switch (types[t]) {
3702 case REG_BINARY:
3703 case REG_DWORD:
3704 data = blob;
3705 offered = blob.length;
3706 break;
3707 case REG_SZ:
3708 torture_assert(tctx,
3709 reg_string_to_val(tctx, lp_iconv_convenience(tctx->lp_ctx),
3710 "REG_SZ", string, &type, &data), "");
3711 offered = data.length;
3712 /*strlen_m_term(data.string)*2;*/
3713 break;
3714 default:
3715 torture_fail(tctx, talloc_asprintf(tctx, "type %d untested\n", types[t]));
3718 torture_assert(tctx,
3719 test_SetPrinterDataEx(tctx, p, handle, keys[i], value_name, types[t], data.data, offered),
3720 "failed to call SetPrinterDataEx");
3722 torture_assert(tctx,
3723 test_GetPrinterDataEx(tctx, p, handle, keys[i], value_name, &type, &data_out, &needed),
3724 "failed to call GetPrinterDataEx");
3726 torture_assert(tctx,
3727 test_EnumPrinterDataEx(tctx, p, handle, keys[i], &ecount, &einfo),
3728 "failed to call EnumPrinterDataEx");
3730 torture_assert_int_equal(tctx, types[t], type, "type mismatch");
3731 torture_assert_int_equal(tctx, needed, offered, "size mismatch");
3732 torture_assert_mem_equal(tctx, data_out, data.data, offered, "buffer mismatch");
3734 torture_assert_int_equal(tctx, ecount, 1, "unexpected enum count");
3735 torture_assert_str_equal(tctx, einfo[0].value_name, value_name, "value_name mismatch");
3736 torture_assert_int_equal(tctx, einfo[0].value_name_len, strlen_m_term(value_name)*2, "unexpected value_name_len");
3737 torture_assert_int_equal(tctx, einfo[0].type, types[t], "type mismatch");
3738 torture_assert_int_equal(tctx, einfo[0].data_length, offered, "size mismatch");
3739 if (einfo[0].data_length > 0) {
3740 torture_assert_mem_equal(tctx, einfo[0].data->data, data.data, offered, "buffer mismatch");
3743 if (winreg_pipe && hive_handle) {
3745 enum winreg_Type w_type;
3746 uint32_t w_size;
3747 uint32_t w_length;
3748 uint8_t *w_data;
3750 torture_assert(tctx,
3751 test_winreg_query_printerdata(tctx, winreg_pipe, hive_handle,
3752 printername, keys[i], value_name,
3753 &w_type, &w_size, &w_length, &w_data), "");
3755 torture_assert_int_equal(tctx, w_type, types[t], "winreg type mismatch");
3756 torture_assert_int_equal(tctx, w_size, offered, "winreg size mismatch");
3757 torture_assert_int_equal(tctx, w_length, offered, "winreg length mismatch");
3758 torture_assert_mem_equal(tctx, w_data, data.data, offered, "winreg buffer mismatch");
3761 key = talloc_strdup(tctx, keys[i]);
3763 if (!test_DeletePrinterDataEx(tctx, p, handle, keys[i], value_name)) {
3764 return false;
3767 c = strchr(key, '\\');
3768 if (c) {
3769 int k;
3771 /* we have subkeys */
3773 *c = 0;
3775 if (!test_EnumPrinterKey(tctx, p, handle, key, &subkeys)) {
3776 return false;
3779 for (k=0; subkeys && subkeys[k]; k++) {
3781 const char *current_key = talloc_asprintf(tctx, "%s\\%s", key, subkeys[k]);
3783 if (!test_DeletePrinterKey(tctx, p, handle, current_key)) {
3784 return false;
3788 if (!test_DeletePrinterKey(tctx, p, handle, key)) {
3789 return false;
3792 } else {
3793 if (!test_DeletePrinterKey(tctx, p, handle, key)) {
3794 return false;
3801 return true;
3804 static bool test_PrinterData_winreg(struct torture_context *tctx,
3805 struct dcerpc_pipe *p,
3806 struct policy_handle *handle,
3807 const char *printer_name)
3809 struct dcerpc_pipe *p2;
3810 bool ret = true;
3811 struct policy_handle hive_handle;
3813 torture_assert_ntstatus_ok(tctx,
3814 torture_rpc_connection(tctx, &p2, &ndr_table_winreg),
3815 "could not open winreg pipe");
3817 torture_assert(tctx, test_winreg_OpenHKLM(tctx, p2, &hive_handle), "");
3819 ret &= test_SetPrinterData_matrix(tctx, p, handle, printer_name, p2, &hive_handle);
3820 ret &= test_SetPrinterDataEx_matrix(tctx, p, handle, printer_name, p2, &hive_handle);
3822 test_winreg_CloseKey(tctx, p2, &hive_handle);
3824 talloc_free(p2);
3826 return ret;
3829 static bool test_GetChangeID_PrinterData(struct torture_context *tctx,
3830 struct dcerpc_pipe *p,
3831 struct policy_handle *handle,
3832 uint32_t *change_id)
3834 enum winreg_Type type;
3835 uint8_t *data;
3836 uint32_t needed;
3838 torture_assert(tctx,
3839 test_GetPrinterData(tctx, p, handle, "ChangeID", &type, &data, &needed),
3840 "failed to call GetPrinterData");
3842 torture_assert(tctx, type == REG_DWORD, "unexpected type");
3843 torture_assert_int_equal(tctx, needed, 4, "unexpected size");
3845 *change_id = IVAL(data, 0);
3847 return true;
3850 static bool test_GetChangeID_PrinterDataEx(struct torture_context *tctx,
3851 struct dcerpc_pipe *p,
3852 struct policy_handle *handle,
3853 uint32_t *change_id)
3855 enum winreg_Type type;
3856 uint8_t *data;
3857 uint32_t needed;
3859 torture_assert(tctx,
3860 test_GetPrinterDataEx(tctx, p, handle, "PrinterDriverData", "ChangeID", &type, &data, &needed),
3861 "failed to call GetPrinterData");
3863 torture_assert(tctx, type == REG_DWORD, "unexpected type");
3864 torture_assert_int_equal(tctx, needed, 4, "unexpected size");
3866 *change_id = IVAL(data, 0);
3868 return true;
3871 static bool test_GetChangeID_PrinterInfo(struct torture_context *tctx,
3872 struct dcerpc_pipe *p,
3873 struct policy_handle *handle,
3874 uint32_t *change_id)
3876 union spoolss_PrinterInfo info;
3878 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 0, &info),
3879 "failed to query Printer level 0");
3881 *change_id = info.info0.change_id;
3883 return true;
3886 static bool test_ChangeID(struct torture_context *tctx,
3887 struct dcerpc_pipe *p,
3888 struct policy_handle *handle)
3890 uint32_t change_id, change_id_ex, change_id_info;
3891 uint32_t change_id2, change_id_ex2, change_id_info2;
3892 union spoolss_PrinterInfo info;
3893 const char *comment;
3896 torture_comment(tctx, "Testing ChangeID: id change test #1\n");
3898 torture_assert(tctx, test_GetChangeID_PrinterData(tctx, p, handle, &change_id),
3899 "failed to query for ChangeID");
3900 torture_assert(tctx, test_GetChangeID_PrinterDataEx(tctx, p, handle, &change_id_ex),
3901 "failed to query for ChangeID");
3902 torture_assert(tctx, test_GetChangeID_PrinterInfo(tctx, p, handle, &change_id_info),
3903 "failed to query for ChangeID");
3905 torture_assert_int_equal(tctx, change_id, change_id_ex,
3906 "change_ids should all be equal");
3907 torture_assert_int_equal(tctx, change_id_ex, change_id_info,
3908 "change_ids should all be equal");
3911 torture_comment(tctx, "Testing ChangeID: id change test #2\n");
3913 torture_assert(tctx, test_GetChangeID_PrinterData(tctx, p, handle, &change_id),
3914 "failed to query for ChangeID");
3915 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 2, &info),
3916 "failed to query Printer level 2");
3917 torture_assert(tctx, test_GetChangeID_PrinterDataEx(tctx, p, handle, &change_id_ex),
3918 "failed to query for ChangeID");
3919 torture_assert(tctx, test_GetChangeID_PrinterInfo(tctx, p, handle, &change_id_info),
3920 "failed to query for ChangeID");
3921 torture_assert_int_equal(tctx, change_id, change_id_ex,
3922 "change_id should not have changed");
3923 torture_assert_int_equal(tctx, change_id_ex, change_id_info,
3924 "change_id should not have changed");
3927 torture_comment(tctx, "Testing ChangeID: id change test #3\n");
3929 torture_assert(tctx, test_GetChangeID_PrinterData(tctx, p, handle, &change_id),
3930 "failed to query for ChangeID");
3931 torture_assert(tctx, test_GetChangeID_PrinterDataEx(tctx, p, handle, &change_id_ex),
3932 "failed to query for ChangeID");
3933 torture_assert(tctx, test_GetChangeID_PrinterInfo(tctx, p, handle, &change_id_info),
3934 "failed to query for ChangeID");
3935 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 2, &info),
3936 "failed to query Printer level 2");
3937 comment = talloc_strdup(tctx, info.info2.comment);
3940 struct spoolss_SetPrinterInfoCtr info_ctr;
3941 struct spoolss_DevmodeContainer devmode_ctr;
3942 struct sec_desc_buf secdesc_ctr;
3943 union spoolss_SetPrinterInfo sinfo;
3945 ZERO_STRUCT(info_ctr);
3946 ZERO_STRUCT(devmode_ctr);
3947 ZERO_STRUCT(secdesc_ctr);
3950 torture_assert(tctx, PrinterInfo_to_SetPrinterInfo(tctx, &info, 2, &sinfo), "");
3951 sinfo.info2->comment = "torture_comment";
3953 info_ctr.level = 2;
3954 info_ctr.info = sinfo;
3956 torture_assert(tctx, test_SetPrinter(tctx, p, handle, &info_ctr, &devmode_ctr, &secdesc_ctr, 0),
3957 "failed to call SetPrinter");
3959 sinfo.info2->comment = comment;
3961 torture_assert(tctx, test_SetPrinter(tctx, p, handle, &info_ctr, &devmode_ctr, &secdesc_ctr, 0),
3962 "failed to call SetPrinter");
3966 torture_assert(tctx, test_GetChangeID_PrinterData(tctx, p, handle, &change_id2),
3967 "failed to query for ChangeID");
3968 torture_assert(tctx, test_GetChangeID_PrinterDataEx(tctx, p, handle, &change_id_ex2),
3969 "failed to query for ChangeID");
3970 torture_assert(tctx, test_GetChangeID_PrinterInfo(tctx, p, handle, &change_id_info2),
3971 "failed to query for ChangeID");
3973 torture_assert_int_equal(tctx, change_id2, change_id_ex2,
3974 "change_ids should all be equal");
3975 torture_assert_int_equal(tctx, change_id_ex2, change_id_info2,
3976 "change_ids should all be equal");
3978 torture_assert(tctx, (change_id < change_id2),
3979 talloc_asprintf(tctx, "change_id %d needs to be larger than change_id %d",
3980 change_id2, change_id));
3981 torture_assert(tctx, (change_id_ex < change_id_ex2),
3982 talloc_asprintf(tctx, "change_id %d needs to be larger than change_id %d",
3983 change_id_ex2, change_id_ex));
3984 torture_assert(tctx, (change_id_info < change_id_info2),
3985 talloc_asprintf(tctx, "change_id %d needs to be larger than change_id %d",
3986 change_id_info2, change_id_info));
3988 return true;
3991 static bool test_SecondaryClosePrinter(struct torture_context *tctx,
3992 struct dcerpc_pipe *p,
3993 struct policy_handle *handle)
3995 NTSTATUS status;
3996 struct dcerpc_binding *b;
3997 struct dcerpc_pipe *p2;
3998 struct spoolss_ClosePrinter cp;
4000 /* only makes sense on SMB */
4001 if (p->conn->transport.transport != NCACN_NP) {
4002 return true;
4005 torture_comment(tctx, "testing close on secondary pipe\n");
4007 status = dcerpc_parse_binding(tctx, p->conn->binding_string, &b);
4008 torture_assert_ntstatus_ok(tctx, status, "Failed to parse dcerpc binding");
4010 status = dcerpc_secondary_connection(p, &p2, b);
4011 torture_assert_ntstatus_ok(tctx, status, "Failed to create secondary connection");
4013 status = dcerpc_bind_auth_none(p2, &ndr_table_spoolss);
4014 torture_assert_ntstatus_ok(tctx, status, "Failed to create bind on secondary connection");
4016 cp.in.handle = handle;
4017 cp.out.handle = handle;
4019 status = dcerpc_spoolss_ClosePrinter(p2, tctx, &cp);
4020 torture_assert_ntstatus_equal(tctx, status, NT_STATUS_NET_WRITE_FAULT,
4021 "ERROR: Allowed close on secondary connection");
4023 torture_assert_int_equal(tctx, p2->last_fault_code, DCERPC_FAULT_CONTEXT_MISMATCH,
4024 "Unexpected fault code");
4026 talloc_free(p2);
4028 return true;
4031 static bool test_OpenPrinter_badname(struct torture_context *tctx,
4032 struct dcerpc_pipe *p, const char *name)
4034 NTSTATUS status;
4035 struct spoolss_OpenPrinter op;
4036 struct spoolss_OpenPrinterEx opEx;
4037 struct policy_handle handle;
4038 bool ret = true;
4040 op.in.printername = name;
4041 op.in.datatype = NULL;
4042 op.in.devmode_ctr.devmode= NULL;
4043 op.in.access_mask = 0;
4044 op.out.handle = &handle;
4046 torture_comment(tctx, "Testing OpenPrinter(%s) with bad name\n", op.in.printername);
4048 status = dcerpc_spoolss_OpenPrinter(p, tctx, &op);
4049 torture_assert_ntstatus_ok(tctx, status, "OpenPrinter failed");
4050 if (!W_ERROR_EQUAL(WERR_INVALID_PRINTER_NAME,op.out.result)) {
4051 torture_comment(tctx, "OpenPrinter(%s) unexpected result[%s] should be WERR_INVALID_PRINTER_NAME\n",
4052 name, win_errstr(op.out.result));
4055 if (W_ERROR_IS_OK(op.out.result)) {
4056 ret &=test_ClosePrinter(tctx, p, &handle);
4059 opEx.in.printername = name;
4060 opEx.in.datatype = NULL;
4061 opEx.in.devmode_ctr.devmode = NULL;
4062 opEx.in.access_mask = 0;
4063 opEx.in.level = 1;
4064 opEx.in.userlevel.level1 = NULL;
4065 opEx.out.handle = &handle;
4067 torture_comment(tctx, "Testing OpenPrinterEx(%s) with bad name\n", opEx.in.printername);
4069 status = dcerpc_spoolss_OpenPrinterEx(p, tctx, &opEx);
4070 torture_assert_ntstatus_ok(tctx, status, "OpenPrinterEx failed");
4071 if (!W_ERROR_EQUAL(WERR_INVALID_PARAM,opEx.out.result)) {
4072 torture_comment(tctx, "OpenPrinterEx(%s) unexpected result[%s] should be WERR_INVALID_PARAM\n",
4073 name, win_errstr(opEx.out.result));
4076 if (W_ERROR_IS_OK(opEx.out.result)) {
4077 ret &=test_ClosePrinter(tctx, p, &handle);
4080 return ret;
4083 static bool test_OpenPrinter(struct torture_context *tctx,
4084 struct dcerpc_pipe *p,
4085 const char *name,
4086 const char *environment)
4088 NTSTATUS status;
4089 struct spoolss_OpenPrinter r;
4090 struct policy_handle handle;
4091 bool ret = true;
4093 r.in.printername = talloc_asprintf(tctx, "\\\\%s\\%s", dcerpc_server_name(p), name);
4094 r.in.datatype = NULL;
4095 r.in.devmode_ctr.devmode= NULL;
4096 r.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
4097 r.out.handle = &handle;
4099 torture_comment(tctx, "Testing OpenPrinter(%s)\n", r.in.printername);
4101 status = dcerpc_spoolss_OpenPrinter(p, tctx, &r);
4103 torture_assert_ntstatus_ok(tctx, status, "OpenPrinter failed");
4105 torture_assert_werr_ok(tctx, r.out.result, "OpenPrinter failed");
4107 if (!test_GetPrinter(tctx, p, &handle, environment)) {
4108 ret = false;
4111 if (!torture_setting_bool(tctx, "samba3", false)) {
4112 if (!test_SecondaryClosePrinter(tctx, p, &handle)) {
4113 ret = false;
4117 if (!test_ClosePrinter(tctx, p, &handle)) {
4118 ret = false;
4121 return ret;
4124 static bool call_OpenPrinterEx(struct torture_context *tctx,
4125 struct dcerpc_pipe *p,
4126 const char *name,
4127 struct spoolss_DeviceMode *devmode,
4128 struct policy_handle *handle)
4130 struct spoolss_OpenPrinterEx r;
4131 struct spoolss_UserLevel1 userlevel1;
4132 NTSTATUS status;
4134 if (name && name[0]) {
4135 r.in.printername = talloc_asprintf(tctx, "\\\\%s\\%s",
4136 dcerpc_server_name(p), name);
4137 } else {
4138 r.in.printername = talloc_asprintf(tctx, "\\\\%s",
4139 dcerpc_server_name(p));
4142 r.in.datatype = NULL;
4143 r.in.devmode_ctr.devmode= devmode;
4144 r.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
4145 r.in.level = 1;
4146 r.in.userlevel.level1 = &userlevel1;
4147 r.out.handle = handle;
4149 userlevel1.size = 1234;
4150 userlevel1.client = "hello";
4151 userlevel1.user = "spottyfoot!";
4152 userlevel1.build = 1;
4153 userlevel1.major = 2;
4154 userlevel1.minor = 3;
4155 userlevel1.processor = 4;
4157 torture_comment(tctx, "Testing OpenPrinterEx(%s)\n", r.in.printername);
4159 status = dcerpc_spoolss_OpenPrinterEx(p, tctx, &r);
4161 torture_assert_ntstatus_ok(tctx, status, "OpenPrinterEx failed");
4163 torture_assert_werr_ok(tctx, r.out.result, "OpenPrinterEx failed");
4165 return true;
4168 static bool test_printer_rename(struct torture_context *tctx,
4169 struct dcerpc_pipe *p,
4170 struct policy_handle *handle,
4171 const char *name)
4173 bool ret = true;
4174 union spoolss_PrinterInfo info;
4175 union spoolss_SetPrinterInfo sinfo;
4176 struct spoolss_SetPrinterInfoCtr info_ctr;
4177 struct spoolss_DevmodeContainer devmode_ctr;
4178 struct sec_desc_buf secdesc_ctr;
4179 const char *printer_name;
4180 const char *printer_name_orig;
4181 const char *printer_name_new = "SAMBA smbtorture Test Printer (Copy 2)";
4182 struct policy_handle new_handle;
4183 const char *q;
4185 ZERO_STRUCT(devmode_ctr);
4186 ZERO_STRUCT(secdesc_ctr);
4188 torture_comment(tctx, "Testing Printer rename operations\n");
4190 torture_assert(tctx,
4191 test_GetPrinter_level(tctx, p, handle, 2, &info),
4192 "failed to call GetPrinter level 2");
4194 printer_name_orig = talloc_strdup(tctx, info.info2.printername);
4196 q = strrchr(info.info2.printername, '\\');
4197 if (q) {
4198 torture_warning(tctx,
4199 "server returns printername %s incl. servername although we did not set servername", info.info2.printername);
4202 torture_assert(tctx,
4203 PrinterInfo_to_SetPrinterInfo(tctx, &info, 2, &sinfo), "");
4205 sinfo.info2->printername = printer_name_new;
4207 info_ctr.level = 2;
4208 info_ctr.info = sinfo;
4210 torture_assert(tctx,
4211 test_SetPrinter(tctx, p, handle, &info_ctr, &devmode_ctr, &secdesc_ctr, 0),
4212 "failed to call SetPrinter level 2");
4214 torture_assert(tctx,
4215 test_GetPrinter_level(tctx, p, handle, 2, &info),
4216 "failed to call GetPrinter level 2");
4218 printer_name = talloc_strdup(tctx, info.info2.printername);
4220 q = strrchr(info.info2.printername, '\\');
4221 if (q) {
4222 torture_warning(tctx,
4223 "server returns printername %s incl. servername although we did not set servername", info.info2.printername);
4224 q++;
4225 printer_name = q;
4228 torture_assert_str_equal(tctx, printer_name, printer_name_new,
4229 "new printer name was not set");
4231 torture_assert(tctx,
4232 test_OpenPrinter_badname(tctx, p, printer_name_orig),
4233 "still can open printer with oldname");
4235 torture_assert(tctx,
4236 call_OpenPrinterEx(tctx, p, printer_name_new, NULL, &new_handle),
4237 "failed to open printer with new name");
4239 torture_assert(tctx,
4240 test_GetPrinter_level(tctx, p, &new_handle, 2, &info),
4241 "failed to call GetPrinter level 2");
4243 /* FIXME: we openend with servername! */
4244 printer_name = talloc_asprintf(tctx, "\\\\%s\\%s",
4245 dcerpc_server_name(p), printer_name_new);
4247 torture_assert_str_equal(tctx, info.info2.printername, printer_name,
4248 "new printer name was not set");
4250 torture_assert(tctx,
4251 test_ClosePrinter(tctx, p, &new_handle),
4252 "failed to close printer");
4254 return ret;
4258 static bool test_OpenPrinterEx(struct torture_context *tctx,
4259 struct dcerpc_pipe *p,
4260 const char *name,
4261 const char *environment)
4263 struct policy_handle handle;
4264 bool ret = true;
4266 if (!call_OpenPrinterEx(tctx, p, name, NULL, &handle)) {
4267 return false;
4270 if (!test_PrinterInfo_SD(tctx, p, &handle)) {
4271 ret = false;
4274 if (!test_GetPrinter(tctx, p, &handle, environment)) {
4275 ret = false;
4278 if (!test_EnumForms(tctx, p, &handle, false)) {
4279 ret = false;
4282 if (!test_AddForm(tctx, p, &handle, false)) {
4283 ret = false;
4286 if (!test_EnumPrinterData_all(tctx, p, &handle)) {
4287 ret = false;
4290 if (!test_EnumPrinterDataEx(tctx, p, &handle, "PrinterDriverData", NULL, NULL)) {
4291 ret = false;
4294 if (!test_EnumPrinterData_consistency(tctx, p, &handle)) {
4295 ret = false;
4298 if (!test_printer_keys(tctx, p, &handle)) {
4299 ret = false;
4302 if (!test_PausePrinter(tctx, p, &handle)) {
4303 ret = false;
4306 if (!test_DoPrintTest(tctx, p, &handle)) {
4307 ret = false;
4310 if (!test_ResumePrinter(tctx, p, &handle)) {
4311 ret = false;
4314 if (!test_SetPrinterData_matrix(tctx, p, &handle, name, NULL, NULL)) {
4315 ret = false;
4318 if (!test_SetPrinterDataEx_matrix(tctx, p, &handle, name, NULL, NULL)) {
4319 ret = false;
4322 if (!torture_setting_bool(tctx, "samba3", false)) {
4323 if (!test_SecondaryClosePrinter(tctx, p, &handle)) {
4324 ret = false;
4328 if (!test_ClosePrinter(tctx, p, &handle)) {
4329 ret = false;
4332 return ret;
4335 static bool test_EnumPrinters_old(struct torture_context *tctx,
4336 struct dcerpc_pipe *p,
4337 const char *environment)
4339 struct spoolss_EnumPrinters r;
4340 NTSTATUS status;
4341 uint16_t levels[] = {1, 2, 4, 5};
4342 int i;
4343 bool ret = true;
4345 for (i=0;i<ARRAY_SIZE(levels);i++) {
4346 union spoolss_PrinterInfo *info;
4347 int j;
4348 uint32_t needed;
4349 uint32_t count;
4351 r.in.flags = PRINTER_ENUM_LOCAL;
4352 r.in.server = "";
4353 r.in.level = levels[i];
4354 r.in.buffer = NULL;
4355 r.in.offered = 0;
4356 r.out.needed = &needed;
4357 r.out.count = &count;
4358 r.out.info = &info;
4360 torture_comment(tctx, "Testing EnumPrinters level %u\n", r.in.level);
4362 status = dcerpc_spoolss_EnumPrinters(p, tctx, &r);
4363 torture_assert_ntstatus_ok(tctx, status, "EnumPrinters failed");
4365 if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
4366 DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed);
4367 data_blob_clear(&blob);
4368 r.in.buffer = &blob;
4369 r.in.offered = needed;
4370 status = dcerpc_spoolss_EnumPrinters(p, tctx, &r);
4373 torture_assert_ntstatus_ok(tctx, status, "EnumPrinters failed");
4375 torture_assert_werr_ok(tctx, r.out.result, "EnumPrinters failed");
4377 CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumPrinters, info, r.in.level, count, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
4379 if (!info) {
4380 torture_comment(tctx, "No printers returned\n");
4381 return true;
4384 for (j=0;j<count;j++) {
4385 if (r.in.level == 1) {
4386 char *unc = talloc_strdup(tctx, info[j].info1.name);
4387 char *slash, *name;
4388 name = unc;
4389 if (unc[0] == '\\' && unc[1] == '\\') {
4390 unc +=2;
4392 slash = strchr(unc, '\\');
4393 if (slash) {
4394 slash++;
4395 name = slash;
4397 if (!test_OpenPrinter(tctx, p, name, environment)) {
4398 ret = false;
4400 if (!test_OpenPrinterEx(tctx, p, name, environment)) {
4401 ret = false;
4407 return ret;
4410 static bool test_GetPrinterDriver(struct torture_context *tctx,
4411 struct dcerpc_pipe *p,
4412 struct policy_handle *handle,
4413 const char *driver_name)
4415 struct spoolss_GetPrinterDriver r;
4416 uint32_t needed;
4418 r.in.handle = handle;
4419 r.in.architecture = "W32X86";
4420 r.in.level = 1;
4421 r.in.buffer = NULL;
4422 r.in.offered = 0;
4423 r.out.needed = &needed;
4425 torture_comment(tctx, "Testing GetPrinterDriver level %d\n", r.in.level);
4427 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_GetPrinterDriver(p, tctx, &r),
4428 "failed to call GetPrinterDriver");
4429 if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
4430 DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed);
4431 data_blob_clear(&blob);
4432 r.in.buffer = &blob;
4433 r.in.offered = needed;
4434 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_GetPrinterDriver(p, tctx, &r),
4435 "failed to call GetPrinterDriver");
4438 torture_assert_werr_ok(tctx, r.out.result,
4439 "failed to call GetPrinterDriver");
4441 CHECK_NEEDED_SIZE_LEVEL(spoolss_DriverInfo, r.out.info, r.in.level, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
4443 return true;
4446 static bool test_GetPrinterDriver2(struct torture_context *tctx,
4447 struct dcerpc_pipe *p,
4448 struct policy_handle *handle,
4449 const char *driver_name,
4450 const char *architecture)
4452 struct spoolss_GetPrinterDriver2 r;
4453 uint16_t levels[] = {1, 2, 3, 4, 5, 6, 8, 101 };
4454 uint32_t needed;
4455 uint32_t server_major_version;
4456 uint32_t server_minor_version;
4457 int i;
4459 r.in.handle = handle;
4460 r.in.architecture = architecture;
4461 r.in.client_major_version = 3;
4462 r.in.client_minor_version = 0;
4463 r.out.needed = &needed;
4464 r.out.server_major_version = &server_major_version;
4465 r.out.server_minor_version = &server_minor_version;
4467 for (i=0;i<ARRAY_SIZE(levels);i++) {
4469 r.in.buffer = NULL;
4470 r.in.offered = 0;
4471 r.in.level = levels[i];
4473 torture_comment(tctx, "Testing GetPrinterDriver2(%s) level %d\n",
4474 driver_name, r.in.level);
4476 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_GetPrinterDriver2(p, tctx, &r),
4477 "failed to call GetPrinterDriver2");
4478 if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
4479 DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed);
4480 data_blob_clear(&blob);
4481 r.in.buffer = &blob;
4482 r.in.offered = needed;
4483 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_GetPrinterDriver2(p, tctx, &r),
4484 "failed to call GetPrinterDriver2");
4487 if (W_ERROR_EQUAL(r.out.result, WERR_INVALID_LEVEL)) {
4488 switch (r.in.level) {
4489 case 101:
4490 case 8:
4491 continue;
4492 default:
4493 break;
4497 torture_assert_werr_ok(tctx, r.out.result,
4498 "failed to call GetPrinterDriver2");
4500 CHECK_NEEDED_SIZE_LEVEL(spoolss_DriverInfo, r.out.info, r.in.level, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
4503 return true;
4506 static bool test_EnumPrinterDrivers_old(struct torture_context *tctx,
4507 struct dcerpc_pipe *p,
4508 const char *environment)
4510 struct spoolss_EnumPrinterDrivers r;
4511 NTSTATUS status;
4512 uint16_t levels[] = {1, 2, 3, 4, 5, 6};
4513 int i;
4515 for (i=0;i<ARRAY_SIZE(levels);i++) {
4517 uint32_t needed;
4518 uint32_t count;
4519 union spoolss_DriverInfo *info;
4521 r.in.server = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
4522 r.in.environment = environment;
4523 r.in.level = levels[i];
4524 r.in.buffer = NULL;
4525 r.in.offered = 0;
4526 r.out.needed = &needed;
4527 r.out.count = &count;
4528 r.out.info = &info;
4530 torture_comment(tctx, "Testing EnumPrinterDrivers level %u\n", r.in.level);
4532 status = dcerpc_spoolss_EnumPrinterDrivers(p, tctx, &r);
4534 torture_assert_ntstatus_ok(tctx, status, "EnumPrinterDrivers failed");
4536 if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
4537 DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed);
4538 data_blob_clear(&blob);
4539 r.in.buffer = &blob;
4540 r.in.offered = needed;
4541 status = dcerpc_spoolss_EnumPrinterDrivers(p, tctx, &r);
4544 torture_assert_ntstatus_ok(tctx, status, "EnumPrinterDrivers failed");
4546 torture_assert_werr_ok(tctx, r.out.result, "EnumPrinterDrivers failed");
4548 if (!info) {
4549 torture_comment(tctx, "No printer drivers returned\n");
4550 break;
4553 CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumPrinterDrivers, info, r.in.level, count, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
4556 return true;
4559 static bool test_DeletePrinter(struct torture_context *tctx,
4560 struct dcerpc_pipe *p,
4561 struct policy_handle *handle)
4563 struct spoolss_DeletePrinter r;
4565 torture_comment(tctx, "Testing DeletePrinter\n");
4567 r.in.handle = handle;
4569 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_DeletePrinter(p, tctx, &r),
4570 "failed to delete printer");
4571 torture_assert_werr_ok(tctx, r.out.result,
4572 "failed to delete printer");
4574 return true;
4577 static bool test_EnumPrinters_findname(struct torture_context *tctx,
4578 struct dcerpc_pipe *p,
4579 uint32_t flags,
4580 uint32_t level,
4581 const char *name,
4582 bool *found)
4584 struct spoolss_EnumPrinters e;
4585 uint32_t count;
4586 union spoolss_PrinterInfo *info;
4587 uint32_t needed;
4588 int i;
4590 *found = false;
4592 e.in.flags = flags;
4593 e.in.server = NULL;
4594 e.in.level = level;
4595 e.in.buffer = NULL;
4596 e.in.offered = 0;
4597 e.out.count = &count;
4598 e.out.info = &info;
4599 e.out.needed = &needed;
4601 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_EnumPrinters(p, tctx, &e),
4602 "failed to enum printers");
4604 if (W_ERROR_EQUAL(e.out.result, WERR_INSUFFICIENT_BUFFER)) {
4605 DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed);
4606 data_blob_clear(&blob);
4607 e.in.buffer = &blob;
4608 e.in.offered = needed;
4610 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_EnumPrinters(p, tctx, &e),
4611 "failed to enum printers");
4614 torture_assert_werr_ok(tctx, e.out.result,
4615 "failed to enum printers");
4617 for (i=0; i < count; i++) {
4619 const char *current = NULL;
4620 const char *q;
4622 switch (level) {
4623 case 1:
4624 current = info[i].info1.name;
4625 break;
4628 if (strequal(current, name)) {
4629 *found = true;
4630 break;
4633 q = strrchr(current, '\\');
4634 if (q) {
4635 if (!e.in.server) {
4636 torture_warning(tctx,
4637 "server returns printername %s incl. servername although we did not set servername", current);
4639 q++;
4640 if (strequal(q, name)) {
4641 *found = true;
4642 break;
4647 return true;
4650 static bool test_AddPrinter_wellknown(struct torture_context *tctx,
4651 struct dcerpc_pipe *p,
4652 const char *printername,
4653 bool ex)
4655 WERROR result;
4656 struct spoolss_AddPrinter r;
4657 struct spoolss_AddPrinterEx rex;
4658 struct spoolss_SetPrinterInfoCtr info_ctr;
4659 struct spoolss_SetPrinterInfo1 info1;
4660 struct spoolss_DevmodeContainer devmode_ctr;
4661 struct sec_desc_buf secdesc_ctr;
4662 struct spoolss_UserLevelCtr userlevel_ctr;
4663 struct policy_handle handle;
4664 bool found = false;
4666 ZERO_STRUCT(devmode_ctr);
4667 ZERO_STRUCT(secdesc_ctr);
4668 ZERO_STRUCT(userlevel_ctr);
4669 ZERO_STRUCT(info1);
4671 torture_comment(tctx, "Testing AddPrinter%s level 1\n", ex ? "Ex":"");
4673 /* try to add printer to wellknown printer list (level 1) */
4675 userlevel_ctr.level = 1;
4677 info_ctr.info.info1 = &info1;
4678 info_ctr.level = 1;
4680 rex.in.server = NULL;
4681 rex.in.info_ctr = &info_ctr;
4682 rex.in.devmode_ctr = &devmode_ctr;
4683 rex.in.secdesc_ctr = &secdesc_ctr;
4684 rex.in.userlevel_ctr = &userlevel_ctr;
4685 rex.out.handle = &handle;
4687 r.in.server = NULL;
4688 r.in.info_ctr = &info_ctr;
4689 r.in.devmode_ctr = &devmode_ctr;
4690 r.in.secdesc_ctr = &secdesc_ctr;
4691 r.out.handle = &handle;
4693 torture_assert_ntstatus_ok(tctx, ex ? dcerpc_spoolss_AddPrinterEx(p, tctx, &rex) :
4694 dcerpc_spoolss_AddPrinter(p, tctx, &r),
4695 "failed to add printer");
4696 result = ex ? rex.out.result : r.out.result;
4697 torture_assert_werr_equal(tctx, result, WERR_INVALID_PRINTER_NAME,
4698 "unexpected result code");
4700 info1.name = printername;
4701 info1.flags = PRINTER_ATTRIBUTE_SHARED;
4703 torture_assert_ntstatus_ok(tctx, ex ? dcerpc_spoolss_AddPrinterEx(p, tctx, &rex) :
4704 dcerpc_spoolss_AddPrinter(p, tctx, &r),
4705 "failed to add printer");
4706 result = ex ? rex.out.result : r.out.result;
4707 torture_assert_werr_equal(tctx, result, WERR_PRINTER_ALREADY_EXISTS,
4708 "unexpected result code");
4710 /* bizarre protocol, WERR_PRINTER_ALREADY_EXISTS means success here,
4711 better do a real check to see the printer is really there */
4713 torture_assert(tctx, test_EnumPrinters_findname(tctx, p,
4714 PRINTER_ENUM_NETWORK, 1,
4715 printername,
4716 &found),
4717 "failed to enum printers");
4719 torture_assert(tctx, found, "failed to find newly added printer");
4721 info1.flags = 0;
4723 torture_assert_ntstatus_ok(tctx, ex ? dcerpc_spoolss_AddPrinterEx(p, tctx, &rex) :
4724 dcerpc_spoolss_AddPrinter(p, tctx, &r),
4725 "failed to add printer");
4726 result = ex ? rex.out.result : r.out.result;
4727 torture_assert_werr_equal(tctx, result, WERR_PRINTER_ALREADY_EXISTS,
4728 "unexpected result code");
4730 /* bizarre protocol, WERR_PRINTER_ALREADY_EXISTS means success here,
4731 better do a real check to see the printer has really been removed
4732 from the well known printer list */
4734 found = false;
4736 torture_assert(tctx, test_EnumPrinters_findname(tctx, p,
4737 PRINTER_ENUM_NETWORK, 1,
4738 printername,
4739 &found),
4740 "failed to enum printers");
4741 #if 0
4742 torture_assert(tctx, !found, "printer still in well known printer list");
4743 #endif
4744 return true;
4747 static bool test_AddPrinter_normal(struct torture_context *tctx,
4748 struct dcerpc_pipe *p,
4749 struct policy_handle *handle_p,
4750 const char *printername,
4751 const char *drivername,
4752 const char *portname,
4753 bool ex)
4755 WERROR result;
4756 struct spoolss_AddPrinter r;
4757 struct spoolss_AddPrinterEx rex;
4758 struct spoolss_SetPrinterInfoCtr info_ctr;
4759 struct spoolss_SetPrinterInfo2 info2;
4760 struct spoolss_DevmodeContainer devmode_ctr;
4761 struct sec_desc_buf secdesc_ctr;
4762 struct spoolss_UserLevelCtr userlevel_ctr;
4763 struct policy_handle handle;
4764 bool found = false;
4765 bool existing_printer_deleted = false;
4767 ZERO_STRUCT(devmode_ctr);
4768 ZERO_STRUCT(secdesc_ctr);
4769 ZERO_STRUCT(userlevel_ctr);
4771 torture_comment(tctx, "Testing AddPrinter%s level 2\n", ex ? "Ex":"");
4773 userlevel_ctr.level = 1;
4775 rex.in.server = NULL;
4776 rex.in.info_ctr = &info_ctr;
4777 rex.in.devmode_ctr = &devmode_ctr;
4778 rex.in.secdesc_ctr = &secdesc_ctr;
4779 rex.in.userlevel_ctr = &userlevel_ctr;
4780 rex.out.handle = &handle;
4782 r.in.server = NULL;
4783 r.in.info_ctr = &info_ctr;
4784 r.in.devmode_ctr = &devmode_ctr;
4785 r.in.secdesc_ctr = &secdesc_ctr;
4786 r.out.handle = &handle;
4788 again:
4790 /* try to add printer to printer list (level 2) */
4792 ZERO_STRUCT(info2);
4794 info_ctr.info.info2 = &info2;
4795 info_ctr.level = 2;
4797 torture_assert_ntstatus_ok(tctx, ex ? dcerpc_spoolss_AddPrinterEx(p, tctx, &rex) :
4798 dcerpc_spoolss_AddPrinter(p, tctx, &r),
4799 "failed to add printer");
4800 result = ex ? rex.out.result : r.out.result;
4801 torture_assert_werr_equal(tctx, result, WERR_INVALID_PRINTER_NAME,
4802 "unexpected result code");
4804 info2.printername = printername;
4806 torture_assert_ntstatus_ok(tctx, ex ? dcerpc_spoolss_AddPrinterEx(p, tctx, &rex) :
4807 dcerpc_spoolss_AddPrinter(p, tctx, &r),
4808 "failed to add printer");
4809 result = ex ? rex.out.result : r.out.result;
4811 if (W_ERROR_EQUAL(result, WERR_PRINTER_ALREADY_EXISTS)) {
4812 struct policy_handle printer_handle;
4814 if (existing_printer_deleted) {
4815 torture_fail(tctx, "already deleted printer still existing?");
4818 torture_assert(tctx, call_OpenPrinterEx(tctx, p, printername, NULL, &printer_handle),
4819 "failed to open printer handle");
4821 torture_assert(tctx, test_DeletePrinter(tctx, p, &printer_handle),
4822 "failed to delete printer");
4824 torture_assert(tctx, test_ClosePrinter(tctx, p, &printer_handle),
4825 "failed to close server handle");
4827 existing_printer_deleted = true;
4829 goto again;
4832 torture_assert_werr_equal(tctx, result, WERR_UNKNOWN_PORT,
4833 "unexpected result code");
4835 info2.portname = portname;
4837 torture_assert_ntstatus_ok(tctx, ex ? dcerpc_spoolss_AddPrinterEx(p, tctx, &rex) :
4838 dcerpc_spoolss_AddPrinter(p, tctx, &r),
4839 "failed to add printer");
4840 result = ex ? rex.out.result : r.out.result;
4841 torture_assert_werr_equal(tctx, result, WERR_UNKNOWN_PRINTER_DRIVER,
4842 "unexpected result code");
4844 info2.drivername = drivername;
4846 torture_assert_ntstatus_ok(tctx, ex ? dcerpc_spoolss_AddPrinterEx(p, tctx, &rex) :
4847 dcerpc_spoolss_AddPrinter(p, tctx, &r),
4848 "failed to add printer");
4849 result = ex ? rex.out.result : r.out.result;
4851 /* w2k8r2 allows to add printer w/o defining printprocessor */
4853 if (!W_ERROR_IS_OK(result)) {
4854 torture_assert_werr_equal(tctx, result, WERR_UNKNOWN_PRINTPROCESSOR,
4855 "unexpected result code");
4857 info2.printprocessor = "winprint";
4859 torture_assert_ntstatus_ok(tctx, ex ? dcerpc_spoolss_AddPrinterEx(p, tctx, &rex) :
4860 dcerpc_spoolss_AddPrinter(p, tctx, &r),
4861 "failed to add printer");
4862 result = ex ? rex.out.result : r.out.result;
4863 torture_assert_werr_ok(tctx, result,
4864 "failed to add printer");
4867 *handle_p = handle;
4869 /* we are paranoid, really check if the printer is there now */
4871 torture_assert(tctx, test_EnumPrinters_findname(tctx, p,
4872 PRINTER_ENUM_LOCAL, 1,
4873 printername,
4874 &found),
4875 "failed to enum printers");
4876 torture_assert(tctx, found, "failed to find newly added printer");
4878 torture_assert_ntstatus_ok(tctx, ex ? dcerpc_spoolss_AddPrinterEx(p, tctx, &rex) :
4879 dcerpc_spoolss_AddPrinter(p, tctx, &r),
4880 "failed to add printer");
4881 result = ex ? rex.out.result : r.out.result;
4882 torture_assert_werr_equal(tctx, result, WERR_PRINTER_ALREADY_EXISTS,
4883 "unexpected result code");
4885 return true;
4888 static bool test_AddPrinterEx(struct torture_context *tctx,
4889 struct dcerpc_pipe *p,
4890 struct policy_handle *handle_p,
4891 const char *printername,
4892 const char *drivername,
4893 const char *portname)
4895 bool ret = true;
4897 if (!torture_setting_bool(tctx, "samba3", false)) {
4898 if (!test_AddPrinter_wellknown(tctx, p, TORTURE_WELLKNOWN_PRINTER_EX, true)) {
4899 torture_comment(tctx, "failed to add printer to well known list\n");
4900 ret = false;
4904 if (!test_AddPrinter_normal(tctx, p, handle_p,
4905 printername, drivername, portname,
4906 true)) {
4907 torture_comment(tctx, "failed to add printer to printer list\n");
4908 ret = false;
4911 return ret;
4914 static bool test_AddPrinter(struct torture_context *tctx,
4915 struct dcerpc_pipe *p,
4916 struct policy_handle *handle_p,
4917 const char *printername,
4918 const char *drivername,
4919 const char *portname)
4921 bool ret = true;
4923 if (!torture_setting_bool(tctx, "samba3", false)) {
4924 if (!test_AddPrinter_wellknown(tctx, p, TORTURE_WELLKNOWN_PRINTER, false)) {
4925 torture_comment(tctx, "failed to add printer to well known list\n");
4926 ret = false;
4930 if (!test_AddPrinter_normal(tctx, p, handle_p,
4931 printername, drivername, portname,
4932 false)) {
4933 torture_comment(tctx, "failed to add printer to printer list\n");
4934 ret = false;
4937 return ret;
4940 static bool test_printer_info(struct torture_context *tctx,
4941 struct dcerpc_pipe *p,
4942 struct policy_handle *handle)
4944 bool ret = true;
4946 if (torture_setting_bool(tctx, "samba3", false)) {
4947 torture_skip(tctx, "skipping printer info cross tests against samba 3");
4950 if (!test_PrinterInfo(tctx, p, handle)) {
4951 ret = false;
4954 if (!test_SetPrinter_errors(tctx, p, handle)) {
4955 ret = false;
4958 return ret;
4961 static bool test_EnumPrinterKey(struct torture_context *tctx,
4962 struct dcerpc_pipe *p,
4963 struct policy_handle *handle,
4964 const char *key_name,
4965 const char ***array)
4967 struct spoolss_EnumPrinterKey r;
4968 uint32_t needed = 0;
4969 union spoolss_KeyNames key_buffer;
4970 int32_t offered[] = { 0, 1, 2, 3, 4, 5, -1, -2, -3, -4, -5, 256, 512, 1024, 2048 };
4971 uint32_t _ndr_size;
4972 int i;
4974 r.in.handle = handle;
4975 r.in.key_name = key_name;
4976 r.out.key_buffer = &key_buffer;
4977 r.out.needed = &needed;
4978 r.out._ndr_size = &_ndr_size;
4980 for (i=0; i < ARRAY_SIZE(offered); i++) {
4982 if (offered[i] < 0 && needed) {
4983 if (needed <= 4) {
4984 continue;
4986 r.in.offered = needed + offered[i];
4987 } else {
4988 r.in.offered = offered[i];
4991 ZERO_STRUCT(key_buffer);
4993 torture_comment(tctx, "Testing EnumPrinterKey(%s) with %d offered\n", r.in.key_name, r.in.offered);
4995 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_EnumPrinterKey(p, tctx, &r),
4996 "failed to call EnumPrinterKey");
4997 if (W_ERROR_EQUAL(r.out.result, WERR_MORE_DATA)) {
4999 torture_assert(tctx, (_ndr_size == r.in.offered/2),
5000 talloc_asprintf(tctx, "EnumPrinterKey size mismatch, _ndr_size %d (expected %d)",
5001 _ndr_size, r.in.offered/2));
5003 r.in.offered = needed;
5004 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_EnumPrinterKey(p, tctx, &r),
5005 "failed to call EnumPrinterKey");
5008 if (offered[i] > 0) {
5009 torture_assert_werr_ok(tctx, r.out.result,
5010 "failed to call EnumPrinterKey");
5013 torture_assert(tctx, (_ndr_size == r.in.offered/2),
5014 talloc_asprintf(tctx, "EnumPrinterKey size mismatch, _ndr_size %d (expected %d)",
5015 _ndr_size, r.in.offered/2));
5017 torture_assert(tctx, (*r.out.needed <= r.in.offered),
5018 talloc_asprintf(tctx, "EnumPrinterKey size mismatch: needed %d is not <= offered %d", *r.out.needed, r.in.offered));
5020 torture_assert(tctx, (*r.out.needed <= _ndr_size * 2),
5021 talloc_asprintf(tctx, "EnumPrinterKey size mismatch: needed %d is not <= _ndr_size %d * 2", *r.out.needed, _ndr_size));
5023 if (key_buffer.string_array) {
5024 uint32_t calc_needed = 0;
5025 int s;
5026 for (s=0; key_buffer.string_array[s]; s++) {
5027 calc_needed += strlen_m_term(key_buffer.string_array[s])*2;
5029 if (!key_buffer.string_array[0]) {
5030 calc_needed += 2;
5032 calc_needed += 2;
5034 torture_assert_int_equal(tctx, *r.out.needed, calc_needed,
5035 "EnumPrinterKey unexpected size");
5039 if (array) {
5040 *array = key_buffer.string_array;
5043 return true;
5046 bool test_printer_keys(struct torture_context *tctx,
5047 struct dcerpc_pipe *p,
5048 struct policy_handle *handle)
5050 const char **key_array = NULL;
5051 int i;
5053 torture_comment(tctx, "\nTesting Printer Keys\n");
5055 torture_assert(tctx, test_EnumPrinterKey(tctx, p, handle, "", &key_array),
5056 "failed to call test_EnumPrinterKey");
5058 for (i=0; key_array && key_array[i]; i++) {
5059 torture_assert(tctx, test_EnumPrinterKey(tctx, p, handle, key_array[i], NULL),
5060 "failed to call test_EnumPrinterKey");
5062 for (i=0; key_array && key_array[i]; i++) {
5063 torture_assert(tctx, test_EnumPrinterDataEx(tctx, p, handle, key_array[i], NULL, NULL),
5064 "failed to call test_EnumPrinterDataEx");
5067 return true;
5070 static bool test_one_printer(struct torture_context *tctx,
5071 struct dcerpc_pipe *p,
5072 struct policy_handle *handle,
5073 const char *name)
5075 bool ret = true;
5077 if (!test_printer_info(tctx, p, handle)) {
5078 ret = false;
5081 if (!test_PrinterInfo_SD(tctx, p, handle)) {
5082 ret = false;
5085 if (!test_PrinterInfo_DevMode(tctx, p, handle, name)) {
5086 ret = false;
5089 if (!test_ChangeID(tctx, p, handle)) {
5090 ret = false;
5093 if (!test_printer_keys(tctx, p, handle)) {
5094 ret = false;
5097 if (!test_EnumPrinterData_consistency(tctx, p, handle)) {
5098 ret = false;
5101 if (!test_SetPrinterDataEx_matrix(tctx, p, handle, name, NULL, NULL)) {
5102 ret = false;
5105 if (!test_PrinterData_winreg(tctx, p, handle, name)) {
5106 ret = false;
5109 if (!test_printer_rename(tctx, p, handle, name)) {
5110 ret = false;
5113 return ret;
5116 static bool test_printer(struct torture_context *tctx,
5117 struct dcerpc_pipe *p)
5119 bool ret = true;
5120 struct policy_handle handle[2];
5121 bool found = false;
5122 const char *drivername = "Microsoft XPS Document Writer";
5123 const char *portname = "LPT1:";
5125 /* test printer created via AddPrinter */
5127 if (!test_AddPrinter(tctx, p, &handle[0], TORTURE_PRINTER, drivername, portname)) {
5128 return false;
5131 if (!test_one_printer(tctx, p, &handle[0], TORTURE_PRINTER)) {
5132 ret = false;
5135 if (!test_DeletePrinter(tctx, p, &handle[0])) {
5136 ret = false;
5139 if (!test_EnumPrinters_findname(tctx, p, PRINTER_ENUM_LOCAL, 1,
5140 TORTURE_PRINTER, &found)) {
5141 ret = false;
5144 torture_assert(tctx, !found, "deleted printer still there");
5146 /* test printer created via AddPrinterEx */
5148 if (!test_AddPrinterEx(tctx, p, &handle[1], TORTURE_PRINTER_EX, drivername, portname)) {
5149 return false;
5152 if (!test_one_printer(tctx, p, &handle[1], TORTURE_PRINTER_EX)) {
5153 ret = false;
5156 if (!test_DeletePrinter(tctx, p, &handle[1])) {
5157 ret = false;
5160 if (!test_EnumPrinters_findname(tctx, p, PRINTER_ENUM_LOCAL, 1,
5161 TORTURE_PRINTER_EX, &found)) {
5162 ret = false;
5165 torture_assert(tctx, !found, "deleted printer still there");
5167 return ret;
5170 static bool test_architecture_buffer(struct torture_context *tctx,
5171 struct dcerpc_pipe *p)
5173 struct spoolss_OpenPrinterEx r;
5174 struct spoolss_UserLevel1 u1;
5175 struct policy_handle handle;
5176 uint32_t architectures[] = {
5177 PROCESSOR_ARCHITECTURE_INTEL,
5178 PROCESSOR_ARCHITECTURE_IA64,
5179 PROCESSOR_ARCHITECTURE_AMD64
5181 uint32_t needed[3];
5182 int i;
5184 for (i=0; i < ARRAY_SIZE(architectures); i++) {
5186 torture_comment(tctx, "Testing OpenPrinterEx with architecture %d\n", architectures[i]);
5188 u1.size = 0;
5189 u1.client = NULL;
5190 u1.user = NULL;
5191 u1.build = 0;
5192 u1.major = 3;
5193 u1.minor = 0;
5194 u1.processor = architectures[i];
5196 r.in.printername = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
5197 r.in.datatype = NULL;
5198 r.in.devmode_ctr.devmode= NULL;
5199 r.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
5200 r.in.level = 1;
5201 r.in.userlevel.level1 = &u1;
5202 r.out.handle = &handle;
5204 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_OpenPrinterEx(p, tctx, &r), "");
5205 torture_assert_werr_ok(tctx, r.out.result, "");
5208 struct spoolss_EnumPrinters e;
5209 uint32_t count;
5210 union spoolss_PrinterInfo *info;
5212 e.in.flags = PRINTER_ENUM_LOCAL;
5213 e.in.server = NULL;
5214 e.in.level = 2;
5215 e.in.buffer = NULL;
5216 e.in.offered = 0;
5217 e.out.count = &count;
5218 e.out.info = &info;
5219 e.out.needed = &needed[i];
5221 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_EnumPrinters(p, tctx, &e), "");
5222 #if 0
5223 torture_comment(tctx, "needed was %d\n", needed[i]);
5224 #endif
5227 torture_assert(tctx, test_ClosePrinter(tctx, p, &handle), "");
5230 for (i=1; i < ARRAY_SIZE(architectures); i++) {
5231 if (needed[i-1] != needed[i]) {
5232 torture_fail(tctx,
5233 talloc_asprintf(tctx, "needed size %d for architecture %d != needed size %d for architecture %d\n",
5234 needed[i-1], architectures[i-1], needed[i], architectures[i]));
5238 return true;
5241 bool torture_rpc_spoolss(struct torture_context *torture)
5243 NTSTATUS status;
5244 struct dcerpc_pipe *p;
5245 bool ret = true;
5246 struct test_spoolss_context *ctx;
5247 const char *environment = SPOOLSS_ARCHITECTURE_NT_X86;
5249 status = torture_rpc_connection(torture, &p, &ndr_table_spoolss);
5250 if (!NT_STATUS_IS_OK(status)) {
5251 return false;
5254 ctx = talloc_zero(torture, struct test_spoolss_context);
5256 ret &= test_OpenPrinter_server(torture, p, &ctx->server_handle);
5257 ret &= test_GetPrinterData_list(torture, p, &ctx->server_handle, &environment);
5258 ret &= test_EnumForms(torture, p, &ctx->server_handle, true);
5259 ret &= test_AddForm(torture, p, &ctx->server_handle, true);
5260 ret &= test_EnumPorts(torture, p, ctx);
5261 ret &= test_GetPrinterDriverDirectory(torture, p, ctx, environment);
5262 ret &= test_GetPrintProcessorDirectory(torture, p, ctx, environment);
5263 ret &= test_EnumPrinterDrivers(torture, p, ctx, environment);
5264 ret &= test_EnumPrinterDrivers(torture, p, ctx, SPOOLSS_ARCHITECTURE_ALL);
5265 ret &= test_EnumMonitors(torture, p, ctx);
5266 ret &= test_EnumPrintProcessors(torture, p, ctx, environment);
5267 ret &= test_EnumPrintProcDataTypes(torture, p, ctx);
5268 ret &= test_EnumPrinters(torture, p, ctx);
5269 ret &= test_OpenPrinter_badname(torture, p, "__INVALID_PRINTER__");
5270 ret &= test_OpenPrinter_badname(torture, p, "\\\\__INVALID_HOST__");
5271 ret &= test_OpenPrinter_badname(torture, p, "");
5272 ret &= test_OpenPrinter_badname(torture, p, "\\\\\\");
5273 ret &= test_OpenPrinter_badname(torture, p, "\\\\\\__INVALID_PRINTER__");
5274 ret &= test_OpenPrinter_badname(torture, p, talloc_asprintf(torture, "\\\\%s\\", dcerpc_server_name(p)));
5275 ret &= test_OpenPrinter_badname(torture, p,
5276 talloc_asprintf(torture, "\\\\%s\\__INVALID_PRINTER__", dcerpc_server_name(p)));
5279 ret &= test_AddPort(torture, p);
5280 ret &= test_EnumPorts_old(torture, p);
5281 ret &= test_EnumPrinters_old(torture, p, environment);
5282 ret &= test_EnumPrinterDrivers_old(torture, p, environment);
5283 ret &= test_architecture_buffer(torture, p);
5285 return ret;
5288 struct torture_suite *torture_rpc_spoolss_printer(TALLOC_CTX *mem_ctx)
5290 struct torture_suite *suite = torture_suite_create(mem_ctx, "SPOOLSS-PRINTER");
5292 struct torture_rpc_tcase *tcase = torture_suite_add_rpc_iface_tcase(suite,
5293 "printer", &ndr_table_spoolss);
5295 torture_rpc_tcase_add_test(tcase, "printer", test_printer);
5297 return suite;