s4:torture/rpc/samlogon.c: make use of dcerpc_binding_handle stubs
[Samba/nascimento.git] / source4 / torture / rpc / spoolss.c
blobdb7d5ab56612e3df0a9c267d57bd4e95e1642f72
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;
212 struct dcerpc_binding_handle *b = p->binding_handle;
214 op.in.printername = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
215 op.in.datatype = NULL;
216 op.in.devmode_ctr.devmode= NULL;
217 op.in.access_mask = 0;
218 op.out.handle = server_handle;
220 torture_comment(tctx, "Testing OpenPrinter(%s)\n", op.in.printername);
222 status = dcerpc_spoolss_OpenPrinter_r(b, tctx, &op);
223 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_OpenPrinter failed");
224 torture_assert_werr_ok(tctx, op.out.result, "dcerpc_spoolss_OpenPrinter failed");
226 return true;
229 static bool test_EnumPorts(struct torture_context *tctx,
230 struct dcerpc_binding_handle *b,
231 struct test_spoolss_context *ctx)
233 NTSTATUS status;
234 struct spoolss_EnumPorts r;
235 uint16_t levels[] = { 1, 2 };
236 int i, j;
238 for (i=0;i<ARRAY_SIZE(levels);i++) {
239 int level = levels[i];
240 DATA_BLOB blob;
241 uint32_t needed;
242 uint32_t count;
243 union spoolss_PortInfo *info;
245 r.in.servername = "";
246 r.in.level = level;
247 r.in.buffer = NULL;
248 r.in.offered = 0;
249 r.out.needed = &needed;
250 r.out.count = &count;
251 r.out.info = &info;
253 torture_comment(tctx, "Testing EnumPorts level %u\n", r.in.level);
255 status = dcerpc_spoolss_EnumPorts_r(b, ctx, &r);
256 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EnumPorts failed");
257 if (W_ERROR_IS_OK(r.out.result)) {
258 /* TODO: do some more checks here */
259 continue;
261 torture_assert_werr_equal(tctx, r.out.result, WERR_INSUFFICIENT_BUFFER,
262 "EnumPorts unexpected return code");
264 blob = data_blob_talloc(ctx, NULL, needed);
265 data_blob_clear(&blob);
266 r.in.buffer = &blob;
267 r.in.offered = needed;
269 status = dcerpc_spoolss_EnumPorts_r(b, ctx, &r);
270 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EnumPorts failed");
272 torture_assert_werr_ok(tctx, r.out.result, "EnumPorts failed");
274 torture_assert(tctx, info, "EnumPorts returned no info");
276 CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumPorts, info, r.in.level, count, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
278 ctx->port_count[level] = count;
279 ctx->ports[level] = info;
282 for (i=1;i<ARRAY_SIZE(levels);i++) {
283 int level = levels[i];
284 int old_level = levels[i-1];
285 torture_assert_int_equal(tctx, ctx->port_count[level], ctx->port_count[old_level],
286 "EnumPorts invalid value");
288 /* if the array sizes are not the same we would maybe segfault in the following code */
290 for (i=0;i<ARRAY_SIZE(levels);i++) {
291 int level = levels[i];
292 for (j=0;j<ctx->port_count[level];j++) {
293 union spoolss_PortInfo *cur = &ctx->ports[level][j];
294 union spoolss_PortInfo *ref = &ctx->ports[2][j];
295 switch (level) {
296 case 1:
297 COMPARE_STRING(tctx, cur->info1, ref->info2, port_name);
298 break;
299 case 2:
300 /* level 2 is our reference, and it makes no sense to compare it to itself */
301 break;
306 return true;
309 static bool test_GetPrintProcessorDirectory(struct torture_context *tctx,
310 struct dcerpc_pipe *p,
311 struct test_spoolss_context *ctx,
312 const char *environment)
314 NTSTATUS status;
315 struct dcerpc_binding_handle *b = p->binding_handle;
316 struct spoolss_GetPrintProcessorDirectory r;
317 struct {
318 uint16_t level;
319 const char *server;
320 } levels[] = {{
321 .level = 1,
322 .server = NULL
324 .level = 1,
325 .server = ""
327 .level = 78,
328 .server = ""
330 .level = 1,
331 .server = talloc_asprintf(ctx, "\\\\%s", dcerpc_server_name(p))
333 .level = 1024,
334 .server = talloc_asprintf(ctx, "\\\\%s", dcerpc_server_name(p))
337 int i;
338 uint32_t needed;
340 for (i=0;i<ARRAY_SIZE(levels);i++) {
341 int level = levels[i].level;
342 DATA_BLOB blob;
344 r.in.server = levels[i].server;
345 r.in.environment = environment;
346 r.in.level = level;
347 r.in.buffer = NULL;
348 r.in.offered = 0;
349 r.out.needed = &needed;
351 torture_comment(tctx, "Testing GetPrintProcessorDirectory level %u\n", r.in.level);
353 status = dcerpc_spoolss_GetPrintProcessorDirectory_r(b, ctx, &r);
354 torture_assert_ntstatus_ok(tctx, status,
355 "dcerpc_spoolss_GetPrintProcessorDirectory failed");
356 torture_assert_werr_equal(tctx, r.out.result, WERR_INSUFFICIENT_BUFFER,
357 "GetPrintProcessorDirectory unexpected return code");
359 blob = data_blob_talloc(ctx, NULL, needed);
360 data_blob_clear(&blob);
361 r.in.buffer = &blob;
362 r.in.offered = needed;
364 status = dcerpc_spoolss_GetPrintProcessorDirectory_r(b, ctx, &r);
365 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_GetPrintProcessorDirectory failed");
367 torture_assert_werr_ok(tctx, r.out.result, "GetPrintProcessorDirectory failed");
369 CHECK_NEEDED_SIZE_LEVEL(spoolss_PrintProcessorDirectoryInfo, r.out.info, r.in.level, lp_iconv_convenience(tctx->lp_ctx), needed, 2);
372 return true;
376 static bool test_GetPrinterDriverDirectory(struct torture_context *tctx,
377 struct dcerpc_pipe *p,
378 struct test_spoolss_context *ctx,
379 const char *environment)
381 NTSTATUS status;
382 struct dcerpc_binding_handle *b = p->binding_handle;
383 struct spoolss_GetPrinterDriverDirectory r;
384 struct {
385 uint16_t level;
386 const char *server;
387 } levels[] = {{
388 .level = 1,
389 .server = NULL
391 .level = 1,
392 .server = ""
394 .level = 78,
395 .server = ""
397 .level = 1,
398 .server = talloc_asprintf(ctx, "\\\\%s", dcerpc_server_name(p))
400 .level = 1024,
401 .server = talloc_asprintf(ctx, "\\\\%s", dcerpc_server_name(p))
404 int i;
405 uint32_t needed;
407 for (i=0;i<ARRAY_SIZE(levels);i++) {
408 int level = levels[i].level;
409 DATA_BLOB blob;
411 r.in.server = levels[i].server;
412 r.in.environment = environment;
413 r.in.level = level;
414 r.in.buffer = NULL;
415 r.in.offered = 0;
416 r.out.needed = &needed;
418 torture_comment(tctx, "Testing GetPrinterDriverDirectory level %u\n", r.in.level);
420 status = dcerpc_spoolss_GetPrinterDriverDirectory_r(b, ctx, &r);
421 torture_assert_ntstatus_ok(tctx, status,
422 "dcerpc_spoolss_GetPrinterDriverDirectory failed");
423 torture_assert_werr_equal(tctx, r.out.result, WERR_INSUFFICIENT_BUFFER,
424 "GetPrinterDriverDirectory unexpected return code");
426 blob = data_blob_talloc(ctx, NULL, needed);
427 data_blob_clear(&blob);
428 r.in.buffer = &blob;
429 r.in.offered = needed;
431 status = dcerpc_spoolss_GetPrinterDriverDirectory_r(b, ctx, &r);
432 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_GetPrinterDriverDirectory failed");
434 torture_assert_werr_ok(tctx, r.out.result, "GetPrinterDriverDirectory failed");
436 CHECK_NEEDED_SIZE_LEVEL(spoolss_DriverDirectoryInfo, r.out.info, r.in.level, lp_iconv_convenience(tctx->lp_ctx), needed, 2);
439 return true;
442 static bool test_EnumPrinterDrivers(struct torture_context *tctx,
443 struct dcerpc_pipe *p,
444 struct test_spoolss_context *ctx,
445 const char *architecture)
447 NTSTATUS status;
448 struct dcerpc_binding_handle *b = p->binding_handle;
449 struct spoolss_EnumPrinterDrivers r;
450 uint16_t levels[] = { 1, 2, 3, 4, 5, 6, 8 };
451 int i, j;
453 for (i=0;i<ARRAY_SIZE(levels);i++) {
454 int level = levels[i];
455 DATA_BLOB blob;
456 uint32_t needed;
457 uint32_t count;
458 union spoolss_DriverInfo *info;
460 /* FIXME: gd, come back and fix "" as server, and handle
461 * priority of returned error codes in torture test and samba 3
462 * server */
464 r.in.server = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
465 r.in.environment = architecture;
466 r.in.level = level;
467 r.in.buffer = NULL;
468 r.in.offered = 0;
469 r.out.needed = &needed;
470 r.out.count = &count;
471 r.out.info = &info;
473 torture_comment(tctx, "Testing EnumPrinterDrivers level %u (%s)\n", r.in.level, r.in.environment);
475 status = dcerpc_spoolss_EnumPrinterDrivers_r(b, ctx, &r);
476 torture_assert_ntstatus_ok(tctx, status,
477 "dcerpc_spoolss_EnumPrinterDrivers failed");
478 if (W_ERROR_IS_OK(r.out.result)) {
479 /* TODO: do some more checks here */
480 continue;
482 if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
483 blob = data_blob_talloc(ctx, NULL, needed);
484 data_blob_clear(&blob);
485 r.in.buffer = &blob;
486 r.in.offered = needed;
488 status = dcerpc_spoolss_EnumPrinterDrivers_r(b, ctx, &r);
489 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EnumPrinterDrivers failed");
492 torture_assert_werr_ok(tctx, r.out.result, "EnumPrinterDrivers failed");
494 CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumPrinterDrivers, info, r.in.level, count, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
496 ctx->driver_count[level] = count;
497 ctx->drivers[level] = info;
500 for (i=1;i<ARRAY_SIZE(levels);i++) {
501 int level = levels[i];
502 int old_level = levels[i-1];
504 torture_assert_int_equal(tctx, ctx->driver_count[level], ctx->driver_count[old_level],
505 "EnumPrinterDrivers invalid value");
508 for (i=0;i<ARRAY_SIZE(levels);i++) {
509 int level = levels[i];
511 for (j=0;j<ctx->driver_count[level];j++) {
512 union spoolss_DriverInfo *cur = &ctx->drivers[level][j];
513 union spoolss_DriverInfo *ref = &ctx->drivers[8][j];
515 switch (level) {
516 case 1:
517 COMPARE_STRING(tctx, cur->info1, ref->info8, driver_name);
518 break;
519 case 2:
520 COMPARE_UINT32(tctx, cur->info2, ref->info8, version);
521 COMPARE_STRING(tctx, cur->info2, ref->info8, driver_name);
522 COMPARE_STRING(tctx, cur->info2, ref->info8, architecture);
523 COMPARE_STRING(tctx, cur->info2, ref->info8, driver_path);
524 COMPARE_STRING(tctx, cur->info2, ref->info8, data_file);
525 COMPARE_STRING(tctx, cur->info2, ref->info8, config_file);
526 break;
527 case 3:
528 COMPARE_UINT32(tctx, cur->info3, ref->info8, version);
529 COMPARE_STRING(tctx, cur->info3, ref->info8, driver_name);
530 COMPARE_STRING(tctx, cur->info3, ref->info8, architecture);
531 COMPARE_STRING(tctx, cur->info3, ref->info8, driver_path);
532 COMPARE_STRING(tctx, cur->info3, ref->info8, data_file);
533 COMPARE_STRING(tctx, cur->info3, ref->info8, config_file);
534 COMPARE_STRING(tctx, cur->info3, ref->info8, help_file);
535 COMPARE_STRING_ARRAY(tctx, cur->info3, ref->info8, dependent_files);
536 COMPARE_STRING(tctx, cur->info3, ref->info8, monitor_name);
537 COMPARE_STRING(tctx, cur->info3, ref->info8, default_datatype);
538 break;
539 case 4:
540 COMPARE_UINT32(tctx, cur->info4, ref->info8, version);
541 COMPARE_STRING(tctx, cur->info4, ref->info8, driver_name);
542 COMPARE_STRING(tctx, cur->info4, ref->info8, architecture);
543 COMPARE_STRING(tctx, cur->info4, ref->info8, driver_path);
544 COMPARE_STRING(tctx, cur->info4, ref->info8, data_file);
545 COMPARE_STRING(tctx, cur->info4, ref->info8, config_file);
546 COMPARE_STRING(tctx, cur->info4, ref->info8, help_file);
547 COMPARE_STRING_ARRAY(tctx, cur->info4, ref->info8, dependent_files);
548 COMPARE_STRING(tctx, cur->info4, ref->info8, monitor_name);
549 COMPARE_STRING(tctx, cur->info4, ref->info8, default_datatype);
550 COMPARE_STRING_ARRAY(tctx, cur->info4, ref->info8, previous_names);
551 break;
552 case 5:
553 COMPARE_UINT32(tctx, cur->info5, ref->info8, version);
554 COMPARE_STRING(tctx, cur->info5, ref->info8, driver_name);
555 COMPARE_STRING(tctx, cur->info5, ref->info8, architecture);
556 COMPARE_STRING(tctx, cur->info5, ref->info8, driver_path);
557 COMPARE_STRING(tctx, cur->info5, ref->info8, data_file);
558 COMPARE_STRING(tctx, cur->info5, ref->info8, config_file);
559 /*COMPARE_UINT32(tctx, cur->info5, ref->info8, driver_attributes);*/
560 /*COMPARE_UINT32(tctx, cur->info5, ref->info8, config_version);*/
561 /*TODO: ! COMPARE_UINT32(tctx, cur->info5, ref->info8, driver_version); */
562 break;
563 case 6:
564 COMPARE_UINT32(tctx, cur->info6, ref->info8, version);
565 COMPARE_STRING(tctx, cur->info6, ref->info8, driver_name);
566 COMPARE_STRING(tctx, cur->info6, ref->info8, architecture);
567 COMPARE_STRING(tctx, cur->info6, ref->info8, driver_path);
568 COMPARE_STRING(tctx, cur->info6, ref->info8, data_file);
569 COMPARE_STRING(tctx, cur->info6, ref->info8, config_file);
570 COMPARE_STRING(tctx, cur->info6, ref->info8, help_file);
571 COMPARE_STRING_ARRAY(tctx, cur->info6, ref->info8, dependent_files);
572 COMPARE_STRING(tctx, cur->info6, ref->info8, monitor_name);
573 COMPARE_STRING(tctx, cur->info6, ref->info8, default_datatype);
574 COMPARE_STRING_ARRAY(tctx, cur->info6, ref->info8, previous_names);
575 COMPARE_NTTIME(tctx, cur->info6, ref->info8, driver_date);
576 COMPARE_UINT64(tctx, cur->info6, ref->info8, driver_version);
577 COMPARE_STRING(tctx, cur->info6, ref->info8, manufacturer_name);
578 COMPARE_STRING(tctx, cur->info6, ref->info8, manufacturer_url);
579 COMPARE_STRING(tctx, cur->info6, ref->info8, hardware_id);
580 COMPARE_STRING(tctx, cur->info6, ref->info8, provider);
581 break;
582 case 8:
583 /* level 8 is our reference, and it makes no sense to compare it to itself */
584 break;
589 return true;
592 static bool test_EnumMonitors(struct torture_context *tctx,
593 struct dcerpc_binding_handle *b,
594 struct test_spoolss_context *ctx)
596 NTSTATUS status;
597 struct spoolss_EnumMonitors r;
598 uint16_t levels[] = { 1, 2 };
599 int i, j;
601 for (i=0;i<ARRAY_SIZE(levels);i++) {
602 int level = levels[i];
603 DATA_BLOB blob;
604 uint32_t needed;
605 uint32_t count;
606 union spoolss_MonitorInfo *info;
608 r.in.servername = "";
609 r.in.level = level;
610 r.in.buffer = NULL;
611 r.in.offered = 0;
612 r.out.needed = &needed;
613 r.out.count = &count;
614 r.out.info = &info;
616 torture_comment(tctx, "Testing EnumMonitors level %u\n", r.in.level);
618 status = dcerpc_spoolss_EnumMonitors_r(b, ctx, &r);
619 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EnumMonitors failed");
620 if (W_ERROR_IS_OK(r.out.result)) {
621 /* TODO: do some more checks here */
622 continue;
624 torture_assert_werr_equal(tctx, r.out.result, WERR_INSUFFICIENT_BUFFER,
625 "EnumMonitors failed");
627 blob = data_blob_talloc(ctx, NULL, needed);
628 data_blob_clear(&blob);
629 r.in.buffer = &blob;
630 r.in.offered = needed;
632 status = dcerpc_spoolss_EnumMonitors_r(b, ctx, &r);
633 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EnumMonitors failed");
635 torture_assert_werr_ok(tctx, r.out.result, "EnumMonitors failed");
637 CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumMonitors, info, r.in.level, count, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
639 ctx->monitor_count[level] = count;
640 ctx->monitors[level] = info;
643 for (i=1;i<ARRAY_SIZE(levels);i++) {
644 int level = levels[i];
645 int old_level = levels[i-1];
646 torture_assert_int_equal(tctx, ctx->monitor_count[level], ctx->monitor_count[old_level],
647 "EnumMonitors invalid value");
650 for (i=0;i<ARRAY_SIZE(levels);i++) {
651 int level = levels[i];
652 for (j=0;j<ctx->monitor_count[level];j++) {
653 union spoolss_MonitorInfo *cur = &ctx->monitors[level][j];
654 union spoolss_MonitorInfo *ref = &ctx->monitors[2][j];
655 switch (level) {
656 case 1:
657 COMPARE_STRING(tctx, cur->info1, ref->info2, monitor_name);
658 break;
659 case 2:
660 /* level 2 is our reference, and it makes no sense to compare it to itself */
661 break;
666 return true;
669 static bool test_EnumPrintProcessors(struct torture_context *tctx,
670 struct dcerpc_binding_handle *b,
671 struct test_spoolss_context *ctx,
672 const char *environment)
674 NTSTATUS status;
675 struct spoolss_EnumPrintProcessors r;
676 uint16_t levels[] = { 1 };
677 int i, j;
679 for (i=0;i<ARRAY_SIZE(levels);i++) {
680 int level = levels[i];
681 DATA_BLOB blob;
682 uint32_t needed;
683 uint32_t count;
684 union spoolss_PrintProcessorInfo *info;
686 r.in.servername = "";
687 r.in.environment = environment;
688 r.in.level = level;
689 r.in.buffer = NULL;
690 r.in.offered = 0;
691 r.out.needed = &needed;
692 r.out.count = &count;
693 r.out.info = &info;
695 torture_comment(tctx, "Testing EnumPrintProcessors level %u\n", r.in.level);
697 status = dcerpc_spoolss_EnumPrintProcessors_r(b, ctx, &r);
698 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EnumPrintProcessors failed");
699 if (W_ERROR_IS_OK(r.out.result)) {
700 /* TODO: do some more checks here */
701 continue;
703 torture_assert_werr_equal(tctx, r.out.result, WERR_INSUFFICIENT_BUFFER,
704 "EnumPrintProcessors unexpected return code");
706 blob = data_blob_talloc(ctx, NULL, needed);
707 data_blob_clear(&blob);
708 r.in.buffer = &blob;
709 r.in.offered = needed;
711 status = dcerpc_spoolss_EnumPrintProcessors_r(b, ctx, &r);
712 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EnumPrintProcessors failed");
714 torture_assert_werr_ok(tctx, r.out.result, "EnumPrintProcessors failed");
716 CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumPrintProcessors, info, r.in.level, count, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
718 ctx->print_processor_count[level] = count;
719 ctx->print_processors[level] = info;
722 for (i=1;i<ARRAY_SIZE(levels);i++) {
723 int level = levels[i];
724 int old_level = levels[i-1];
725 torture_assert_int_equal(tctx, ctx->print_processor_count[level], ctx->print_processor_count[old_level],
726 "EnumPrintProcessors failed");
729 for (i=0;i<ARRAY_SIZE(levels);i++) {
730 int level = levels[i];
731 for (j=0;j<ctx->print_processor_count[level];j++) {
732 #if 0
733 union spoolss_PrintProcessorInfo *cur = &ctx->print_processors[level][j];
734 union spoolss_PrintProcessorInfo *ref = &ctx->print_processors[1][j];
735 #endif
736 switch (level) {
737 case 1:
738 /* level 1 is our reference, and it makes no sense to compare it to itself */
739 break;
744 return true;
747 static bool test_EnumPrintProcDataTypes(struct torture_context *tctx,
748 struct dcerpc_binding_handle *b,
749 struct test_spoolss_context *ctx)
751 NTSTATUS status;
752 struct spoolss_EnumPrintProcDataTypes r;
753 uint16_t levels[] = { 1 };
754 int i;
756 for (i=0;i<ARRAY_SIZE(levels);i++) {
757 int level = levels[i];
758 DATA_BLOB blob;
759 uint32_t needed;
760 uint32_t count;
761 union spoolss_PrintProcDataTypesInfo *info;
763 r.in.servername = "";
764 r.in.print_processor_name = "winprint";
765 r.in.level = level;
766 r.in.buffer = NULL;
767 r.in.offered = 0;
768 r.out.needed = &needed;
769 r.out.count = &count;
770 r.out.info = &info;
772 torture_comment(tctx, "Testing EnumPrintProcDataTypes level %u\n", r.in.level);
774 status = dcerpc_spoolss_EnumPrintProcDataTypes_r(b, ctx, &r);
775 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EnumPrintProcDataType failed");
776 if (W_ERROR_IS_OK(r.out.result)) {
777 /* TODO: do some more checks here */
778 continue;
780 torture_assert_werr_equal(tctx, r.out.result, WERR_INSUFFICIENT_BUFFER,
781 "EnumPrintProcDataTypes unexpected return code");
783 blob = data_blob_talloc(ctx, NULL, needed);
784 data_blob_clear(&blob);
785 r.in.buffer = &blob;
786 r.in.offered = needed;
788 status = dcerpc_spoolss_EnumPrintProcDataTypes_r(b, ctx, &r);
789 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EnumPrintProcDataTypes failed");
791 torture_assert_werr_ok(tctx, r.out.result, "EnumPrintProcDataTypes failed");
793 CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumPrintProcDataTypes, info, r.in.level, count, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
797 return true;
801 static bool test_EnumPrinters(struct torture_context *tctx,
802 struct dcerpc_binding_handle *b,
803 struct test_spoolss_context *ctx)
805 struct spoolss_EnumPrinters r;
806 NTSTATUS status;
807 uint16_t levels[] = { 0, 1, 2, 4, 5 };
808 int i, j;
810 for (i=0;i<ARRAY_SIZE(levels);i++) {
811 int level = levels[i];
812 DATA_BLOB blob;
813 uint32_t needed;
814 uint32_t count;
815 union spoolss_PrinterInfo *info;
817 r.in.flags = PRINTER_ENUM_LOCAL;
818 r.in.server = "";
819 r.in.level = level;
820 r.in.buffer = NULL;
821 r.in.offered = 0;
822 r.out.needed = &needed;
823 r.out.count = &count;
824 r.out.info = &info;
826 torture_comment(tctx, "Testing EnumPrinters level %u\n", r.in.level);
828 status = dcerpc_spoolss_EnumPrinters_r(b, ctx, &r);
829 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EnumPrinters failed");
830 if (W_ERROR_IS_OK(r.out.result)) {
831 /* TODO: do some more checks here */
832 continue;
834 torture_assert_werr_equal(tctx, r.out.result, WERR_INSUFFICIENT_BUFFER,
835 "EnumPrinters unexpected return code");
837 blob = data_blob_talloc(ctx, NULL, needed);
838 data_blob_clear(&blob);
839 r.in.buffer = &blob;
840 r.in.offered = needed;
842 status = dcerpc_spoolss_EnumPrinters_r(b, ctx, &r);
843 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EnumPrinters failed");
845 torture_assert_werr_ok(tctx, r.out.result, "EnumPrinters failed");
847 CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumPrinters, info, r.in.level, count, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
849 ctx->printer_count[level] = count;
850 ctx->printers[level] = info;
853 for (i=1;i<ARRAY_SIZE(levels);i++) {
854 int level = levels[i];
855 int old_level = levels[i-1];
856 torture_assert_int_equal(tctx, ctx->printer_count[level], ctx->printer_count[old_level],
857 "EnumPrinters invalid value");
860 for (i=0;i<ARRAY_SIZE(levels);i++) {
861 int level = levels[i];
862 for (j=0;j<ctx->printer_count[level];j++) {
863 union spoolss_PrinterInfo *cur = &ctx->printers[level][j];
864 union spoolss_PrinterInfo *ref = &ctx->printers[2][j];
865 switch (level) {
866 case 0:
867 COMPARE_STRING(tctx, cur->info0, ref->info2, printername);
868 COMPARE_STRING(tctx, cur->info0, ref->info2, servername);
869 COMPARE_UINT32(tctx, cur->info0, ref->info2, cjobs);
870 /*COMPARE_UINT32(tctx, cur->info0, ref->info2, total_jobs);
871 COMPARE_UINT32(tctx, cur->info0, ref->info2, total_bytes);
872 COMPARE_SPOOLSS_TIME(cur->info0, ref->info2, spoolss_Time time);
873 COMPARE_UINT32(tctx, cur->info0, ref->info2, global_counter);
874 COMPARE_UINT32(tctx, cur->info0, ref->info2, total_pages);
875 COMPARE_UINT32(tctx, cur->info0, ref->info2, version);
876 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown10);
877 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown11);
878 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown12);
879 COMPARE_UINT32(tctx, cur->info0, ref->info2, session_counter);
880 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown14);
881 COMPARE_UINT32(tctx, cur->info0, ref->info2, printer_errors);
882 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown16);
883 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown17);
884 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown18);
885 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown19);
886 COMPARE_UINT32(tctx, cur->info0, ref->info2, change_id);
887 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown21);*/
888 COMPARE_UINT32(tctx, cur->info0, ref->info2, status);
889 /*COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown23);
890 COMPARE_UINT32(tctx, cur->info0, ref->info2, c_setprinter);
891 COMPARE_UINT16(cur->info0, ref->info2, unknown25);
892 COMPARE_UINT16(cur->info0, ref->info2, unknown26);
893 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown27);
894 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown28);
895 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown29);*/
896 break;
897 case 1:
898 /*COMPARE_UINT32(tctx, cur->info1, ref->info2, flags);*/
899 /*COMPARE_STRING(tctx, cur->info1, ref->info2, name);*/
900 /*COMPARE_STRING(tctx, cur->info1, ref->info2, description);*/
901 COMPARE_STRING(tctx, cur->info1, ref->info2, comment);
902 break;
903 case 2:
904 /* level 2 is our reference, and it makes no sense to compare it to itself */
905 break;
906 case 4:
907 COMPARE_STRING(tctx, cur->info4, ref->info2, printername);
908 COMPARE_STRING(tctx, cur->info4, ref->info2, servername);
909 COMPARE_UINT32(tctx, cur->info4, ref->info2, attributes);
910 break;
911 case 5:
912 COMPARE_STRING(tctx, cur->info5, ref->info2, printername);
913 COMPARE_STRING(tctx, cur->info5, ref->info2, portname);
914 COMPARE_UINT32(tctx, cur->info5, ref->info2, attributes);
915 /*COMPARE_UINT32(tctx, cur->info5, ref->info2, device_not_selected_timeout);
916 COMPARE_UINT32(tctx, cur->info5, ref->info2, transmission_retry_timeout);*/
917 break;
922 /* TODO:
923 * - verify that the port of a printer was in the list returned by EnumPorts
926 return true;
929 static bool test_GetPrinterDriver2(struct torture_context *tctx,
930 struct dcerpc_binding_handle *b,
931 struct policy_handle *handle,
932 const char *driver_name,
933 const char *environment);
935 bool test_GetPrinter_level(struct torture_context *tctx,
936 struct dcerpc_binding_handle *b,
937 struct policy_handle *handle,
938 uint32_t level,
939 union spoolss_PrinterInfo *info)
941 struct spoolss_GetPrinter r;
942 uint32_t needed;
944 r.in.handle = handle;
945 r.in.level = level;
946 r.in.buffer = NULL;
947 r.in.offered = 0;
948 r.out.needed = &needed;
950 torture_comment(tctx, "Testing GetPrinter level %u\n", r.in.level);
952 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_GetPrinter_r(b, tctx, &r),
953 "GetPrinter failed");
955 if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
956 DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed);
957 data_blob_clear(&blob);
958 r.in.buffer = &blob;
959 r.in.offered = needed;
961 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_GetPrinter_r(b, tctx, &r),
962 "GetPrinter failed");
965 torture_assert_werr_ok(tctx, r.out.result, "GetPrinter failed");
967 CHECK_NEEDED_SIZE_LEVEL(spoolss_PrinterInfo, r.out.info, r.in.level, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
969 if (info && r.out.info) {
970 *info = *r.out.info;
973 return true;
977 static bool test_GetPrinter(struct torture_context *tctx,
978 struct dcerpc_binding_handle *b,
979 struct policy_handle *handle,
980 const char *environment)
982 uint32_t levels[] = {0, 1, 2, 3, 4, 5, 6, 7, 8};
983 int i;
985 for (i=0;i<ARRAY_SIZE(levels);i++) {
987 union spoolss_PrinterInfo info;
989 ZERO_STRUCT(info);
991 torture_assert(tctx, test_GetPrinter_level(tctx, b, handle, levels[i], &info),
992 "failed to call GetPrinter");
994 if ((levels[i] == 2) && info.info2.drivername && strlen(info.info2.drivername)) {
995 torture_assert(tctx,
996 test_GetPrinterDriver2(tctx, b, handle, info.info2.drivername, environment),
997 "failed to call test_GetPrinterDriver2");
1001 return true;
1004 static bool test_SetPrinter(struct torture_context *tctx,
1005 struct dcerpc_binding_handle *b,
1006 struct policy_handle *handle,
1007 struct spoolss_SetPrinterInfoCtr *info_ctr,
1008 struct spoolss_DevmodeContainer *devmode_ctr,
1009 struct sec_desc_buf *secdesc_ctr,
1010 enum spoolss_PrinterControl command)
1012 struct spoolss_SetPrinter r;
1014 r.in.handle = handle;
1015 r.in.info_ctr = info_ctr;
1016 r.in.devmode_ctr = devmode_ctr;
1017 r.in.secdesc_ctr = secdesc_ctr;
1018 r.in.command = command;
1020 torture_comment(tctx, "Testing SetPrinter level %d\n", r.in.info_ctr->level);
1022 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_SetPrinter_r(b, tctx, &r),
1023 "failed to call SetPrinter");
1024 torture_assert_werr_ok(tctx, r.out.result,
1025 "failed to call SetPrinter");
1027 return true;
1030 static bool test_SetPrinter_errors(struct torture_context *tctx,
1031 struct dcerpc_binding_handle *b,
1032 struct policy_handle *handle)
1034 struct spoolss_SetPrinter r;
1035 uint16_t levels[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
1036 int i;
1038 struct spoolss_SetPrinterInfoCtr info_ctr;
1039 struct spoolss_DevmodeContainer devmode_ctr;
1040 struct sec_desc_buf secdesc_ctr;
1042 info_ctr.level = 0;
1043 info_ctr.info.info0 = NULL;
1045 ZERO_STRUCT(devmode_ctr);
1046 ZERO_STRUCT(secdesc_ctr);
1048 r.in.handle = handle;
1049 r.in.info_ctr = &info_ctr;
1050 r.in.devmode_ctr = &devmode_ctr;
1051 r.in.secdesc_ctr = &secdesc_ctr;
1052 r.in.command = 0;
1054 torture_comment(tctx, "Testing SetPrinter all zero\n");
1056 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_SetPrinter_r(b, tctx, &r),
1057 "failed to call SetPrinter");
1058 torture_assert_werr_equal(tctx, r.out.result, WERR_INVALID_PARAM,
1059 "failed to call SetPrinter");
1061 again:
1062 for (i=0; i < ARRAY_SIZE(levels); i++) {
1064 struct spoolss_SetPrinterInfo0 info0;
1065 struct spoolss_SetPrinterInfo1 info1;
1066 struct spoolss_SetPrinterInfo2 info2;
1067 struct spoolss_SetPrinterInfo3 info3;
1068 struct spoolss_SetPrinterInfo4 info4;
1069 struct spoolss_SetPrinterInfo5 info5;
1070 struct spoolss_SetPrinterInfo6 info6;
1071 struct spoolss_SetPrinterInfo7 info7;
1072 struct spoolss_SetPrinterInfo8 info8;
1073 struct spoolss_SetPrinterInfo9 info9;
1076 info_ctr.level = levels[i];
1077 switch (levels[i]) {
1078 case 0:
1079 ZERO_STRUCT(info0);
1080 info_ctr.info.info0 = &info0;
1081 break;
1082 case 1:
1083 ZERO_STRUCT(info1);
1084 info_ctr.info.info1 = &info1;
1085 break;
1086 case 2:
1087 ZERO_STRUCT(info2);
1088 info_ctr.info.info2 = &info2;
1089 break;
1090 case 3:
1091 ZERO_STRUCT(info3);
1092 info_ctr.info.info3 = &info3;
1093 break;
1094 case 4:
1095 ZERO_STRUCT(info4);
1096 info_ctr.info.info4 = &info4;
1097 break;
1098 case 5:
1099 ZERO_STRUCT(info5);
1100 info_ctr.info.info5 = &info5;
1101 break;
1102 case 6:
1103 ZERO_STRUCT(info6);
1104 info_ctr.info.info6 = &info6;
1105 break;
1106 case 7:
1107 ZERO_STRUCT(info7);
1108 info_ctr.info.info7 = &info7;
1109 break;
1110 case 8:
1111 ZERO_STRUCT(info8);
1112 info_ctr.info.info8 = &info8;
1113 break;
1114 case 9:
1115 ZERO_STRUCT(info9);
1116 info_ctr.info.info9 = &info9;
1117 break;
1120 torture_comment(tctx, "Testing SetPrinter level %d, command %d\n",
1121 info_ctr.level, r.in.command);
1123 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_SetPrinter_r(b, tctx, &r),
1124 "failed to call SetPrinter");
1126 switch (r.in.command) {
1127 case SPOOLSS_PRINTER_CONTROL_UNPAUSE: /* 0 */
1128 /* is ignored for all levels other then 0 */
1129 if (info_ctr.level > 0) {
1130 /* ignored then */
1131 break;
1133 case SPOOLSS_PRINTER_CONTROL_PAUSE: /* 1 */
1134 case SPOOLSS_PRINTER_CONTROL_RESUME: /* 2 */
1135 case SPOOLSS_PRINTER_CONTROL_PURGE: /* 3 */
1136 if (info_ctr.level > 0) {
1137 /* is invalid for all levels other then 0 */
1138 torture_assert_werr_equal(tctx, r.out.result, WERR_INVALID_PRINTER_COMMAND,
1139 "unexpected error code returned");
1140 continue;
1141 } else {
1142 torture_assert_werr_ok(tctx, r.out.result,
1143 "failed to call SetPrinter with non 0 command");
1144 continue;
1146 break;
1148 case SPOOLSS_PRINTER_CONTROL_SET_STATUS: /* 4 */
1149 /* FIXME: gd needs further investigation */
1150 default:
1151 torture_assert_werr_equal(tctx, r.out.result, WERR_INVALID_PRINTER_COMMAND,
1152 "unexpected error code returned");
1153 continue;
1156 switch (info_ctr.level) {
1157 case 1:
1158 torture_assert_werr_equal(tctx, r.out.result, WERR_UNKNOWN_LEVEL,
1159 "unexpected error code returned");
1160 break;
1161 case 2:
1162 torture_assert_werr_equal(tctx, r.out.result, WERR_UNKNOWN_PRINTER_DRIVER,
1163 "unexpected error code returned");
1164 break;
1165 case 3:
1166 case 4:
1167 case 5:
1168 case 7:
1169 torture_assert_werr_equal(tctx, r.out.result, WERR_INVALID_PARAM,
1170 "unexpected error code returned");
1171 break;
1172 case 9:
1173 torture_assert_werr_equal(tctx, r.out.result, WERR_NOT_SUPPORTED,
1174 "unexpected error code returned");
1175 break;
1176 default:
1177 torture_assert_werr_ok(tctx, r.out.result,
1178 "failed to call SetPrinter");
1179 break;
1183 if (r.in.command < 5) {
1184 r.in.command++;
1185 goto again;
1188 return true;
1191 static void clear_info2(struct spoolss_SetPrinterInfoCtr *r)
1193 if ((r->level == 2) && (r->info.info2)) {
1194 r->info.info2->secdesc_ptr = 0;
1195 r->info.info2->devmode_ptr = 0;
1199 static bool test_PrinterInfo(struct torture_context *tctx,
1200 struct dcerpc_binding_handle *b,
1201 struct policy_handle *handle)
1203 NTSTATUS status;
1204 struct spoolss_SetPrinter s;
1205 struct spoolss_GetPrinter q;
1206 struct spoolss_GetPrinter q0;
1207 struct spoolss_SetPrinterInfoCtr info_ctr;
1208 union spoolss_PrinterInfo info;
1209 struct spoolss_DevmodeContainer devmode_ctr;
1210 struct sec_desc_buf secdesc_ctr;
1211 uint32_t needed;
1212 bool ret = true;
1213 int i;
1215 uint32_t status_list[] = {
1216 /* these do not stick
1217 PRINTER_STATUS_PAUSED,
1218 PRINTER_STATUS_ERROR,
1219 PRINTER_STATUS_PENDING_DELETION, */
1220 PRINTER_STATUS_PAPER_JAM,
1221 PRINTER_STATUS_PAPER_OUT,
1222 PRINTER_STATUS_MANUAL_FEED,
1223 PRINTER_STATUS_PAPER_PROBLEM,
1224 PRINTER_STATUS_OFFLINE,
1225 PRINTER_STATUS_IO_ACTIVE,
1226 PRINTER_STATUS_BUSY,
1227 PRINTER_STATUS_PRINTING,
1228 PRINTER_STATUS_OUTPUT_BIN_FULL,
1229 PRINTER_STATUS_NOT_AVAILABLE,
1230 PRINTER_STATUS_WAITING,
1231 PRINTER_STATUS_PROCESSING,
1232 PRINTER_STATUS_INITIALIZING,
1233 PRINTER_STATUS_WARMING_UP,
1234 PRINTER_STATUS_TONER_LOW,
1235 PRINTER_STATUS_NO_TONER,
1236 PRINTER_STATUS_PAGE_PUNT,
1237 PRINTER_STATUS_USER_INTERVENTION,
1238 PRINTER_STATUS_OUT_OF_MEMORY,
1239 PRINTER_STATUS_DOOR_OPEN,
1240 PRINTER_STATUS_SERVER_UNKNOWN,
1241 PRINTER_STATUS_POWER_SAVE,
1242 /* these do not stick
1243 0x02000000,
1244 0x04000000,
1245 0x08000000,
1246 0x10000000,
1247 0x20000000,
1248 0x40000000,
1249 0x80000000 */
1251 uint32_t default_attribute = PRINTER_ATTRIBUTE_LOCAL;
1252 uint32_t attribute_list[] = {
1253 PRINTER_ATTRIBUTE_QUEUED,
1254 /* fails with WERR_INVALID_DATATYPE:
1255 PRINTER_ATTRIBUTE_DIRECT, */
1256 /* does not stick
1257 PRINTER_ATTRIBUTE_DEFAULT, */
1258 PRINTER_ATTRIBUTE_SHARED,
1259 /* does not stick
1260 PRINTER_ATTRIBUTE_NETWORK, */
1261 PRINTER_ATTRIBUTE_HIDDEN,
1262 PRINTER_ATTRIBUTE_LOCAL,
1263 PRINTER_ATTRIBUTE_ENABLE_DEVQ,
1264 PRINTER_ATTRIBUTE_KEEPPRINTEDJOBS,
1265 PRINTER_ATTRIBUTE_DO_COMPLETE_FIRST,
1266 PRINTER_ATTRIBUTE_WORK_OFFLINE,
1267 /* does not stick
1268 PRINTER_ATTRIBUTE_ENABLE_BIDI, */
1269 /* fails with WERR_INVALID_DATATYPE:
1270 PRINTER_ATTRIBUTE_RAW_ONLY, */
1271 /* these do not stick
1272 PRINTER_ATTRIBUTE_PUBLISHED,
1273 PRINTER_ATTRIBUTE_FAX,
1274 PRINTER_ATTRIBUTE_TS,
1275 0x00010000,
1276 0x00020000,
1277 0x00040000,
1278 0x00080000,
1279 0x00100000,
1280 0x00200000,
1281 0x00400000,
1282 0x00800000,
1283 0x01000000,
1284 0x02000000,
1285 0x04000000,
1286 0x08000000,
1287 0x10000000,
1288 0x20000000,
1289 0x40000000,
1290 0x80000000 */
1293 ZERO_STRUCT(devmode_ctr);
1294 ZERO_STRUCT(secdesc_ctr);
1296 s.in.handle = handle;
1297 s.in.command = 0;
1298 s.in.info_ctr = &info_ctr;
1299 s.in.devmode_ctr = &devmode_ctr;
1300 s.in.secdesc_ctr = &secdesc_ctr;
1302 q.in.handle = handle;
1303 q.out.info = &info;
1304 q0 = q;
1306 #define TESTGETCALL(call, r) \
1307 r.in.buffer = NULL; \
1308 r.in.offered = 0;\
1309 r.out.needed = &needed; \
1310 status = dcerpc_spoolss_ ##call## _r(b, tctx, &r); \
1311 if (!NT_STATUS_IS_OK(status)) { \
1312 torture_comment(tctx, #call " level %u failed - %s (%s)\n", \
1313 r.in.level, nt_errstr(status), __location__); \
1314 ret = false; \
1315 break; \
1317 if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {\
1318 DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed); \
1319 data_blob_clear(&blob); \
1320 r.in.buffer = &blob; \
1321 r.in.offered = needed; \
1323 status = dcerpc_spoolss_ ##call## _r(b, tctx, &r); \
1324 if (!NT_STATUS_IS_OK(status)) { \
1325 torture_comment(tctx, #call " level %u failed - %s (%s)\n", \
1326 r.in.level, nt_errstr(status), __location__); \
1327 ret = false; \
1328 break; \
1330 if (!W_ERROR_IS_OK(r.out.result)) { \
1331 torture_comment(tctx, #call " level %u failed - %s (%s)\n", \
1332 r.in.level, win_errstr(r.out.result), __location__); \
1333 ret = false; \
1334 break; \
1338 #define TESTSETCALL_EXP(call, r, err) \
1339 clear_info2(&info_ctr);\
1340 status = dcerpc_spoolss_ ##call## _r(b, tctx, &r); \
1341 if (!NT_STATUS_IS_OK(status)) { \
1342 torture_comment(tctx, #call " level %u failed - %s (%s)\n", \
1343 r.in.info_ctr->level, nt_errstr(status), __location__); \
1344 ret = false; \
1345 break; \
1347 if (!W_ERROR_IS_OK(err)) { \
1348 if (!W_ERROR_EQUAL(err, r.out.result)) { \
1349 torture_comment(tctx, #call " level %u failed - %s, expected %s (%s)\n", \
1350 r.in.info_ctr->level, win_errstr(r.out.result), win_errstr(err), __location__); \
1351 ret = false; \
1353 break; \
1355 if (!W_ERROR_IS_OK(r.out.result)) { \
1356 torture_comment(tctx, #call " level %u failed - %s (%s)\n", \
1357 r.in.info_ctr->level, win_errstr(r.out.result), __location__); \
1358 ret = false; \
1359 break; \
1362 #define TESTSETCALL(call, r) \
1363 TESTSETCALL_EXP(call, r, WERR_OK)
1365 #define STRING_EQUAL(s1, s2, field) \
1366 if ((s1 && !s2) || (s2 && !s1) || strcmp(s1, s2)) { \
1367 torture_comment(tctx, "Failed to set %s to '%s' (%s)\n", \
1368 #field, s2, __location__); \
1369 ret = false; \
1370 break; \
1373 #define MEM_EQUAL(s1, s2, length, field) \
1374 if ((s1 && !s2) || (s2 && !s1) || memcmp(s1, s2, length)) { \
1375 torture_comment(tctx, "Failed to set %s to '%s' (%s)\n", \
1376 #field, (const char *)s2, __location__); \
1377 ret = false; \
1378 break; \
1381 #define INT_EQUAL(i1, i2, field) \
1382 if (i1 != i2) { \
1383 torture_comment(tctx, "Failed to set %s to 0x%llx - got 0x%llx (%s)\n", \
1384 #field, (unsigned long long)i2, (unsigned long long)i1, __location__); \
1385 ret = false; \
1386 break; \
1389 #define SD_EQUAL(sd1, sd2, field) \
1390 if (!security_descriptor_equal(sd1, sd2)) { \
1391 torture_comment(tctx, "Failed to set %s (%s)\n", \
1392 #field, __location__); \
1393 ret = false; \
1394 break; \
1397 #define TEST_PRINTERINFO_STRING_EXP_ERR(lvl1, field1, lvl2, field2, value, err) do { \
1398 torture_comment(tctx, "field test %d/%s vs %d/%s\n", lvl1, #field1, lvl2, #field2); \
1399 q.in.level = lvl1; \
1400 TESTGETCALL(GetPrinter, q) \
1401 info_ctr.level = lvl1; \
1402 info_ctr.info.info ## lvl1 = (struct spoolss_SetPrinterInfo ## lvl1 *)(void *)&q.out.info->info ## lvl1; \
1403 info_ctr.info.info ## lvl1->field1 = value;\
1404 TESTSETCALL_EXP(SetPrinter, s, err) \
1405 info_ctr.info.info ## lvl1->field1 = ""; \
1406 TESTGETCALL(GetPrinter, q) \
1407 info_ctr.info.info ## lvl1->field1 = value; \
1408 STRING_EQUAL(info_ctr.info.info ## lvl1->field1, value, field1); \
1409 q.in.level = lvl2; \
1410 TESTGETCALL(GetPrinter, q) \
1411 info_ctr.info.info ## lvl2 = (struct spoolss_SetPrinterInfo ## lvl2 *)(void *)&q.out.info->info ## lvl2; \
1412 STRING_EQUAL(info_ctr.info.info ## lvl2->field2, value, field2); \
1413 } while (0)
1415 #define TEST_PRINTERINFO_STRING(lvl1, field1, lvl2, field2, value) do { \
1416 TEST_PRINTERINFO_STRING_EXP_ERR(lvl1, field1, lvl2, field2, value, WERR_OK); \
1417 } while (0);
1419 #define TEST_PRINTERINFO_INT_EXP(lvl1, field1, lvl2, field2, value, exp_value) do { \
1420 torture_comment(tctx, "field test %d/%s vs %d/%s\n", lvl1, #field1, lvl2, #field2); \
1421 q.in.level = lvl1; \
1422 TESTGETCALL(GetPrinter, q) \
1423 info_ctr.level = lvl1; \
1424 info_ctr.info.info ## lvl1 = (struct spoolss_SetPrinterInfo ## lvl1 *)(void *)&q.out.info->info ## lvl1; \
1425 info_ctr.info.info ## lvl1->field1 = value; \
1426 TESTSETCALL(SetPrinter, s) \
1427 info_ctr.info.info ## lvl1->field1 = 0; \
1428 TESTGETCALL(GetPrinter, q) \
1429 info_ctr.info.info ## lvl1 = (struct spoolss_SetPrinterInfo ## lvl1 *)(void *)&q.out.info->info ## lvl1; \
1430 INT_EQUAL(info_ctr.info.info ## lvl1->field1, exp_value, field1); \
1431 q.in.level = lvl2; \
1432 TESTGETCALL(GetPrinter, q) \
1433 info_ctr.info.info ## lvl2 = (struct spoolss_SetPrinterInfo ## lvl2 *)(void *)&q.out.info->info ## lvl2; \
1434 INT_EQUAL(info_ctr.info.info ## lvl2->field2, exp_value, field1); \
1435 } while (0)
1437 #define TEST_PRINTERINFO_INT(lvl1, field1, lvl2, field2, value) do { \
1438 TEST_PRINTERINFO_INT_EXP(lvl1, field1, lvl2, field2, value, value); \
1439 } while (0)
1441 q0.in.level = 0;
1442 do { TESTGETCALL(GetPrinter, q0) } while (0);
1444 TEST_PRINTERINFO_STRING(2, comment, 1, comment, "xx2-1 comment");
1445 TEST_PRINTERINFO_STRING(2, comment, 2, comment, "xx2-2 comment");
1447 /* level 0 printername does not stick */
1448 /* TEST_PRINTERINFO_STRING(2, printername, 0, printername, "xx2-0 printer"); */
1449 TEST_PRINTERINFO_STRING(2, printername, 1, name, "xx2-1 printer");
1450 TEST_PRINTERINFO_STRING(2, printername, 2, printername, "xx2-2 printer");
1451 TEST_PRINTERINFO_STRING(2, printername, 4, printername, "xx2-4 printer");
1452 TEST_PRINTERINFO_STRING(2, printername, 5, printername, "xx2-5 printer");
1453 /* TEST_PRINTERINFO_STRING(4, printername, 0, printername, "xx4-0 printer"); */
1454 TEST_PRINTERINFO_STRING(4, printername, 1, name, "xx4-1 printer");
1455 TEST_PRINTERINFO_STRING(4, printername, 2, printername, "xx4-2 printer");
1456 TEST_PRINTERINFO_STRING(4, printername, 4, printername, "xx4-4 printer");
1457 TEST_PRINTERINFO_STRING(4, printername, 5, printername, "xx4-5 printer");
1458 /* TEST_PRINTERINFO_STRING(5, printername, 0, printername, "xx5-0 printer"); */
1459 TEST_PRINTERINFO_STRING(5, printername, 1, name, "xx5-1 printer");
1460 TEST_PRINTERINFO_STRING(5, printername, 2, printername, "xx5-2 printer");
1461 TEST_PRINTERINFO_STRING(5, printername, 4, printername, "xx5-4 printer");
1462 TEST_PRINTERINFO_STRING(5, printername, 5, printername, "xx5-5 printer");
1464 /* servername can be set but does not stick
1465 TEST_PRINTERINFO_STRING(2, servername, 0, servername, "xx2-0 servername");
1466 TEST_PRINTERINFO_STRING(2, servername, 2, servername, "xx2-2 servername");
1467 TEST_PRINTERINFO_STRING(2, servername, 4, servername, "xx2-4 servername");
1470 /* passing an invalid port will result in WERR_UNKNOWN_PORT */
1471 TEST_PRINTERINFO_STRING_EXP_ERR(2, portname, 2, portname, "xx2-2 portname", WERR_UNKNOWN_PORT);
1472 TEST_PRINTERINFO_STRING_EXP_ERR(2, portname, 5, portname, "xx2-5 portname", WERR_UNKNOWN_PORT);
1473 TEST_PRINTERINFO_STRING_EXP_ERR(5, portname, 2, portname, "xx5-2 portname", WERR_UNKNOWN_PORT);
1474 TEST_PRINTERINFO_STRING_EXP_ERR(5, portname, 5, portname, "xx5-5 portname", WERR_UNKNOWN_PORT);
1476 TEST_PRINTERINFO_STRING(2, sharename, 2, sharename, "xx2-2 sharename");
1477 /* passing an invalid driver will result in WERR_UNKNOWN_PRINTER_DRIVER */
1478 TEST_PRINTERINFO_STRING_EXP_ERR(2, drivername, 2, drivername, "xx2-2 drivername", WERR_UNKNOWN_PRINTER_DRIVER);
1479 TEST_PRINTERINFO_STRING(2, location, 2, location, "xx2-2 location");
1480 /* passing an invalid sepfile will result in WERR_INVALID_SEPARATOR_FILE */
1481 TEST_PRINTERINFO_STRING_EXP_ERR(2, sepfile, 2, sepfile, "xx2-2 sepfile", WERR_INVALID_SEPARATOR_FILE);
1482 /* passing an invalid printprocessor will result in WERR_UNKNOWN_PRINTPROCESSOR */
1483 TEST_PRINTERINFO_STRING_EXP_ERR(2, printprocessor, 2, printprocessor, "xx2-2 printprocessor", WERR_UNKNOWN_PRINTPROCESSOR);
1484 TEST_PRINTERINFO_STRING(2, datatype, 2, datatype, "xx2-2 datatype");
1485 TEST_PRINTERINFO_STRING(2, parameters, 2, parameters, "xx2-2 parameters");
1487 for (i=0; i < ARRAY_SIZE(attribute_list); i++) {
1488 /* TEST_PRINTERINFO_INT_EXP(2, attributes, 1, flags,
1489 attribute_list[i],
1490 (attribute_list[i] | default_attribute)
1491 ); */
1492 TEST_PRINTERINFO_INT_EXP(2, attributes, 2, attributes,
1493 attribute_list[i],
1494 (attribute_list[i] | default_attribute)
1496 TEST_PRINTERINFO_INT_EXP(2, attributes, 4, attributes,
1497 attribute_list[i],
1498 (attribute_list[i] | default_attribute)
1500 TEST_PRINTERINFO_INT_EXP(2, attributes, 5, attributes,
1501 attribute_list[i],
1502 (attribute_list[i] | default_attribute)
1504 /* TEST_PRINTERINFO_INT_EXP(4, attributes, 1, flags,
1505 attribute_list[i],
1506 (attribute_list[i] | default_attribute)
1507 ); */
1508 TEST_PRINTERINFO_INT_EXP(4, attributes, 2, attributes,
1509 attribute_list[i],
1510 (attribute_list[i] | default_attribute)
1512 TEST_PRINTERINFO_INT_EXP(4, attributes, 4, attributes,
1513 attribute_list[i],
1514 (attribute_list[i] | default_attribute)
1516 TEST_PRINTERINFO_INT_EXP(4, attributes, 5, attributes,
1517 attribute_list[i],
1518 (attribute_list[i] | default_attribute)
1520 /* TEST_PRINTERINFO_INT_EXP(5, attributes, 1, flags,
1521 attribute_list[i],
1522 (attribute_list[i] | default_attribute)
1523 ); */
1524 TEST_PRINTERINFO_INT_EXP(5, attributes, 2, attributes,
1525 attribute_list[i],
1526 (attribute_list[i] | default_attribute)
1528 TEST_PRINTERINFO_INT_EXP(5, attributes, 4, attributes,
1529 attribute_list[i],
1530 (attribute_list[i] | default_attribute)
1532 TEST_PRINTERINFO_INT_EXP(5, attributes, 5, attributes,
1533 attribute_list[i],
1534 (attribute_list[i] | default_attribute)
1538 for (i=0; i < ARRAY_SIZE(status_list); i++) {
1539 /* level 2 sets do not stick
1540 TEST_PRINTERINFO_INT(2, status, 0, status, status_list[i]);
1541 TEST_PRINTERINFO_INT(2, status, 2, status, status_list[i]);
1542 TEST_PRINTERINFO_INT(2, status, 6, status, status_list[i]); */
1543 TEST_PRINTERINFO_INT(6, status, 0, status, status_list[i]);
1544 TEST_PRINTERINFO_INT(6, status, 2, status, status_list[i]);
1545 TEST_PRINTERINFO_INT(6, status, 6, status, status_list[i]);
1548 /* priorities need to be between 0 and 99
1549 passing an invalid priority will result in WERR_INVALID_PRIORITY */
1550 TEST_PRINTERINFO_INT(2, priority, 2, priority, 0);
1551 TEST_PRINTERINFO_INT(2, priority, 2, priority, 1);
1552 TEST_PRINTERINFO_INT(2, priority, 2, priority, 99);
1553 /* TEST_PRINTERINFO_INT(2, priority, 2, priority, 100); */
1554 TEST_PRINTERINFO_INT(2, defaultpriority,2, defaultpriority, 0);
1555 TEST_PRINTERINFO_INT(2, defaultpriority,2, defaultpriority, 1);
1556 TEST_PRINTERINFO_INT(2, defaultpriority,2, defaultpriority, 99);
1557 /* TEST_PRINTERINFO_INT(2, defaultpriority,2, defaultpriority, 100); */
1559 TEST_PRINTERINFO_INT(2, starttime, 2, starttime, __LINE__);
1560 TEST_PRINTERINFO_INT(2, untiltime, 2, untiltime, __LINE__);
1562 /* does not stick
1563 TEST_PRINTERINFO_INT(2, cjobs, 2, cjobs, __LINE__);
1564 TEST_PRINTERINFO_INT(2, averageppm, 2, averageppm, __LINE__); */
1566 /* does not stick
1567 TEST_PRINTERINFO_INT(5, device_not_selected_timeout, 5, device_not_selected_timeout, __LINE__);
1568 TEST_PRINTERINFO_INT(5, transmission_retry_timeout, 5, transmission_retry_timeout, __LINE__); */
1570 /* FIXME: gd also test devmode and secdesc behavior */
1573 /* verify composition of level 1 description field */
1574 const char *description;
1575 const char *tmp;
1577 q0.in.level = 1;
1578 do { TESTGETCALL(GetPrinter, q0) } while (0);
1580 description = talloc_strdup(tctx, q0.out.info->info1.description);
1582 q0.in.level = 2;
1583 do { TESTGETCALL(GetPrinter, q0) } while (0);
1585 tmp = talloc_asprintf(tctx, "%s,%s,%s",
1586 q0.out.info->info2.printername,
1587 q0.out.info->info2.drivername,
1588 q0.out.info->info2.location);
1590 do { STRING_EQUAL(description, tmp, "description")} while (0);
1593 return ret;
1596 #define torture_assert_sid_equal(torture_ctx,got,expected,cmt)\
1597 do { struct dom_sid *__got = (got), *__expected = (expected); \
1598 if (!dom_sid_equal(__got, __expected)) { \
1599 torture_result(torture_ctx, TORTURE_FAIL, \
1600 __location__": "#got" was %s, expected %s: %s", \
1601 dom_sid_string(torture_ctx, __got), dom_sid_string(torture_ctx, __expected), cmt); \
1602 return false; \
1604 } while(0)
1606 static bool test_security_descriptor_equal(struct torture_context *tctx,
1607 const struct security_descriptor *sd1,
1608 const struct security_descriptor *sd2)
1610 if (sd1 == sd2) {
1611 return true;
1614 if (!sd1 || !sd2) {
1615 torture_comment(tctx, "%s\n", __location__);
1616 return false;
1619 torture_assert_int_equal(tctx, sd1->revision, sd2->revision, "revision mismatch");
1620 torture_assert_int_equal(tctx, sd1->type, sd2->type, "type mismatch");
1622 torture_assert_sid_equal(tctx, sd1->owner_sid, sd2->owner_sid, "owner mismatch");
1623 torture_assert_sid_equal(tctx, sd1->group_sid, sd2->group_sid, "group mismatch");
1625 if (!security_acl_equal(sd1->sacl, sd2->sacl)) {
1626 torture_comment(tctx, "%s: sacl mismatch\n", __location__);
1627 NDR_PRINT_DEBUG(security_acl, sd1->sacl);
1628 NDR_PRINT_DEBUG(security_acl, sd2->sacl);
1629 return false;
1631 if (!security_acl_equal(sd1->dacl, sd2->dacl)) {
1632 torture_comment(tctx, "%s: dacl mismatch\n", __location__);
1633 NDR_PRINT_DEBUG(security_acl, sd1->dacl);
1634 NDR_PRINT_DEBUG(security_acl, sd2->dacl);
1635 return false;
1638 return true;
1641 static bool test_sd_set_level(struct torture_context *tctx,
1642 struct dcerpc_binding_handle *b,
1643 struct policy_handle *handle,
1644 uint32_t level,
1645 struct security_descriptor *sd)
1647 struct spoolss_SetPrinterInfoCtr info_ctr;
1648 struct spoolss_DevmodeContainer devmode_ctr;
1649 struct sec_desc_buf secdesc_ctr;
1650 union spoolss_SetPrinterInfo sinfo;
1652 ZERO_STRUCT(devmode_ctr);
1653 ZERO_STRUCT(secdesc_ctr);
1655 switch (level) {
1656 case 2: {
1657 union spoolss_PrinterInfo info;
1658 torture_assert(tctx, test_GetPrinter_level(tctx, b, handle, 2, &info), "");
1659 torture_assert(tctx, PrinterInfo_to_SetPrinterInfo(tctx, &info, 2, &sinfo), "");
1661 info_ctr.level = 2;
1662 info_ctr.info = sinfo;
1664 break;
1666 case 3: {
1667 struct spoolss_SetPrinterInfo3 info3;
1669 info3.sec_desc_ptr = 0;
1671 info_ctr.level = 3;
1672 info_ctr.info.info3 = &info3;
1674 break;
1676 default:
1677 return false;
1680 secdesc_ctr.sd = sd;
1682 torture_assert(tctx,
1683 test_SetPrinter(tctx, b, handle, &info_ctr, &devmode_ctr, &secdesc_ctr, 0), "");
1685 return true;
1688 static bool test_PrinterInfo_SDs(struct torture_context *tctx,
1689 struct dcerpc_binding_handle *b,
1690 struct policy_handle *handle)
1692 union spoolss_PrinterInfo info;
1693 struct security_descriptor *sd1, *sd2;
1694 int i;
1696 /* just compare level 2 and level 3 */
1698 torture_assert(tctx, test_GetPrinter_level(tctx, b, handle, 2, &info), "");
1700 sd1 = info.info2.secdesc;
1702 torture_assert(tctx, test_GetPrinter_level(tctx, b, handle, 3, &info), "");
1704 sd2 = info.info3.secdesc;
1706 torture_assert(tctx, test_security_descriptor_equal(tctx, sd1, sd2),
1707 "SD level 2 != SD level 3");
1710 /* query level 2, set level 2, query level 2 */
1712 torture_assert(tctx, test_GetPrinter_level(tctx, b, handle, 2, &info), "");
1714 sd1 = info.info2.secdesc;
1716 torture_assert(tctx, test_sd_set_level(tctx, b, handle, 2, sd1), "");
1718 torture_assert(tctx, test_GetPrinter_level(tctx, b, handle, 2, &info), "");
1720 sd2 = info.info2.secdesc;
1721 if (sd1->type & SEC_DESC_DACL_DEFAULTED) {
1722 torture_comment(tctx, "removing SEC_DESC_DACL_DEFAULTED\n");
1723 sd1->type &= ~SEC_DESC_DACL_DEFAULTED;
1726 torture_assert(tctx, test_security_descriptor_equal(tctx, sd1, sd2),
1727 "SD level 2 != SD level 2 after SD has been set via level 2");
1730 /* query level 2, set level 3, query level 2 */
1732 torture_assert(tctx, test_GetPrinter_level(tctx, b, handle, 2, &info), "");
1734 sd1 = info.info2.secdesc;
1736 torture_assert(tctx, test_sd_set_level(tctx, b, handle, 3, sd1), "");
1738 torture_assert(tctx, test_GetPrinter_level(tctx, b, handle, 2, &info), "");
1740 sd2 = info.info2.secdesc;
1742 torture_assert(tctx, test_security_descriptor_equal(tctx, sd1, sd2),
1743 "SD level 2 != SD level 2 after SD has been set via level 3");
1745 /* set modified sd level 3, query level 2 */
1747 for (i=0; i < 93; i++) {
1748 struct security_ace a;
1749 const char *sid_string = talloc_asprintf(tctx, "S-1-5-32-9999%i", i);
1750 a.type = SEC_ACE_TYPE_ACCESS_ALLOWED;
1751 a.flags = 0;
1752 a.size = 0; /* autogenerated */
1753 a.access_mask = 0;
1754 a.trustee = *dom_sid_parse_talloc(tctx, sid_string);
1755 torture_assert_ntstatus_ok(tctx, security_descriptor_dacl_add(sd1, &a), "");
1758 torture_assert(tctx, test_sd_set_level(tctx, b, handle, 3, sd1), "");
1760 torture_assert(tctx, test_GetPrinter_level(tctx, b, handle, 2, &info), "");
1761 sd2 = info.info2.secdesc;
1763 if (sd1->type & SEC_DESC_DACL_DEFAULTED) {
1764 torture_comment(tctx, "removing SEC_DESC_DACL_DEFAULTED\n");
1765 sd1->type &= ~SEC_DESC_DACL_DEFAULTED;
1768 torture_assert(tctx, test_security_descriptor_equal(tctx, sd1, sd2),
1769 "modified SD level 2 != SD level 2 after SD has been set via level 3");
1772 return true;
1776 * wrapper call that saves original sd, runs tests, and restores sd
1779 static bool test_PrinterInfo_SD(struct torture_context *tctx,
1780 struct dcerpc_binding_handle *b,
1781 struct policy_handle *handle)
1783 union spoolss_PrinterInfo info;
1784 struct security_descriptor *sd;
1785 bool ret = true;
1787 torture_comment(tctx, "Testing Printer Security Descriptors\n");
1789 /* save original sd */
1791 torture_assert(tctx, test_GetPrinter_level(tctx, b, handle, 2, &info),
1792 "failed to get initial security descriptor");
1794 sd = security_descriptor_copy(tctx, info.info2.secdesc);
1796 /* run tests */
1798 ret = test_PrinterInfo_SDs(tctx, b, handle);
1800 /* restore original sd */
1802 torture_assert(tctx, test_sd_set_level(tctx, b, handle, 3, sd),
1803 "failed to restore initial security descriptor");
1805 torture_comment(tctx, "Printer Security Descriptors test %s\n\n",
1806 ret ? "succeeded" : "failed");
1809 return ret;
1812 static bool test_devmode_set_level(struct torture_context *tctx,
1813 struct dcerpc_binding_handle *b,
1814 struct policy_handle *handle,
1815 uint32_t level,
1816 struct spoolss_DeviceMode *devmode)
1818 struct spoolss_SetPrinterInfoCtr info_ctr;
1819 struct spoolss_DevmodeContainer devmode_ctr;
1820 struct sec_desc_buf secdesc_ctr;
1821 union spoolss_SetPrinterInfo sinfo;
1823 ZERO_STRUCT(devmode_ctr);
1824 ZERO_STRUCT(secdesc_ctr);
1826 switch (level) {
1827 case 2: {
1828 union spoolss_PrinterInfo info;
1829 torture_assert(tctx, test_GetPrinter_level(tctx, b, handle, 2, &info), "");
1830 torture_assert(tctx, PrinterInfo_to_SetPrinterInfo(tctx, &info, 2, &sinfo), "");
1832 info_ctr.level = 2;
1833 info_ctr.info = sinfo;
1835 break;
1837 case 8: {
1838 struct spoolss_SetPrinterInfo8 info8;
1840 info8.devmode_ptr = 0;
1842 info_ctr.level = 8;
1843 info_ctr.info.info8 = &info8;
1845 break;
1847 default:
1848 return false;
1851 devmode_ctr.devmode = devmode;
1853 torture_assert(tctx,
1854 test_SetPrinter(tctx, b, handle, &info_ctr, &devmode_ctr, &secdesc_ctr, 0), "");
1856 return true;
1860 static bool test_devicemode_equal(struct torture_context *tctx,
1861 const struct spoolss_DeviceMode *d1,
1862 const struct spoolss_DeviceMode *d2)
1864 if (d1 == d2) {
1865 return true;
1868 if (!d1 || !d2) {
1869 torture_comment(tctx, "%s\n", __location__);
1870 return false;
1872 torture_assert_str_equal(tctx, d1->devicename, d2->devicename, "devicename mismatch");
1873 torture_assert_int_equal(tctx, d1->specversion, d2->specversion, "specversion mismatch");
1874 torture_assert_int_equal(tctx, d1->driverversion, d2->driverversion, "driverversion mismatch");
1875 torture_assert_int_equal(tctx, d1->size, d2->size, "size mismatch");
1876 torture_assert_int_equal(tctx, d1->__driverextra_length, d2->__driverextra_length, "__driverextra_length mismatch");
1877 torture_assert_int_equal(tctx, d1->fields, d2->fields, "fields mismatch");
1878 torture_assert_int_equal(tctx, d1->orientation, d2->orientation, "orientation mismatch");
1879 torture_assert_int_equal(tctx, d1->papersize, d2->papersize, "papersize mismatch");
1880 torture_assert_int_equal(tctx, d1->paperlength, d2->paperlength, "paperlength mismatch");
1881 torture_assert_int_equal(tctx, d1->paperwidth, d2->paperwidth, "paperwidth mismatch");
1882 torture_assert_int_equal(tctx, d1->scale, d2->scale, "scale mismatch");
1883 torture_assert_int_equal(tctx, d1->copies, d2->copies, "copies mismatch");
1884 torture_assert_int_equal(tctx, d1->defaultsource, d2->defaultsource, "defaultsource mismatch");
1885 torture_assert_int_equal(tctx, d1->printquality, d2->printquality, "printquality mismatch");
1886 torture_assert_int_equal(tctx, d1->color, d2->color, "color mismatch");
1887 torture_assert_int_equal(tctx, d1->duplex, d2->duplex, "duplex mismatch");
1888 torture_assert_int_equal(tctx, d1->yresolution, d2->yresolution, "yresolution mismatch");
1889 torture_assert_int_equal(tctx, d1->ttoption, d2->ttoption, "ttoption mismatch");
1890 torture_assert_int_equal(tctx, d1->collate, d2->collate, "collate mismatch");
1891 torture_assert_str_equal(tctx, d1->formname, d2->formname, "formname mismatch");
1892 torture_assert_int_equal(tctx, d1->logpixels, d2->logpixels, "logpixels mismatch");
1893 torture_assert_int_equal(tctx, d1->bitsperpel, d2->bitsperpel, "bitsperpel mismatch");
1894 torture_assert_int_equal(tctx, d1->pelswidth, d2->pelswidth, "pelswidth mismatch");
1895 torture_assert_int_equal(tctx, d1->pelsheight, d2->pelsheight, "pelsheight mismatch");
1896 torture_assert_int_equal(tctx, d1->displayflags, d2->displayflags, "displayflags mismatch");
1897 torture_assert_int_equal(tctx, d1->displayfrequency, d2->displayfrequency, "displayfrequency mismatch");
1898 torture_assert_int_equal(tctx, d1->icmmethod, d2->icmmethod, "icmmethod mismatch");
1899 torture_assert_int_equal(tctx, d1->icmintent, d2->icmintent, "icmintent mismatch");
1900 torture_assert_int_equal(tctx, d1->mediatype, d2->mediatype, "mediatype mismatch");
1901 torture_assert_int_equal(tctx, d1->dithertype, d2->dithertype, "dithertype mismatch");
1902 torture_assert_int_equal(tctx, d1->reserved1, d2->reserved1, "reserved1 mismatch");
1903 torture_assert_int_equal(tctx, d1->reserved2, d2->reserved2, "reserved2 mismatch");
1904 torture_assert_int_equal(tctx, d1->panningwidth, d2->panningwidth, "panningwidth mismatch");
1905 torture_assert_int_equal(tctx, d1->panningheight, d2->panningheight, "panningheight mismatch");
1906 torture_assert_data_blob_equal(tctx, d1->driverextra_data, d2->driverextra_data, "driverextra_data mismatch");
1908 return true;
1911 static bool test_devicemode_full(struct torture_context *tctx,
1912 struct dcerpc_binding_handle *b,
1913 struct policy_handle *handle)
1915 struct spoolss_SetPrinter s;
1916 struct spoolss_GetPrinter q;
1917 struct spoolss_GetPrinter q0;
1918 struct spoolss_SetPrinterInfoCtr info_ctr;
1919 struct spoolss_SetPrinterInfo8 info8;
1920 union spoolss_PrinterInfo info;
1921 struct spoolss_DevmodeContainer devmode_ctr;
1922 struct sec_desc_buf secdesc_ctr;
1923 uint32_t needed;
1924 bool ret = true;
1925 NTSTATUS status;
1927 #define TEST_DEVMODE_INT_EXP(lvl1, field1, lvl2, field2, value, exp_value) do { \
1928 torture_comment(tctx, "field test %d/%s vs %d/%s\n", lvl1, #field1, lvl2, #field2); \
1929 q.in.level = lvl1; \
1930 TESTGETCALL(GetPrinter, q) \
1931 info_ctr.level = lvl1; \
1932 if (lvl1 == 2) {\
1933 info_ctr.info.info ## lvl1 = (struct spoolss_SetPrinterInfo ## lvl1 *)(void *)&q.out.info->info ## lvl1; \
1934 } else if (lvl1 == 8) {\
1935 info_ctr.info.info ## lvl1 = &info8; \
1937 devmode_ctr.devmode = q.out.info->info ## lvl1.devmode; \
1938 devmode_ctr.devmode->field1 = value; \
1939 TESTSETCALL(SetPrinter, s) \
1940 TESTGETCALL(GetPrinter, q) \
1941 INT_EQUAL(q.out.info->info ## lvl1.devmode->field1, exp_value, field1); \
1942 q.in.level = lvl2; \
1943 TESTGETCALL(GetPrinter, q) \
1944 INT_EQUAL(q.out.info->info ## lvl2.devmode->field2, exp_value, field1); \
1945 } while (0)
1947 #define TEST_DEVMODE_INT(lvl1, field1, lvl2, field2, value) do { \
1948 TEST_DEVMODE_INT_EXP(lvl1, field1, lvl2, field2, value, value); \
1949 } while (0)
1951 ZERO_STRUCT(devmode_ctr);
1952 ZERO_STRUCT(secdesc_ctr);
1953 ZERO_STRUCT(info8);
1955 s.in.handle = handle;
1956 s.in.command = 0;
1957 s.in.info_ctr = &info_ctr;
1958 s.in.devmode_ctr = &devmode_ctr;
1959 s.in.secdesc_ctr = &secdesc_ctr;
1961 q.in.handle = handle;
1962 q.out.info = &info;
1963 q0 = q;
1965 #if 0
1966 const char *devicename;/* [charset(UTF16)] */
1967 enum spoolss_DeviceModeSpecVersion specversion;
1968 uint16_t driverversion;
1969 uint16_t size;
1970 uint16_t __driverextra_length;/* [value(r->driverextra_data.length)] */
1971 uint32_t fields;
1972 #endif
1974 TEST_DEVMODE_INT(8, orientation, 8, orientation, __LINE__);
1975 TEST_DEVMODE_INT(8, papersize, 8, papersize, __LINE__);
1976 TEST_DEVMODE_INT(8, paperlength, 8, paperlength, __LINE__);
1977 TEST_DEVMODE_INT(8, paperwidth, 8, paperwidth, __LINE__);
1978 TEST_DEVMODE_INT(8, scale, 8, scale, __LINE__);
1979 TEST_DEVMODE_INT(8, copies, 8, copies, __LINE__);
1980 TEST_DEVMODE_INT(8, defaultsource, 8, defaultsource, __LINE__);
1981 TEST_DEVMODE_INT(8, printquality, 8, printquality, __LINE__);
1982 TEST_DEVMODE_INT(8, color, 8, color, __LINE__);
1983 TEST_DEVMODE_INT(8, duplex, 8, duplex, __LINE__);
1984 TEST_DEVMODE_INT(8, yresolution, 8, yresolution, __LINE__);
1985 TEST_DEVMODE_INT(8, ttoption, 8, ttoption, __LINE__);
1986 TEST_DEVMODE_INT(8, collate, 8, collate, __LINE__);
1987 #if 0
1988 const char *formname;/* [charset(UTF16)] */
1989 #endif
1990 TEST_DEVMODE_INT(8, logpixels, 8, logpixels, __LINE__);
1991 TEST_DEVMODE_INT(8, bitsperpel, 8, bitsperpel, __LINE__);
1992 TEST_DEVMODE_INT(8, pelswidth, 8, pelswidth, __LINE__);
1993 TEST_DEVMODE_INT(8, pelsheight, 8, pelsheight, __LINE__);
1994 TEST_DEVMODE_INT(8, displayflags, 8, displayflags, __LINE__);
1995 TEST_DEVMODE_INT(8, displayfrequency, 8, displayfrequency, __LINE__);
1996 TEST_DEVMODE_INT(8, icmmethod, 8, icmmethod, __LINE__);
1997 TEST_DEVMODE_INT(8, icmintent, 8, icmintent, __LINE__);
1998 TEST_DEVMODE_INT(8, mediatype, 8, mediatype, __LINE__);
1999 TEST_DEVMODE_INT(8, dithertype, 8, dithertype, __LINE__);
2000 TEST_DEVMODE_INT(8, reserved1, 8, reserved1, __LINE__);
2001 TEST_DEVMODE_INT(8, reserved2, 8, reserved2, __LINE__);
2002 TEST_DEVMODE_INT(8, panningwidth, 8, panningwidth, __LINE__);
2003 TEST_DEVMODE_INT(8, panningheight, 8, panningheight, __LINE__);
2005 return ret;
2008 static bool call_OpenPrinterEx(struct torture_context *tctx,
2009 struct dcerpc_pipe *p,
2010 const char *name,
2011 struct spoolss_DeviceMode *devmode,
2012 struct policy_handle *handle);
2014 static bool test_ClosePrinter(struct torture_context *tctx,
2015 struct dcerpc_binding_handle *b,
2016 struct policy_handle *handle);
2018 static bool test_PrinterInfo_DevModes(struct torture_context *tctx,
2019 struct dcerpc_pipe *p,
2020 struct policy_handle *handle,
2021 const char *name)
2023 union spoolss_PrinterInfo info;
2024 struct spoolss_DeviceMode *devmode;
2025 struct spoolss_DeviceMode *devmode2;
2026 struct policy_handle handle_devmode;
2027 struct dcerpc_binding_handle *b = p->binding_handle;
2029 /* simply compare level8 and level2 devmode */
2031 torture_assert(tctx, test_GetPrinter_level(tctx, b, handle, 8, &info), "");
2033 devmode = info.info8.devmode;
2035 torture_assert(tctx, test_GetPrinter_level(tctx, b, handle, 2, &info), "");
2037 devmode2 = info.info2.devmode;
2039 torture_assert(tctx, test_devicemode_equal(tctx, devmode, devmode2),
2040 "DM level 8 != DM level 2");
2043 /* set devicemode level 8 and see if it persists */
2045 devmode->copies = 93;
2046 devmode->formname = talloc_strdup(tctx, "Legal");
2048 torture_assert(tctx, test_devmode_set_level(tctx, b, handle, 8, devmode), "");
2050 torture_assert(tctx, test_GetPrinter_level(tctx, b, handle, 8, &info), "");
2052 devmode2 = info.info8.devmode;
2054 torture_assert(tctx, test_devicemode_equal(tctx, devmode, devmode2),
2055 "modified DM level 8 != DM level 8 after DM has been set via level 8");
2057 torture_assert(tctx, test_GetPrinter_level(tctx, b, handle, 2, &info), "");
2059 devmode2 = info.info2.devmode;
2061 torture_assert(tctx, test_devicemode_equal(tctx, devmode, devmode2),
2062 "modified DM level 8 != DM level 2");
2065 /* set devicemode level 2 and see if it persists */
2067 devmode->copies = 39;
2068 devmode->formname = talloc_strdup(tctx, "Executive");
2070 torture_assert(tctx, test_devmode_set_level(tctx, b, handle, 2, devmode), "");
2072 torture_assert(tctx, test_GetPrinter_level(tctx, b, handle, 8, &info), "");
2074 devmode2 = info.info8.devmode;
2076 torture_assert(tctx, test_devicemode_equal(tctx, devmode, devmode2),
2077 "modified DM level 8 != DM level 8 after DM has been set via level 2");
2079 torture_assert(tctx, test_GetPrinter_level(tctx, b, handle, 2, &info), "");
2081 devmode2 = info.info2.devmode;
2083 torture_assert(tctx, test_devicemode_equal(tctx, devmode, devmode2),
2084 "modified DM level 8 != DM level 2");
2087 /* check every single bit in public part of devicemode */
2089 torture_assert(tctx, test_devicemode_full(tctx, b, handle),
2090 "failed to set every single devicemode component");
2093 /* change formname upon open and see if it persists in getprinter calls */
2095 devmode->formname = talloc_strdup(tctx, "A4");
2096 devmode->copies = 42;
2098 torture_assert(tctx, call_OpenPrinterEx(tctx, p, name, devmode, &handle_devmode),
2099 "failed to open printer handle");
2101 torture_assert(tctx, test_GetPrinter_level(tctx, b, &handle_devmode, 8, &info), "");
2103 devmode2 = info.info8.devmode;
2105 if (strequal(devmode->devicename, devmode2->devicename)) {
2106 torture_warning(tctx, "devicenames are the same\n");
2107 } else {
2108 torture_comment(tctx, "devicename passed in for open: %s\n", devmode->devicename);
2109 torture_comment(tctx, "devicename after level 8 get: %s\n", devmode2->devicename);
2112 if (strequal(devmode->formname, devmode2->formname)) {
2113 torture_warning(tctx, "formname are the same\n");
2114 } else {
2115 torture_comment(tctx, "formname passed in for open: %s\n", devmode->formname);
2116 torture_comment(tctx, "formname after level 8 get: %s\n", devmode2->formname);
2119 if (devmode->copies == devmode2->copies) {
2120 torture_warning(tctx, "copies are the same\n");
2121 } else {
2122 torture_comment(tctx, "copies passed in for open: %d\n", devmode->copies);
2123 torture_comment(tctx, "copies after level 8 get: %d\n", devmode2->copies);
2126 torture_assert(tctx, test_GetPrinter_level(tctx, b, &handle_devmode, 2, &info), "");
2128 devmode2 = info.info2.devmode;
2130 if (strequal(devmode->devicename, devmode2->devicename)) {
2131 torture_warning(tctx, "devicenames are the same\n");
2132 } else {
2133 torture_comment(tctx, "devicename passed in for open: %s\n", devmode->devicename);
2134 torture_comment(tctx, "devicename after level 2 get: %s\n", devmode2->devicename);
2137 if (strequal(devmode->formname, devmode2->formname)) {
2138 torture_warning(tctx, "formname is the same\n");
2139 } else {
2140 torture_comment(tctx, "formname passed in for open: %s\n", devmode->formname);
2141 torture_comment(tctx, "formname after level 2 get: %s\n", devmode2->formname);
2144 if (devmode->copies == devmode2->copies) {
2145 torture_warning(tctx, "copies are the same\n");
2146 } else {
2147 torture_comment(tctx, "copies passed in for open: %d\n", devmode->copies);
2148 torture_comment(tctx, "copies after level 2 get: %d\n", devmode2->copies);
2151 test_ClosePrinter(tctx, b, &handle_devmode);
2153 return true;
2157 * wrapper call that saves original devmode, runs tests, and restores devmode
2160 static bool test_PrinterInfo_DevMode(struct torture_context *tctx,
2161 struct dcerpc_pipe *p,
2162 struct policy_handle *handle,
2163 const char *name)
2165 union spoolss_PrinterInfo info;
2166 struct spoolss_DeviceMode *devmode;
2167 bool ret = true;
2168 struct dcerpc_binding_handle *b = p->binding_handle;
2170 torture_comment(tctx, "Testing Printer Devicemodes\n");
2172 /* save original devmode */
2174 torture_assert(tctx, test_GetPrinter_level(tctx, b, handle, 8, &info),
2175 "failed to get initial global devicemode");
2177 devmode = info.info8.devmode;
2179 /* run tests */
2181 ret = test_PrinterInfo_DevModes(tctx, p, handle, name);
2183 /* restore original devmode */
2185 torture_assert(tctx, test_devmode_set_level(tctx, b, handle, 8, devmode),
2186 "failed to restore initial global device mode");
2188 torture_comment(tctx, "Printer Devicemodes test %s\n\n",
2189 ret ? "succeeded" : "failed");
2192 return ret;
2195 static bool test_ClosePrinter(struct torture_context *tctx,
2196 struct dcerpc_binding_handle *b,
2197 struct policy_handle *handle)
2199 NTSTATUS status;
2200 struct spoolss_ClosePrinter r;
2202 r.in.handle = handle;
2203 r.out.handle = handle;
2205 torture_comment(tctx, "Testing ClosePrinter\n");
2207 status = dcerpc_spoolss_ClosePrinter_r(b, tctx, &r);
2208 torture_assert_ntstatus_ok(tctx, status, "ClosePrinter failed");
2209 torture_assert_werr_ok(tctx, r.out.result, "ClosePrinter failed");
2211 return true;
2214 static bool test_GetForm(struct torture_context *tctx,
2215 struct dcerpc_binding_handle *b,
2216 struct policy_handle *handle,
2217 const char *form_name,
2218 uint32_t level)
2220 NTSTATUS status;
2221 struct spoolss_GetForm r;
2222 uint32_t needed;
2224 r.in.handle = handle;
2225 r.in.form_name = form_name;
2226 r.in.level = level;
2227 r.in.buffer = NULL;
2228 r.in.offered = 0;
2229 r.out.needed = &needed;
2231 torture_comment(tctx, "Testing GetForm level %d\n", r.in.level);
2233 status = dcerpc_spoolss_GetForm_r(b, tctx, &r);
2234 torture_assert_ntstatus_ok(tctx, status, "GetForm failed");
2236 if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
2237 DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed);
2238 data_blob_clear(&blob);
2239 r.in.buffer = &blob;
2240 r.in.offered = needed;
2241 status = dcerpc_spoolss_GetForm_r(b, tctx, &r);
2242 torture_assert_ntstatus_ok(tctx, status, "GetForm failed");
2244 torture_assert_werr_ok(tctx, r.out.result, "GetForm failed");
2246 torture_assert(tctx, r.out.info, "No form info returned");
2249 torture_assert_werr_ok(tctx, r.out.result, "GetForm failed");
2251 CHECK_NEEDED_SIZE_LEVEL(spoolss_FormInfo, r.out.info, r.in.level, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
2253 return true;
2256 static bool test_EnumForms(struct torture_context *tctx,
2257 struct dcerpc_binding_handle *b,
2258 struct policy_handle *handle, bool print_server)
2260 NTSTATUS status;
2261 struct spoolss_EnumForms r;
2262 bool ret = true;
2263 uint32_t needed;
2264 uint32_t count;
2265 uint32_t levels[] = { 1, 2 };
2266 int i;
2268 for (i=0; i<ARRAY_SIZE(levels); i++) {
2270 union spoolss_FormInfo *info;
2272 r.in.handle = handle;
2273 r.in.level = levels[i];
2274 r.in.buffer = NULL;
2275 r.in.offered = 0;
2276 r.out.needed = &needed;
2277 r.out.count = &count;
2278 r.out.info = &info;
2280 torture_comment(tctx, "Testing EnumForms level %d\n", levels[i]);
2282 status = dcerpc_spoolss_EnumForms_r(b, tctx, &r);
2283 torture_assert_ntstatus_ok(tctx, status, "EnumForms failed");
2285 if ((r.in.level == 2) && (W_ERROR_EQUAL(r.out.result, WERR_UNKNOWN_LEVEL))) {
2286 break;
2289 if (print_server && W_ERROR_EQUAL(r.out.result, WERR_BADFID))
2290 torture_fail(tctx, "EnumForms on the PrintServer isn't supported by test server (NT4)");
2292 if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
2293 int j;
2294 DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed);
2295 data_blob_clear(&blob);
2296 r.in.buffer = &blob;
2297 r.in.offered = needed;
2299 status = dcerpc_spoolss_EnumForms_r(b, tctx, &r);
2301 torture_assert(tctx, info, "No forms returned");
2303 for (j = 0; j < count; j++) {
2304 if (!print_server)
2305 ret &= test_GetForm(tctx, b, handle, info[j].info1.form_name, levels[i]);
2309 torture_assert_ntstatus_ok(tctx, status, "EnumForms failed");
2311 torture_assert_werr_ok(tctx, r.out.result, "EnumForms failed");
2313 CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumForms, info, r.in.level, count, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
2316 return true;
2319 static bool test_DeleteForm(struct torture_context *tctx,
2320 struct dcerpc_binding_handle *b,
2321 struct policy_handle *handle,
2322 const char *form_name)
2324 NTSTATUS status;
2325 struct spoolss_DeleteForm r;
2327 r.in.handle = handle;
2328 r.in.form_name = form_name;
2330 status = dcerpc_spoolss_DeleteForm_r(b, tctx, &r);
2332 torture_assert_ntstatus_ok(tctx, status, "DeleteForm failed");
2334 torture_assert_werr_ok(tctx, r.out.result, "DeleteForm failed");
2336 return true;
2339 static bool test_AddForm(struct torture_context *tctx,
2340 struct dcerpc_binding_handle *b,
2341 struct policy_handle *handle, bool print_server)
2343 struct spoolss_AddForm r;
2344 struct spoolss_AddFormInfo1 addform;
2345 const char *form_name = "testform3";
2346 NTSTATUS status;
2347 bool ret = true;
2349 r.in.handle = handle;
2350 r.in.level = 1;
2351 r.in.info.info1 = &addform;
2352 addform.flags = SPOOLSS_FORM_USER;
2353 addform.form_name = form_name;
2354 addform.size.width = 50;
2355 addform.size.height = 25;
2356 addform.area.left = 5;
2357 addform.area.top = 10;
2358 addform.area.right = 45;
2359 addform.area.bottom = 15;
2361 status = dcerpc_spoolss_AddForm_r(b, tctx, &r);
2363 torture_assert_ntstatus_ok(tctx, status, "AddForm failed");
2365 torture_assert_werr_ok(tctx, r.out.result, "AddForm failed");
2367 if (!print_server) ret &= test_GetForm(tctx, b, handle, form_name, 1);
2370 struct spoolss_SetForm sf;
2371 struct spoolss_AddFormInfo1 setform;
2373 sf.in.handle = handle;
2374 sf.in.form_name = form_name;
2375 sf.in.level = 1;
2376 sf.in.info.info1= &setform;
2377 setform.flags = addform.flags;
2378 setform.form_name = addform.form_name;
2379 setform.size = addform.size;
2380 setform.area = addform.area;
2382 setform.size.width = 1234;
2384 status = dcerpc_spoolss_SetForm_r(b, tctx, &sf);
2386 torture_assert_ntstatus_ok(tctx, status, "SetForm failed");
2388 torture_assert_werr_ok(tctx, r.out.result, "SetForm failed");
2391 if (!print_server) ret &= test_GetForm(tctx, b, handle, form_name, 1);
2394 struct spoolss_EnumForms e;
2395 union spoolss_FormInfo *info;
2396 uint32_t needed;
2397 uint32_t count;
2398 bool found = false;
2400 e.in.handle = handle;
2401 e.in.level = 1;
2402 e.in.buffer = NULL;
2403 e.in.offered = 0;
2404 e.out.needed = &needed;
2405 e.out.count = &count;
2406 e.out.info = &info;
2408 torture_comment(tctx, "Testing EnumForms level 1\n");
2410 status = dcerpc_spoolss_EnumForms_r(b, tctx, &e);
2411 torture_assert_ntstatus_ok(tctx, status, "EnumForms failed");
2413 if (print_server && W_ERROR_EQUAL(e.out.result, WERR_BADFID))
2414 torture_fail(tctx, "EnumForms on the PrintServer isn't supported by test server (NT4)");
2416 if (W_ERROR_EQUAL(e.out.result, WERR_INSUFFICIENT_BUFFER)) {
2417 int j;
2418 DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed);
2419 data_blob_clear(&blob);
2420 e.in.buffer = &blob;
2421 e.in.offered = needed;
2423 status = dcerpc_spoolss_EnumForms_r(b, tctx, &e);
2425 torture_assert(tctx, info, "No forms returned");
2427 for (j = 0; j < count; j++) {
2428 if (strequal(form_name, info[j].info1.form_name)) {
2429 found = true;
2430 break;
2434 torture_assert(tctx, found, "Newly added form not found in enum call");
2437 if (!test_DeleteForm(tctx, b, handle, form_name)) {
2438 ret = false;
2441 return ret;
2444 static bool test_EnumPorts_old(struct torture_context *tctx,
2445 struct dcerpc_pipe *p)
2447 NTSTATUS status;
2448 struct spoolss_EnumPorts r;
2449 uint32_t needed;
2450 uint32_t count;
2451 union spoolss_PortInfo *info;
2452 struct dcerpc_binding_handle *b = p->binding_handle;
2454 r.in.servername = talloc_asprintf(tctx, "\\\\%s",
2455 dcerpc_server_name(p));
2456 r.in.level = 2;
2457 r.in.buffer = NULL;
2458 r.in.offered = 0;
2459 r.out.needed = &needed;
2460 r.out.count = &count;
2461 r.out.info = &info;
2463 torture_comment(tctx, "Testing EnumPorts\n");
2465 status = dcerpc_spoolss_EnumPorts_r(b, tctx, &r);
2467 torture_assert_ntstatus_ok(tctx, status, "EnumPorts failed");
2469 if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
2470 DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed);
2471 data_blob_clear(&blob);
2472 r.in.buffer = &blob;
2473 r.in.offered = needed;
2475 status = dcerpc_spoolss_EnumPorts_r(b, tctx, &r);
2476 torture_assert_ntstatus_ok(tctx, status, "EnumPorts failed");
2477 torture_assert_werr_ok(tctx, r.out.result, "EnumPorts failed");
2479 torture_assert(tctx, info, "No ports returned");
2482 torture_assert_werr_ok(tctx, r.out.result, "EnumPorts failed");
2484 CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumPorts, info, 2, count, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
2486 return true;
2489 static bool test_AddPort(struct torture_context *tctx,
2490 struct dcerpc_pipe *p)
2492 NTSTATUS status;
2493 struct spoolss_AddPort r;
2494 struct dcerpc_binding_handle *b = p->binding_handle;
2496 r.in.server_name = talloc_asprintf(tctx, "\\\\%s",
2497 dcerpc_server_name(p));
2498 r.in.unknown = 0;
2499 r.in.monitor_name = "foo";
2501 torture_comment(tctx, "Testing AddPort\n");
2503 status = dcerpc_spoolss_AddPort_r(b, tctx, &r);
2505 torture_assert_ntstatus_ok(tctx, status, "AddPort failed");
2507 /* win2k3 returns WERR_NOT_SUPPORTED */
2509 #if 0
2511 if (!W_ERROR_IS_OK(r.out.result)) {
2512 printf("AddPort failed - %s\n", win_errstr(r.out.result));
2513 return false;
2516 #endif
2518 return true;
2521 static bool test_GetJob(struct torture_context *tctx,
2522 struct dcerpc_binding_handle *b,
2523 struct policy_handle *handle, uint32_t job_id)
2525 NTSTATUS status;
2526 struct spoolss_GetJob r;
2527 union spoolss_JobInfo info;
2528 uint32_t needed;
2529 uint32_t levels[] = {1, 2 /* 3, 4 */};
2530 uint32_t i;
2532 r.in.handle = handle;
2533 r.in.job_id = job_id;
2534 r.in.level = 0;
2535 r.in.buffer = NULL;
2536 r.in.offered = 0;
2537 r.out.needed = &needed;
2538 r.out.info = &info;
2540 torture_comment(tctx, "Testing GetJob level %d\n", r.in.level);
2542 status = dcerpc_spoolss_GetJob_r(b, tctx, &r);
2543 torture_assert_werr_equal(tctx, r.out.result, WERR_UNKNOWN_LEVEL, "Unexpected return code");
2545 for (i = 0; i < ARRAY_SIZE(levels); i++) {
2547 torture_comment(tctx, "Testing GetJob level %d\n", r.in.level);
2549 needed = 0;
2551 r.in.level = levels[i];
2552 r.in.offered = 0;
2553 r.in.buffer = NULL;
2555 status = dcerpc_spoolss_GetJob_r(b, tctx, &r);
2556 torture_assert_ntstatus_ok(tctx, status, "GetJob failed");
2558 if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
2559 DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed);
2560 data_blob_clear(&blob);
2561 r.in.buffer = &blob;
2562 r.in.offered = needed;
2564 status = dcerpc_spoolss_GetJob_r(b, tctx, &r);
2565 torture_assert_ntstatus_ok(tctx, status, "GetJob failed");
2568 torture_assert(tctx, r.out.info, "No job info returned");
2569 torture_assert_werr_ok(tctx, r.out.result, "GetJob failed");
2571 CHECK_NEEDED_SIZE_LEVEL(spoolss_JobInfo, r.out.info, r.in.level, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
2574 return true;
2577 static bool test_SetJob(struct torture_context *tctx,
2578 struct dcerpc_binding_handle *b,
2579 struct policy_handle *handle, uint32_t job_id,
2580 enum spoolss_JobControl command)
2582 NTSTATUS status;
2583 struct spoolss_SetJob r;
2585 r.in.handle = handle;
2586 r.in.job_id = job_id;
2587 r.in.ctr = NULL;
2588 r.in.command = command;
2590 switch (command) {
2591 case SPOOLSS_JOB_CONTROL_PAUSE:
2592 torture_comment(tctx, "Testing SetJob: SPOOLSS_JOB_CONTROL_PAUSE\n");
2593 break;
2594 case SPOOLSS_JOB_CONTROL_RESUME:
2595 torture_comment(tctx, "Testing SetJob: SPOOLSS_JOB_CONTROL_RESUME\n");
2596 break;
2597 case SPOOLSS_JOB_CONTROL_CANCEL:
2598 torture_comment(tctx, "Testing SetJob: SPOOLSS_JOB_CONTROL_CANCEL\n");
2599 break;
2600 case SPOOLSS_JOB_CONTROL_RESTART:
2601 torture_comment(tctx, "Testing SetJob: SPOOLSS_JOB_CONTROL_RESTART\n");
2602 break;
2603 case SPOOLSS_JOB_CONTROL_DELETE:
2604 torture_comment(tctx, "Testing SetJob: SPOOLSS_JOB_CONTROL_DELETE\n");
2605 break;
2606 case SPOOLSS_JOB_CONTROL_SEND_TO_PRINTER:
2607 torture_comment(tctx, "Testing SetJob: SPOOLSS_JOB_CONTROL_SEND_TO_PRINTER\n");
2608 break;
2609 case SPOOLSS_JOB_CONTROL_LAST_PAGE_EJECTED:
2610 torture_comment(tctx, "Testing SetJob: SPOOLSS_JOB_CONTROL_LAST_PAGE_EJECTED\n");
2611 break;
2612 case SPOOLSS_JOB_CONTROL_RETAIN:
2613 torture_comment(tctx, "Testing SetJob: SPOOLSS_JOB_CONTROL_RETAIN\n");
2614 break;
2615 case SPOOLSS_JOB_CONTROL_RELEASE:
2616 torture_comment(tctx, "Testing SetJob: SPOOLSS_JOB_CONTROL_RELEASE\n");
2617 break;
2618 default:
2619 torture_comment(tctx, "Testing SetJob\n");
2620 break;
2623 status = dcerpc_spoolss_SetJob_r(b, tctx, &r);
2624 torture_assert_ntstatus_ok(tctx, status, "SetJob failed");
2625 torture_assert_werr_ok(tctx, r.out.result, "SetJob failed");
2627 return true;
2630 static bool test_AddJob(struct torture_context *tctx,
2631 struct dcerpc_binding_handle *b,
2632 struct policy_handle *handle)
2634 NTSTATUS status;
2635 struct spoolss_AddJob r;
2636 uint32_t needed;
2638 r.in.level = 0;
2639 r.in.handle = handle;
2640 r.in.offered = 0;
2641 r.out.needed = &needed;
2642 r.in.buffer = r.out.buffer = NULL;
2644 torture_comment(tctx, "Testing AddJob\n");
2646 status = dcerpc_spoolss_AddJob_r(b, tctx, &r);
2647 torture_assert_werr_equal(tctx, r.out.result, WERR_UNKNOWN_LEVEL, "AddJob failed");
2649 r.in.level = 1;
2651 status = dcerpc_spoolss_AddJob_r(b, tctx, &r);
2652 torture_assert_werr_equal(tctx, r.out.result, WERR_INVALID_PARAM, "AddJob failed");
2654 return true;
2658 static bool test_EnumJobs(struct torture_context *tctx,
2659 struct dcerpc_binding_handle *b,
2660 struct policy_handle *handle)
2662 NTSTATUS status;
2663 struct spoolss_EnumJobs r;
2664 uint32_t needed;
2665 uint32_t count;
2666 union spoolss_JobInfo *info;
2668 r.in.handle = handle;
2669 r.in.firstjob = 0;
2670 r.in.numjobs = 0xffffffff;
2671 r.in.level = 1;
2672 r.in.buffer = NULL;
2673 r.in.offered = 0;
2674 r.out.needed = &needed;
2675 r.out.count = &count;
2676 r.out.info = &info;
2678 torture_comment(tctx, "Testing EnumJobs\n");
2680 status = dcerpc_spoolss_EnumJobs_r(b, tctx, &r);
2682 torture_assert_ntstatus_ok(tctx, status, "EnumJobs failed");
2684 if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
2685 int j;
2686 DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed);
2687 data_blob_clear(&blob);
2688 r.in.buffer = &blob;
2689 r.in.offered = needed;
2691 status = dcerpc_spoolss_EnumJobs_r(b, tctx, &r);
2693 torture_assert_ntstatus_ok(tctx, status, "EnumJobs failed");
2694 torture_assert_werr_ok(tctx, r.out.result, "EnumJobs failed");
2695 torture_assert(tctx, info, "No jobs returned");
2697 CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumJobs, *r.out.info, r.in.level, count, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
2699 for (j = 0; j < count; j++) {
2701 torture_assert(tctx, test_GetJob(tctx, b, handle, info[j].info1.job_id),
2702 "failed to call test_GetJob");
2704 /* FIXME - gd */
2705 if (!torture_setting_bool(tctx, "samba3", false)) {
2706 test_SetJob(tctx, b, handle, info[j].info1.job_id, SPOOLSS_JOB_CONTROL_PAUSE);
2707 test_SetJob(tctx, b, handle, info[j].info1.job_id, SPOOLSS_JOB_CONTROL_RESUME);
2711 } else {
2712 torture_assert_werr_ok(tctx, r.out.result, "EnumJobs failed");
2715 return true;
2718 static bool test_DoPrintTest(struct torture_context *tctx,
2719 struct dcerpc_binding_handle *b,
2720 struct policy_handle *handle)
2722 bool ret = true;
2723 NTSTATUS status;
2724 struct spoolss_StartDocPrinter s;
2725 struct spoolss_DocumentInfo1 info1;
2726 struct spoolss_StartPagePrinter sp;
2727 struct spoolss_WritePrinter w;
2728 struct spoolss_EndPagePrinter ep;
2729 struct spoolss_EndDocPrinter e;
2730 int i;
2731 uint32_t job_id;
2732 uint32_t num_written;
2734 torture_comment(tctx, "Testing StartDocPrinter\n");
2736 s.in.handle = handle;
2737 s.in.level = 1;
2738 s.in.info.info1 = &info1;
2739 s.out.job_id = &job_id;
2740 info1.document_name = "TorturePrintJob";
2741 info1.output_file = NULL;
2742 info1.datatype = "RAW";
2744 status = dcerpc_spoolss_StartDocPrinter_r(b, tctx, &s);
2745 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_StartDocPrinter failed");
2746 torture_assert_werr_ok(tctx, s.out.result, "StartDocPrinter failed");
2748 for (i=1; i < 4; i++) {
2749 torture_comment(tctx, "Testing StartPagePrinter: Page[%d]\n", i);
2751 sp.in.handle = handle;
2753 status = dcerpc_spoolss_StartPagePrinter_r(b, tctx, &sp);
2754 torture_assert_ntstatus_ok(tctx, status,
2755 "dcerpc_spoolss_StartPagePrinter failed");
2756 torture_assert_werr_ok(tctx, sp.out.result, "StartPagePrinter failed");
2758 torture_comment(tctx, "Testing WritePrinter: Page[%d]\n", i);
2760 w.in.handle = handle;
2761 w.in.data = data_blob_string_const(talloc_asprintf(tctx,"TortureTestPage: %d\nData\n",i));
2762 w.out.num_written = &num_written;
2764 status = dcerpc_spoolss_WritePrinter_r(b, tctx, &w);
2765 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_WritePrinter failed");
2766 torture_assert_werr_ok(tctx, w.out.result, "WritePrinter failed");
2768 torture_comment(tctx, "Testing EndPagePrinter: Page[%d]\n", i);
2770 ep.in.handle = handle;
2772 status = dcerpc_spoolss_EndPagePrinter_r(b, tctx, &ep);
2773 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EndPagePrinter failed");
2774 torture_assert_werr_ok(tctx, ep.out.result, "EndPagePrinter failed");
2777 torture_comment(tctx, "Testing EndDocPrinter\n");
2779 e.in.handle = handle;
2781 status = dcerpc_spoolss_EndDocPrinter_r(b, tctx, &e);
2782 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EndDocPrinter failed");
2783 torture_assert_werr_ok(tctx, e.out.result, "EndDocPrinter failed");
2785 ret &= test_AddJob(tctx, b, handle);
2786 ret &= test_EnumJobs(tctx, b, handle);
2788 ret &= test_SetJob(tctx, b, handle, job_id, SPOOLSS_JOB_CONTROL_DELETE);
2790 return ret;
2793 static bool test_PausePrinter(struct torture_context *tctx,
2794 struct dcerpc_binding_handle *b,
2795 struct policy_handle *handle)
2797 NTSTATUS status;
2798 struct spoolss_SetPrinter r;
2799 struct spoolss_SetPrinterInfoCtr info_ctr;
2800 struct spoolss_DevmodeContainer devmode_ctr;
2801 struct sec_desc_buf secdesc_ctr;
2803 info_ctr.level = 0;
2804 info_ctr.info.info0 = NULL;
2806 ZERO_STRUCT(devmode_ctr);
2807 ZERO_STRUCT(secdesc_ctr);
2809 r.in.handle = handle;
2810 r.in.info_ctr = &info_ctr;
2811 r.in.devmode_ctr = &devmode_ctr;
2812 r.in.secdesc_ctr = &secdesc_ctr;
2813 r.in.command = SPOOLSS_PRINTER_CONTROL_PAUSE;
2815 torture_comment(tctx, "Testing SetPrinter: SPOOLSS_PRINTER_CONTROL_PAUSE\n");
2817 status = dcerpc_spoolss_SetPrinter_r(b, tctx, &r);
2819 torture_assert_ntstatus_ok(tctx, status, "SetPrinter failed");
2821 torture_assert_werr_ok(tctx, r.out.result, "SetPrinter failed");
2823 return true;
2826 static bool test_ResumePrinter(struct torture_context *tctx,
2827 struct dcerpc_binding_handle *b,
2828 struct policy_handle *handle)
2830 NTSTATUS status;
2831 struct spoolss_SetPrinter r;
2832 struct spoolss_SetPrinterInfoCtr info_ctr;
2833 struct spoolss_DevmodeContainer devmode_ctr;
2834 struct sec_desc_buf secdesc_ctr;
2836 info_ctr.level = 0;
2837 info_ctr.info.info0 = NULL;
2839 ZERO_STRUCT(devmode_ctr);
2840 ZERO_STRUCT(secdesc_ctr);
2842 r.in.handle = handle;
2843 r.in.info_ctr = &info_ctr;
2844 r.in.devmode_ctr = &devmode_ctr;
2845 r.in.secdesc_ctr = &secdesc_ctr;
2846 r.in.command = SPOOLSS_PRINTER_CONTROL_RESUME;
2848 torture_comment(tctx, "Testing SetPrinter: SPOOLSS_PRINTER_CONTROL_RESUME\n");
2850 status = dcerpc_spoolss_SetPrinter_r(b, tctx, &r);
2852 torture_assert_ntstatus_ok(tctx, status, "SetPrinter failed");
2854 torture_assert_werr_ok(tctx, r.out.result, "SetPrinter failed");
2856 return true;
2859 static bool test_GetPrinterData(struct torture_context *tctx,
2860 struct dcerpc_binding_handle *b,
2861 struct policy_handle *handle,
2862 const char *value_name,
2863 enum winreg_Type *type_p,
2864 uint8_t **data_p,
2865 uint32_t *needed_p)
2867 NTSTATUS status;
2868 struct spoolss_GetPrinterData r;
2869 uint32_t needed;
2870 enum winreg_Type type;
2871 union spoolss_PrinterData data;
2873 r.in.handle = handle;
2874 r.in.value_name = value_name;
2875 r.in.offered = 0;
2876 r.out.needed = &needed;
2877 r.out.type = &type;
2878 r.out.data = talloc_zero_array(tctx, uint8_t, r.in.offered);
2880 torture_comment(tctx, "Testing GetPrinterData(%s)\n", r.in.value_name);
2882 status = dcerpc_spoolss_GetPrinterData_r(b, tctx, &r);
2883 torture_assert_ntstatus_ok(tctx, status, "GetPrinterData failed");
2885 if (W_ERROR_EQUAL(r.out.result, WERR_MORE_DATA)) {
2886 r.in.offered = needed;
2887 r.out.data = talloc_zero_array(tctx, uint8_t, r.in.offered);
2888 status = dcerpc_spoolss_GetPrinterData_r(b, tctx, &r);
2889 torture_assert_ntstatus_ok(tctx, status, "GetPrinterData failed");
2892 torture_assert_werr_ok(tctx, r.out.result,
2893 talloc_asprintf(tctx, "GetPrinterData(%s) failed", r.in.value_name));
2895 CHECK_NEEDED_SIZE_LEVEL(spoolss_PrinterData, &data, type, lp_iconv_convenience(tctx->lp_ctx), needed, 1);
2897 if (type_p) {
2898 *type_p = type;
2901 if (data_p) {
2902 *data_p = r.out.data;
2905 if (needed_p) {
2906 *needed_p = needed;
2909 return true;
2912 static bool test_GetPrinterDataEx(struct torture_context *tctx,
2913 struct dcerpc_pipe *p,
2914 struct policy_handle *handle,
2915 const char *key_name,
2916 const char *value_name,
2917 enum winreg_Type *type_p,
2918 uint8_t **data_p,
2919 uint32_t *needed_p)
2921 NTSTATUS status;
2922 struct spoolss_GetPrinterDataEx r;
2923 enum winreg_Type type;
2924 uint32_t needed;
2925 union spoolss_PrinterData data;
2926 struct dcerpc_binding_handle *b = p->binding_handle;
2928 r.in.handle = handle;
2929 r.in.key_name = key_name;
2930 r.in.value_name = value_name;
2931 r.in.offered = 0;
2932 r.out.type = &type;
2933 r.out.needed = &needed;
2934 r.out.data = talloc_zero_array(tctx, uint8_t, r.in.offered);
2936 torture_comment(tctx, "Testing GetPrinterDataEx(%s - %s)\n",
2937 r.in.key_name, r.in.value_name);
2939 status = dcerpc_spoolss_GetPrinterDataEx_r(b, tctx, &r);
2940 if (!NT_STATUS_IS_OK(status)) {
2941 if (NT_STATUS_EQUAL(status,NT_STATUS_NET_WRITE_FAULT) &&
2942 p->last_fault_code == DCERPC_FAULT_OP_RNG_ERROR) {
2943 torture_skip(tctx, "GetPrinterDataEx not supported by server\n");
2945 torture_assert_ntstatus_ok(tctx, status, "GetPrinterDataEx failed");
2948 if (W_ERROR_EQUAL(r.out.result, WERR_MORE_DATA)) {
2949 r.in.offered = needed;
2950 r.out.data = talloc_zero_array(tctx, uint8_t, r.in.offered);
2951 status = dcerpc_spoolss_GetPrinterDataEx_r(b, tctx, &r);
2952 torture_assert_ntstatus_ok(tctx, status, "GetPrinterDataEx failed");
2955 torture_assert_werr_ok(tctx, r.out.result,
2956 talloc_asprintf(tctx, "GetPrinterDataEx(%s - %s) failed", r.in.key_name, r.in.value_name));
2958 CHECK_NEEDED_SIZE_LEVEL(spoolss_PrinterData, &data, type, lp_iconv_convenience(tctx->lp_ctx), needed, 1);
2960 if (type_p) {
2961 *type_p = type;
2964 if (data_p) {
2965 *data_p = r.out.data;
2968 if (needed_p) {
2969 *needed_p = needed;
2972 return true;
2975 static bool test_GetPrinterData_list(struct torture_context *tctx,
2976 struct dcerpc_pipe *p,
2977 struct policy_handle *handle,
2978 const char **architecture)
2980 struct dcerpc_binding_handle *b = p->binding_handle;
2981 const char *list[] = {
2982 "W3SvcInstalled",
2983 "BeepEnabled",
2984 "EventLog",
2985 /* "NetPopup", not on w2k8 */
2986 /* "NetPopupToComputer", not on w2k8 */
2987 "MajorVersion",
2988 "MinorVersion",
2989 "DefaultSpoolDirectory",
2990 "Architecture",
2991 "DsPresent",
2992 "OSVersion",
2993 /* "OSVersionEx", not on s3 */
2994 "DNSMachineName"
2996 int i;
2998 for (i=0; i < ARRAY_SIZE(list); i++) {
2999 enum winreg_Type type, type_ex;
3000 uint8_t *data, *data_ex;
3001 uint32_t needed, needed_ex;
3003 torture_assert(tctx, test_GetPrinterData(tctx, b, handle, list[i], &type, &data, &needed),
3004 talloc_asprintf(tctx, "GetPrinterData failed on %s\n", list[i]));
3005 torture_assert(tctx, test_GetPrinterDataEx(tctx, p, handle, "random_string", list[i], &type_ex, &data_ex, &needed_ex),
3006 talloc_asprintf(tctx, "GetPrinterDataEx failed on %s\n", list[i]));
3007 torture_assert_int_equal(tctx, type, type_ex, "type mismatch");
3008 torture_assert_int_equal(tctx, needed, needed_ex, "needed mismatch");
3009 torture_assert_mem_equal(tctx, data, data_ex, needed, "data mismatch");
3011 if (strequal(list[i], "Architecture")) {
3012 if (architecture) {
3013 DATA_BLOB blob = data_blob_const(data, needed);
3014 *architecture = reg_val_data_string(tctx, lp_iconv_convenience(tctx->lp_ctx), REG_SZ, blob);
3019 return true;
3022 static bool test_EnumPrinterData(struct torture_context *tctx,
3023 struct dcerpc_pipe *p,
3024 struct policy_handle *handle,
3025 uint32_t enum_index,
3026 uint32_t value_offered,
3027 uint32_t data_offered,
3028 enum winreg_Type *type_p,
3029 uint32_t *value_needed_p,
3030 uint32_t *data_needed_p,
3031 const char **value_name_p,
3032 uint8_t **data_p,
3033 WERROR *result_p)
3035 struct spoolss_EnumPrinterData r;
3036 uint32_t data_needed;
3037 uint32_t value_needed;
3038 enum winreg_Type type;
3039 struct dcerpc_binding_handle *b = p->binding_handle;
3041 r.in.handle = handle;
3042 r.in.enum_index = enum_index;
3043 r.in.value_offered = value_offered;
3044 r.in.data_offered = data_offered;
3045 r.out.data_needed = &data_needed;
3046 r.out.value_needed = &value_needed;
3047 r.out.type = &type;
3048 r.out.data = talloc_zero_array(tctx, uint8_t, r.in.data_offered);
3049 r.out.value_name = talloc_zero_array(tctx, const char, r.in.value_offered);
3051 torture_comment(tctx, "Testing EnumPrinterData(%d)\n", enum_index);
3053 torture_assert_ntstatus_ok(tctx,
3054 dcerpc_spoolss_EnumPrinterData_r(b, tctx, &r),
3055 "EnumPrinterData failed");
3057 if (type_p) {
3058 *type_p = type;
3060 if (value_needed_p) {
3061 *value_needed_p = value_needed;
3063 if (data_needed_p) {
3064 *data_needed_p = data_needed;
3066 if (value_name_p) {
3067 *value_name_p = r.out.value_name;
3069 if (data_p) {
3070 *data_p = r.out.data;
3072 if (result_p) {
3073 *result_p = r.out.result;
3076 return true;
3080 static bool test_EnumPrinterData_all(struct torture_context *tctx,
3081 struct dcerpc_pipe *p,
3082 struct policy_handle *handle)
3084 uint32_t enum_index = 0;
3085 enum winreg_Type type;
3086 uint32_t value_needed;
3087 uint32_t data_needed;
3088 uint8_t *data;
3089 const char *value_name;
3090 WERROR result;
3092 torture_comment(tctx, "Testing EnumPrinterData\n");
3094 do {
3095 torture_assert(tctx,
3096 test_EnumPrinterData(tctx, p, handle, enum_index, 0, 0,
3097 &type, &value_needed, &data_needed,
3098 &value_name, &data, &result),
3099 "EnumPrinterData failed");
3101 if (W_ERROR_EQUAL(result, WERR_NO_MORE_ITEMS)) {
3102 break;
3105 torture_assert(tctx,
3106 test_EnumPrinterData(tctx, p, handle, enum_index, value_needed, data_needed,
3107 &type, &value_needed, &data_needed,
3108 &value_name, &data, &result),
3109 "EnumPrinterData failed");
3111 if (W_ERROR_EQUAL(result, WERR_NO_MORE_ITEMS)) {
3112 break;
3115 enum_index++;
3117 } while (W_ERROR_IS_OK(result));
3119 torture_comment(tctx, "EnumPrinterData test succeeded\n");
3121 return true;
3124 static bool test_EnumPrinterDataEx(struct torture_context *tctx,
3125 struct dcerpc_binding_handle *b,
3126 struct policy_handle *handle,
3127 const char *key_name,
3128 uint32_t *count_p,
3129 struct spoolss_PrinterEnumValues **info_p)
3131 struct spoolss_EnumPrinterDataEx r;
3132 struct spoolss_PrinterEnumValues *info;
3133 uint32_t needed;
3134 uint32_t count;
3136 r.in.handle = handle;
3137 r.in.key_name = key_name;
3138 r.in.offered = 0;
3139 r.out.needed = &needed;
3140 r.out.count = &count;
3141 r.out.info = &info;
3143 torture_comment(tctx, "Testing EnumPrinterDataEx(%s)\n", key_name);
3145 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_EnumPrinterDataEx_r(b, tctx, &r),
3146 "EnumPrinterDataEx failed");
3147 if (W_ERROR_EQUAL(r.out.result, WERR_MORE_DATA)) {
3148 r.in.offered = needed;
3149 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_EnumPrinterDataEx_r(b, tctx, &r),
3150 "EnumPrinterDataEx failed");
3153 torture_assert_werr_ok(tctx, r.out.result, "EnumPrinterDataEx failed");
3155 CHECK_NEEDED_SIZE_ENUM(spoolss_EnumPrinterDataEx, info, count, lp_iconv_convenience(tctx->lp_ctx), needed, 1);
3157 if (count_p) {
3158 *count_p = count;
3160 if (info_p) {
3161 *info_p = info;
3164 return true;
3167 static bool test_SetPrinterData(struct torture_context *tctx,
3168 struct dcerpc_binding_handle *b,
3169 struct policy_handle *handle,
3170 const char *value_name,
3171 enum winreg_Type type,
3172 uint8_t *data,
3173 uint32_t offered);
3174 static bool test_DeletePrinterData(struct torture_context *tctx,
3175 struct dcerpc_binding_handle *b,
3176 struct policy_handle *handle,
3177 const char *value_name);
3179 static bool test_EnumPrinterData_consistency(struct torture_context *tctx,
3180 struct dcerpc_pipe *p,
3181 struct policy_handle *handle)
3183 uint32_t count;
3184 struct spoolss_PrinterEnumValues *info;
3185 int i;
3186 uint32_t value_needed, data_needed;
3187 uint32_t value_offered, data_offered;
3188 WERROR result;
3189 struct dcerpc_binding_handle *b = p->binding_handle;
3191 enum winreg_Type type;
3192 DATA_BLOB blob;
3194 torture_comment(tctx, "Testing EnumPrinterData vs EnumPrinterDataEx consistency\n");
3196 torture_assert(tctx,
3197 reg_string_to_val(tctx, lp_iconv_convenience(tctx->lp_ctx),
3198 "REG_SZ", "torture_data1", &type, &blob), "");
3200 torture_assert(tctx,
3201 test_SetPrinterData(tctx, b, handle, "torture_value1", type, blob.data, blob.length),
3202 "SetPrinterData failed");
3204 blob = data_blob_string_const("torture_data2");
3206 torture_assert(tctx,
3207 test_SetPrinterData(tctx, b, handle, "torture_value2", REG_BINARY, blob.data, blob.length),
3208 "SetPrinterData failed");
3210 blob = data_blob_talloc(tctx, NULL, 4);
3211 SIVAL(blob.data, 0, 0x11223344);
3213 torture_assert(tctx,
3214 test_SetPrinterData(tctx, b, handle, "torture_value3", type, blob.data, blob.length),
3215 "SetPrinterData failed");
3217 torture_assert(tctx,
3218 test_EnumPrinterDataEx(tctx, b, handle, "PrinterDriverData", &count, &info),
3219 "failed to call EnumPrinterDataEx");
3221 /* get the max sizes for value and data */
3223 torture_assert(tctx,
3224 test_EnumPrinterData(tctx, p, handle, 0, 0, 0,
3225 NULL, &value_needed, &data_needed,
3226 NULL, NULL, &result),
3227 "EnumPrinterData failed");
3228 torture_assert_werr_ok(tctx, result, "unexpected result");
3230 /* check if the reply from the EnumPrinterData really matches max values */
3232 for (i=0; i < count; i++) {
3233 if (info[i].value_name_len > value_needed) {
3234 torture_fail(tctx,
3235 talloc_asprintf(tctx,
3236 "EnumPrinterDataEx gave a reply with value length %d which is larger then expected max value length %d from EnumPrinterData",
3237 info[i].value_name_len, value_needed));
3239 if (info[i].data_length > data_needed) {
3240 torture_fail(tctx,
3241 talloc_asprintf(tctx,
3242 "EnumPrinterDataEx gave a reply with data length %d which is larger then expected max data length %d from EnumPrinterData",
3243 info[i].data_length, data_needed));
3247 /* assuming that both EnumPrinterData and EnumPrinterDataEx do either
3248 * sort or not sort the replies by value name, we should be able to do
3249 * the following entry comparison */
3251 data_offered = data_needed;
3252 value_offered = value_needed;
3254 for (i=0; i < count; i++) {
3256 const char *value_name;
3257 uint8_t *data;
3259 torture_assert(tctx,
3260 test_EnumPrinterData(tctx, p, handle, i, value_offered, data_offered,
3261 &type, &value_needed, &data_needed,
3262 &value_name, &data, &result),
3263 "EnumPrinterData failed");
3265 if (i -1 == count) {
3266 torture_assert_werr_equal(tctx, result, WERR_NO_MORE_ITEMS,
3267 "unexpected result");
3268 break;
3269 } else {
3270 torture_assert_werr_ok(tctx, result, "unexpected result");
3273 torture_assert_int_equal(tctx, type, info[i].type, "type mismatch");
3274 torture_assert_int_equal(tctx, value_needed, info[i].value_name_len, "value name length mismatch");
3275 torture_assert_str_equal(tctx, value_name, info[i].value_name, "value name mismatch");
3276 torture_assert_int_equal(tctx, data_needed, info[i].data_length, "data length mismatch");
3277 torture_assert_mem_equal(tctx, data, info[i].data->data, info[i].data_length, "data mismatch");
3280 torture_assert(tctx,
3281 test_DeletePrinterData(tctx, b, handle, "torture_value1"),
3282 "DeletePrinterData failed");
3283 torture_assert(tctx,
3284 test_DeletePrinterData(tctx, b, handle, "torture_value2"),
3285 "DeletePrinterData failed");
3286 torture_assert(tctx,
3287 test_DeletePrinterData(tctx, b, handle, "torture_value3"),
3288 "DeletePrinterData failed");
3290 torture_comment(tctx, "EnumPrinterData vs EnumPrinterDataEx consistency test succeeded\n\n");
3292 return true;
3295 static bool test_DeletePrinterData(struct torture_context *tctx,
3296 struct dcerpc_binding_handle *b,
3297 struct policy_handle *handle,
3298 const char *value_name)
3300 NTSTATUS status;
3301 struct spoolss_DeletePrinterData r;
3303 r.in.handle = handle;
3304 r.in.value_name = value_name;
3306 torture_comment(tctx, "Testing DeletePrinterData(%s)\n",
3307 r.in.value_name);
3309 status = dcerpc_spoolss_DeletePrinterData_r(b, tctx, &r);
3311 torture_assert_ntstatus_ok(tctx, status, "DeletePrinterData failed");
3312 torture_assert_werr_ok(tctx, r.out.result, "DeletePrinterData failed");
3314 return true;
3317 static bool test_DeletePrinterDataEx(struct torture_context *tctx,
3318 struct dcerpc_binding_handle *b,
3319 struct policy_handle *handle,
3320 const char *key_name,
3321 const char *value_name)
3323 struct spoolss_DeletePrinterDataEx r;
3325 r.in.handle = handle;
3326 r.in.key_name = key_name;
3327 r.in.value_name = value_name;
3329 torture_comment(tctx, "Testing DeletePrinterDataEx(%s - %s)\n",
3330 r.in.key_name, r.in.value_name);
3332 torture_assert_ntstatus_ok(tctx,
3333 dcerpc_spoolss_DeletePrinterDataEx_r(b, tctx, &r),
3334 "DeletePrinterDataEx failed");
3335 torture_assert_werr_ok(tctx, r.out.result,
3336 "DeletePrinterDataEx failed");
3338 return true;
3341 static bool test_DeletePrinterKey(struct torture_context *tctx,
3342 struct dcerpc_binding_handle *b,
3343 struct policy_handle *handle,
3344 const char *key_name)
3346 struct spoolss_DeletePrinterKey r;
3348 r.in.handle = handle;
3349 r.in.key_name = key_name;
3351 torture_comment(tctx, "Testing DeletePrinterKey(%s)\n", r.in.key_name);
3353 if (strequal(key_name, "") && !torture_setting_bool(tctx, "dangerous", false)) {
3354 torture_skip(tctx, "not wiping out printer registry - enable dangerous tests to use\n");
3355 return true;
3358 torture_assert_ntstatus_ok(tctx,
3359 dcerpc_spoolss_DeletePrinterKey_r(b, tctx, &r),
3360 "DeletePrinterKey failed");
3361 torture_assert_werr_ok(tctx, r.out.result,
3362 "DeletePrinterKey failed");
3364 return true;
3367 static bool test_winreg_OpenHKLM(struct torture_context *tctx,
3368 struct dcerpc_binding_handle *b,
3369 struct policy_handle *handle)
3371 struct winreg_OpenHKLM r;
3373 r.in.system_name = NULL;
3374 r.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
3375 r.out.handle = handle;
3377 torture_comment(tctx, "Testing winreg_OpenHKLM\n");
3379 torture_assert_ntstatus_ok(tctx, dcerpc_winreg_OpenHKLM_r(b, tctx, &r), "OpenHKLM failed");
3380 torture_assert_werr_ok(tctx, r.out.result, "OpenHKLM failed");
3382 return true;
3385 static void init_winreg_String(struct winreg_String *name, const char *s)
3387 name->name = s;
3388 if (s) {
3389 name->name_len = 2 * (strlen_m(s) + 1);
3390 name->name_size = name->name_len;
3391 } else {
3392 name->name_len = 0;
3393 name->name_size = 0;
3397 static bool test_winreg_OpenKey(struct torture_context *tctx,
3398 struct dcerpc_binding_handle *b,
3399 struct policy_handle *hive_handle,
3400 const char *keyname,
3401 struct policy_handle *key_handle)
3403 struct winreg_OpenKey r;
3405 r.in.parent_handle = hive_handle;
3406 init_winreg_String(&r.in.keyname, keyname);
3407 r.in.options = REG_KEYTYPE_NON_VOLATILE;
3408 r.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
3409 r.out.handle = key_handle;
3411 torture_comment(tctx, "Testing winreg_OpenKey(%s)\n", keyname);
3413 torture_assert_ntstatus_ok(tctx, dcerpc_winreg_OpenKey_r(b, tctx, &r), "OpenKey failed");
3414 torture_assert_werr_ok(tctx, r.out.result, "OpenKey failed");
3416 return true;
3419 static bool test_winreg_CloseKey(struct torture_context *tctx,
3420 struct dcerpc_binding_handle *b,
3421 struct policy_handle *handle)
3423 struct winreg_CloseKey r;
3425 r.in.handle = handle;
3426 r.out.handle = handle;
3428 torture_comment(tctx, "Testing winreg_CloseKey\n");
3430 torture_assert_ntstatus_ok(tctx, dcerpc_winreg_CloseKey_r(b, tctx, &r), "CloseKey failed");
3431 torture_assert_werr_ok(tctx, r.out.result, "CloseKey failed");
3433 return true;
3436 bool test_winreg_QueryValue(struct torture_context *tctx,
3437 struct dcerpc_binding_handle *b,
3438 struct policy_handle *handle,
3439 const char *value_name,
3440 enum winreg_Type *type_p,
3441 uint32_t *data_size_p,
3442 uint32_t *data_length_p,
3443 uint8_t **data_p)
3445 struct winreg_QueryValue r;
3446 enum winreg_Type type = REG_NONE;
3447 uint32_t data_size = 0;
3448 uint32_t data_length = 0;
3449 struct winreg_String valuename;
3450 uint8_t *data = NULL;
3452 init_winreg_String(&valuename, value_name);
3454 data = talloc_zero_array(tctx, uint8_t, 0);
3456 r.in.handle = handle;
3457 r.in.value_name = &valuename;
3458 r.in.type = &type;
3459 r.in.data_size = &data_size;
3460 r.in.data_length = &data_length;
3461 r.in.data = data;
3462 r.out.type = &type;
3463 r.out.data = data;
3464 r.out.data_size = &data_size;
3465 r.out.data_length = &data_length;
3467 torture_comment(tctx, "Testing winreg_QueryValue(%s)\n", value_name);
3469 torture_assert_ntstatus_ok(tctx, dcerpc_winreg_QueryValue_r(b, tctx, &r), "QueryValue failed");
3470 if (W_ERROR_EQUAL(r.out.result, WERR_MORE_DATA)) {
3471 *r.in.data_size = *r.out.data_size;
3472 data = talloc_zero_array(tctx, uint8_t, *r.in.data_size);
3473 r.in.data = data;
3474 r.out.data = data;
3475 torture_assert_ntstatus_ok(tctx, dcerpc_winreg_QueryValue_r(b, tctx, &r), "QueryValue failed");
3477 torture_assert_werr_ok(tctx, r.out.result, "QueryValue failed");
3479 if (type_p) {
3480 *type_p = *r.out.type;
3482 if (data_size_p) {
3483 *data_size_p = *r.out.data_size;
3485 if (data_length_p) {
3486 *data_length_p = *r.out.data_length;
3488 if (data_p) {
3489 *data_p = r.out.data;
3492 return true;
3495 static bool test_winreg_query_printerdata(struct torture_context *tctx,
3496 struct dcerpc_binding_handle *b,
3497 struct policy_handle *handle,
3498 const char *printer_name,
3499 const char *key_name,
3500 const char *value_name,
3501 enum winreg_Type *w_type,
3502 uint32_t *w_size,
3503 uint32_t *w_length,
3504 uint8_t **w_data)
3506 const char *printer_key;
3507 struct policy_handle key_handle;
3509 printer_key = talloc_asprintf(tctx, "%s\\%s\\%s",
3510 TOP_LEVEL_PRINTER_KEY, printer_name, key_name);
3512 torture_assert(tctx,
3513 test_winreg_OpenKey(tctx, b, handle, printer_key, &key_handle), "");
3515 torture_assert(tctx,
3516 test_winreg_QueryValue(tctx, b, &key_handle, value_name, w_type, w_size, w_length, w_data), "");
3518 torture_assert(tctx,
3519 test_winreg_CloseKey(tctx, b, &key_handle), "");
3521 return true;
3524 static bool test_SetPrinterData(struct torture_context *tctx,
3525 struct dcerpc_binding_handle *b,
3526 struct policy_handle *handle,
3527 const char *value_name,
3528 enum winreg_Type type,
3529 uint8_t *data,
3530 uint32_t offered)
3532 struct spoolss_SetPrinterData r;
3534 r.in.handle = handle;
3535 r.in.value_name = value_name;
3536 r.in.type = type;
3537 r.in.data = data;
3538 r.in.offered = offered;
3540 torture_comment(tctx, "Testing SetPrinterData(%s)\n",
3541 r.in.value_name);
3543 torture_assert_ntstatus_ok(tctx,
3544 dcerpc_spoolss_SetPrinterData_r(b, tctx, &r),
3545 "SetPrinterData failed");
3546 torture_assert_werr_ok(tctx, r.out.result,
3547 "SetPrinterData failed");
3549 return true;
3552 static bool test_SetPrinterData_matrix(struct torture_context *tctx,
3553 struct dcerpc_binding_handle *b,
3554 struct policy_handle *handle,
3555 const char *printer_name,
3556 struct dcerpc_binding_handle *winreg_handle,
3557 struct policy_handle *hive_handle)
3559 const char *values[] = {
3560 "spootyfoot",
3561 "spooty\\foot",
3562 #if 0
3563 /* FIXME: not working with s3 atm. */
3564 "spooty,foot",
3565 "spooty,fo,ot",
3566 #endif
3567 "spooty foot",
3568 #if 0
3569 /* FIXME: not working with s3 atm. */
3570 "spooty\\fo,ot",
3571 "spooty,fo\\ot"
3572 #endif
3574 int i;
3576 for (i=0; i < ARRAY_SIZE(values); i++) {
3578 enum winreg_Type type;
3579 DATA_BLOB blob;
3580 uint8_t *data;
3581 uint32_t needed;
3583 torture_assert(tctx,
3584 reg_string_to_val(tctx, lp_iconv_convenience(tctx->lp_ctx),
3585 "REG_SZ", "dog", &type, &blob), "");
3587 torture_assert(tctx,
3588 test_SetPrinterData(tctx, b, handle, values[i], REG_SZ, blob.data, blob.length),
3589 "SetPrinterData failed");
3591 torture_assert(tctx,
3592 test_GetPrinterData(tctx, b, handle, values[i], &type, &data, &needed),
3593 "GetPrinterData failed");
3595 torture_assert_int_equal(tctx, type, REG_SZ, "type mismatch");
3596 torture_assert_int_equal(tctx, needed, blob.length, "size mismatch");
3597 torture_assert_mem_equal(tctx, data, blob.data, blob.length, "buffer mismatch");
3599 if (winreg_handle && hive_handle) {
3601 enum winreg_Type w_type;
3602 uint32_t w_size;
3603 uint32_t w_length;
3604 uint8_t *w_data;
3606 torture_assert(tctx,
3607 test_winreg_query_printerdata(tctx, winreg_handle, hive_handle,
3608 printer_name, "PrinterDriverData", values[i],
3609 &w_type, &w_size, &w_length, &w_data), "");
3611 torture_assert_int_equal(tctx, w_type, REG_SZ, "winreg type mismatch");
3612 torture_assert_int_equal(tctx, w_size, blob.length, "winreg size mismatch");
3613 torture_assert_int_equal(tctx, w_length, blob.length, "winreg length mismatch");
3614 torture_assert_mem_equal(tctx, w_data, blob.data, blob.length, "winreg buffer mismatch");
3617 torture_assert(tctx,
3618 test_DeletePrinterData(tctx, b, handle, values[i]),
3619 "DeletePrinterData failed");
3622 return true;
3626 static bool test_EnumPrinterKey(struct torture_context *tctx,
3627 struct dcerpc_binding_handle *b,
3628 struct policy_handle *handle,
3629 const char *key_name,
3630 const char ***array);
3632 static bool test_SetPrinterDataEx(struct torture_context *tctx,
3633 struct dcerpc_binding_handle *b,
3634 struct policy_handle *handle,
3635 const char *key_name,
3636 const char *value_name,
3637 enum winreg_Type type,
3638 uint8_t *data,
3639 uint32_t offered)
3641 NTSTATUS status;
3642 struct spoolss_SetPrinterDataEx r;
3644 r.in.handle = handle;
3645 r.in.key_name = key_name;
3646 r.in.value_name = value_name;
3647 r.in.type = type;
3648 r.in.data = data;
3649 r.in.offered = offered;
3651 torture_comment(tctx, "Testing SetPrinterDataEx(%s - %s) type: %s, offered: 0x%08x\n",
3652 r.in.key_name, r.in.value_name, str_regtype(r.in.type), r.in.offered);
3654 status = dcerpc_spoolss_SetPrinterDataEx_r(b, tctx, &r);
3656 torture_assert_ntstatus_ok(tctx, status, "SetPrinterDataEx failed");
3657 torture_assert_werr_ok(tctx, r.out.result, "SetPrinterDataEx failed");
3659 return true;
3662 static bool test_SetPrinterDataEx_matrix(struct torture_context *tctx,
3663 struct dcerpc_pipe *p,
3664 struct policy_handle *handle,
3665 const char *printername,
3666 struct dcerpc_binding_handle *winreg_handle,
3667 struct policy_handle *hive_handle)
3669 struct dcerpc_binding_handle *b = p->binding_handle;
3670 const char *value_name = "dog";
3671 const char *keys[] = {
3672 "torturedataex",
3673 "torture data ex",
3674 #if 0
3675 /* FIXME: not working with s3 atm. */
3676 "torturedataex_with_subkey\\subkey",
3677 "torturedataex_with_subkey\\subkey:0",
3678 "torturedataex_with_subkey\\subkey:1",
3679 "torturedataex_with_subkey\\subkey\\subsubkey",
3680 "torturedataex_with_subkey\\subkey\\subsubkey:0",
3681 "torturedataex_with_subkey\\subkey\\subsubkey:1",
3682 #endif
3683 "torture,data",
3684 #if 0
3685 /* FIXME: not working with s3 atm. */
3687 "torture,data,ex",
3688 "torture,data\\ex",
3689 "torture\\data,ex"
3690 #endif
3692 enum winreg_Type types[] = {
3693 REG_SZ,
3694 REG_MULTI_SZ,
3695 REG_DWORD,
3696 REG_BINARY
3698 const char *str = "abcdefghijklmnopqrstuvwxzy";
3699 int i, t, s;
3702 for (i=0; i < ARRAY_SIZE(keys); i++) {
3703 for (t=0; t < ARRAY_SIZE(types); t++) {
3704 for (s=0; s < strlen(str); s++) {
3706 char *c;
3707 const char *key;
3708 enum winreg_Type type;
3709 const char *string = talloc_strndup(tctx, str, s);
3710 DATA_BLOB blob = data_blob_string_const(string);
3711 const char **subkeys;
3712 DATA_BLOB data;
3713 uint8_t *data_out;
3714 uint32_t needed, offered = 0;
3715 uint32_t ecount;
3716 struct spoolss_PrinterEnumValues *einfo;
3718 if (types[t] == REG_DWORD) {
3719 s = 0xffff;
3722 if (torture_setting_bool(tctx, "samba3", false)) {
3723 if ((types[t] == REG_MULTI_SZ) && s == 0) {
3724 torture_warning(tctx, "samba3 does not handle 4 byte emtpy REG_MULTI_SZ buffers");
3725 continue;
3729 switch (types[t]) {
3730 case REG_BINARY:
3731 data = blob;
3732 offered = blob.length;
3733 break;
3734 case REG_DWORD:
3735 data = data_blob_talloc(tctx, NULL, 4);
3736 SIVAL(data.data, 0, 0x12345678);
3737 offered = 4;
3738 break;
3739 case REG_SZ:
3740 torture_assert(tctx,
3741 reg_string_to_val(tctx, lp_iconv_convenience(tctx->lp_ctx),
3742 "REG_SZ", string, &type, &data), "");
3743 offered = data.length;
3744 /*strlen_m_term(data.string)*2;*/
3745 break;
3746 case REG_MULTI_SZ:
3747 torture_assert(tctx,
3748 reg_string_to_val(tctx, lp_iconv_convenience(tctx->lp_ctx),
3749 "REG_SZ", string, &type, &data), "");
3750 torture_assert(tctx, data_blob_realloc(tctx, &data, data.length + 2), "");
3751 memset(&data.data[data.length - 2], '\0', 2);
3752 offered = data.length;
3753 break;
3754 default:
3755 torture_fail(tctx, talloc_asprintf(tctx, "type %d untested\n", types[t]));
3758 torture_assert(tctx,
3759 test_SetPrinterDataEx(tctx, b, handle, keys[i], value_name, types[t], data.data, offered),
3760 "failed to call SetPrinterDataEx");
3762 torture_assert(tctx,
3763 test_GetPrinterDataEx(tctx, p, handle, keys[i], value_name, &type, &data_out, &needed),
3764 "failed to call GetPrinterDataEx");
3766 torture_assert(tctx,
3767 test_EnumPrinterDataEx(tctx, b, handle, keys[i], &ecount, &einfo),
3768 "failed to call EnumPrinterDataEx");
3770 torture_assert_int_equal(tctx, types[t], type, "type mismatch");
3771 torture_assert_int_equal(tctx, needed, offered, "size mismatch");
3772 torture_assert_mem_equal(tctx, data_out, data.data, offered, "buffer mismatch");
3774 torture_assert_int_equal(tctx, ecount, 1, "unexpected enum count");
3775 torture_assert_str_equal(tctx, einfo[0].value_name, value_name, "value_name mismatch");
3776 torture_assert_int_equal(tctx, einfo[0].value_name_len, strlen_m_term(value_name)*2, "unexpected value_name_len");
3777 torture_assert_int_equal(tctx, einfo[0].type, types[t], "type mismatch");
3778 torture_assert_int_equal(tctx, einfo[0].data_length, offered, "size mismatch");
3779 if (einfo[0].data_length > 0) {
3780 torture_assert_mem_equal(tctx, einfo[0].data->data, data.data, offered, "buffer mismatch");
3783 if (winreg_handle && hive_handle) {
3784 enum winreg_Type w_type;
3785 uint32_t w_size;
3786 uint32_t w_length;
3787 uint8_t *w_data;
3789 torture_assert(tctx,
3790 test_winreg_query_printerdata(tctx, winreg_handle, hive_handle,
3791 printername, keys[i], value_name,
3792 &w_type, &w_size, &w_length, &w_data), "");
3794 torture_assert_int_equal(tctx, w_type, types[t], "winreg type mismatch");
3795 torture_assert_int_equal(tctx, w_size, offered, "winreg size mismatch");
3796 torture_assert_int_equal(tctx, w_length, offered, "winreg length mismatch");
3797 torture_assert_mem_equal(tctx, w_data, data.data, offered, "winreg buffer mismatch");
3800 key = talloc_strdup(tctx, keys[i]);
3802 if (!test_DeletePrinterDataEx(tctx, b, handle, keys[i], value_name)) {
3803 return false;
3806 c = strchr(key, '\\');
3807 if (c) {
3808 int k;
3810 /* we have subkeys */
3812 *c = 0;
3814 if (!test_EnumPrinterKey(tctx, b, handle, key, &subkeys)) {
3815 return false;
3818 for (k=0; subkeys && subkeys[k]; k++) {
3820 const char *current_key = talloc_asprintf(tctx, "%s\\%s", key, subkeys[k]);
3822 if (!test_DeletePrinterKey(tctx, b, handle, current_key)) {
3823 return false;
3827 if (!test_DeletePrinterKey(tctx, b, handle, key)) {
3828 return false;
3831 } else {
3832 if (!test_DeletePrinterKey(tctx, b, handle, key)) {
3833 return false;
3840 return true;
3843 static bool test_PrinterData_winreg(struct torture_context *tctx,
3844 struct dcerpc_pipe *p,
3845 struct policy_handle *handle,
3846 const char *printer_name)
3848 struct dcerpc_binding_handle *b = p->binding_handle;
3849 struct dcerpc_pipe *p2;
3850 bool ret = true;
3851 struct policy_handle hive_handle;
3852 struct dcerpc_binding_handle *b2;
3854 torture_assert_ntstatus_ok(tctx,
3855 torture_rpc_connection(tctx, &p2, &ndr_table_winreg),
3856 "could not open winreg pipe");
3857 b2 = p2->binding_handle;
3859 torture_assert(tctx, test_winreg_OpenHKLM(tctx, b2, &hive_handle), "");
3861 ret &= test_SetPrinterData_matrix(tctx, b, handle, printer_name, b2, &hive_handle);
3862 ret &= test_SetPrinterDataEx_matrix(tctx, p, handle, printer_name, b2, &hive_handle);
3864 test_winreg_CloseKey(tctx, b2, &hive_handle);
3866 talloc_free(p2);
3868 return ret;
3871 static bool test_GetChangeID_PrinterData(struct torture_context *tctx,
3872 struct dcerpc_binding_handle *b,
3873 struct policy_handle *handle,
3874 uint32_t *change_id)
3876 enum winreg_Type type;
3877 uint8_t *data;
3878 uint32_t needed;
3880 torture_assert(tctx,
3881 test_GetPrinterData(tctx, b, handle, "ChangeID", &type, &data, &needed),
3882 "failed to call GetPrinterData");
3884 torture_assert(tctx, type == REG_DWORD, "unexpected type");
3885 torture_assert_int_equal(tctx, needed, 4, "unexpected size");
3887 *change_id = IVAL(data, 0);
3889 return true;
3892 static bool test_GetChangeID_PrinterDataEx(struct torture_context *tctx,
3893 struct dcerpc_pipe *p,
3894 struct policy_handle *handle,
3895 uint32_t *change_id)
3897 enum winreg_Type type;
3898 uint8_t *data;
3899 uint32_t needed;
3901 torture_assert(tctx,
3902 test_GetPrinterDataEx(tctx, p, handle, "PrinterDriverData", "ChangeID", &type, &data, &needed),
3903 "failed to call GetPrinterData");
3905 torture_assert(tctx, type == REG_DWORD, "unexpected type");
3906 torture_assert_int_equal(tctx, needed, 4, "unexpected size");
3908 *change_id = IVAL(data, 0);
3910 return true;
3913 static bool test_GetChangeID_PrinterInfo(struct torture_context *tctx,
3914 struct dcerpc_binding_handle *b,
3915 struct policy_handle *handle,
3916 uint32_t *change_id)
3918 union spoolss_PrinterInfo info;
3920 torture_assert(tctx, test_GetPrinter_level(tctx, b, handle, 0, &info),
3921 "failed to query Printer level 0");
3923 *change_id = info.info0.change_id;
3925 return true;
3928 static bool test_ChangeID(struct torture_context *tctx,
3929 struct dcerpc_pipe *p,
3930 struct policy_handle *handle)
3932 uint32_t change_id, change_id_ex, change_id_info;
3933 uint32_t change_id2, change_id_ex2, change_id_info2;
3934 union spoolss_PrinterInfo info;
3935 const char *comment;
3936 struct dcerpc_binding_handle *b = p->binding_handle;
3938 torture_comment(tctx, "Testing ChangeID: id change test #1\n");
3940 torture_assert(tctx, test_GetChangeID_PrinterData(tctx, b, handle, &change_id),
3941 "failed to query for ChangeID");
3942 torture_assert(tctx, test_GetChangeID_PrinterDataEx(tctx, p, handle, &change_id_ex),
3943 "failed to query for ChangeID");
3944 torture_assert(tctx, test_GetChangeID_PrinterInfo(tctx, b, handle, &change_id_info),
3945 "failed to query for ChangeID");
3947 torture_assert_int_equal(tctx, change_id, change_id_ex,
3948 "change_ids should all be equal");
3949 torture_assert_int_equal(tctx, change_id_ex, change_id_info,
3950 "change_ids should all be equal");
3953 torture_comment(tctx, "Testing ChangeID: id change test #2\n");
3955 torture_assert(tctx, test_GetChangeID_PrinterData(tctx, b, handle, &change_id),
3956 "failed to query for ChangeID");
3957 torture_assert(tctx, test_GetPrinter_level(tctx, b, handle, 2, &info),
3958 "failed to query Printer level 2");
3959 torture_assert(tctx, test_GetChangeID_PrinterDataEx(tctx, p, handle, &change_id_ex),
3960 "failed to query for ChangeID");
3961 torture_assert(tctx, test_GetChangeID_PrinterInfo(tctx, b, handle, &change_id_info),
3962 "failed to query for ChangeID");
3963 torture_assert_int_equal(tctx, change_id, change_id_ex,
3964 "change_id should not have changed");
3965 torture_assert_int_equal(tctx, change_id_ex, change_id_info,
3966 "change_id should not have changed");
3969 torture_comment(tctx, "Testing ChangeID: id change test #3\n");
3971 torture_assert(tctx, test_GetChangeID_PrinterData(tctx, b, handle, &change_id),
3972 "failed to query for ChangeID");
3973 torture_assert(tctx, test_GetChangeID_PrinterDataEx(tctx, p, handle, &change_id_ex),
3974 "failed to query for ChangeID");
3975 torture_assert(tctx, test_GetChangeID_PrinterInfo(tctx, b, handle, &change_id_info),
3976 "failed to query for ChangeID");
3977 torture_assert(tctx, test_GetPrinter_level(tctx, b, handle, 2, &info),
3978 "failed to query Printer level 2");
3979 comment = talloc_strdup(tctx, info.info2.comment);
3982 struct spoolss_SetPrinterInfoCtr info_ctr;
3983 struct spoolss_DevmodeContainer devmode_ctr;
3984 struct sec_desc_buf secdesc_ctr;
3985 union spoolss_SetPrinterInfo sinfo;
3987 ZERO_STRUCT(info_ctr);
3988 ZERO_STRUCT(devmode_ctr);
3989 ZERO_STRUCT(secdesc_ctr);
3992 torture_assert(tctx, PrinterInfo_to_SetPrinterInfo(tctx, &info, 2, &sinfo), "");
3993 sinfo.info2->comment = "torture_comment";
3995 info_ctr.level = 2;
3996 info_ctr.info = sinfo;
3998 torture_assert(tctx, test_SetPrinter(tctx, b, handle, &info_ctr, &devmode_ctr, &secdesc_ctr, 0),
3999 "failed to call SetPrinter");
4001 sinfo.info2->comment = comment;
4003 torture_assert(tctx, test_SetPrinter(tctx, b, handle, &info_ctr, &devmode_ctr, &secdesc_ctr, 0),
4004 "failed to call SetPrinter");
4008 torture_assert(tctx, test_GetChangeID_PrinterData(tctx, b, handle, &change_id2),
4009 "failed to query for ChangeID");
4010 torture_assert(tctx, test_GetChangeID_PrinterDataEx(tctx, p, handle, &change_id_ex2),
4011 "failed to query for ChangeID");
4012 torture_assert(tctx, test_GetChangeID_PrinterInfo(tctx, b, handle, &change_id_info2),
4013 "failed to query for ChangeID");
4015 torture_assert_int_equal(tctx, change_id2, change_id_ex2,
4016 "change_ids should all be equal");
4017 torture_assert_int_equal(tctx, change_id_ex2, change_id_info2,
4018 "change_ids should all be equal");
4020 torture_assert(tctx, (change_id < change_id2),
4021 talloc_asprintf(tctx, "change_id %d needs to be larger than change_id %d",
4022 change_id2, change_id));
4023 torture_assert(tctx, (change_id_ex < change_id_ex2),
4024 talloc_asprintf(tctx, "change_id %d needs to be larger than change_id %d",
4025 change_id_ex2, change_id_ex));
4026 torture_assert(tctx, (change_id_info < change_id_info2),
4027 talloc_asprintf(tctx, "change_id %d needs to be larger than change_id %d",
4028 change_id_info2, change_id_info));
4030 torture_comment(tctx, "ChangeID tests succeeded\n\n");
4032 return true;
4035 static bool test_SecondaryClosePrinter(struct torture_context *tctx,
4036 struct dcerpc_pipe *p,
4037 struct policy_handle *handle)
4039 NTSTATUS status;
4040 struct dcerpc_binding *b;
4041 struct dcerpc_pipe *p2;
4042 struct spoolss_ClosePrinter cp;
4044 /* only makes sense on SMB */
4045 if (p->conn->transport.transport != NCACN_NP) {
4046 return true;
4049 torture_comment(tctx, "testing close on secondary pipe\n");
4051 status = dcerpc_parse_binding(tctx, p->conn->binding_string, &b);
4052 torture_assert_ntstatus_ok(tctx, status, "Failed to parse dcerpc binding");
4054 status = dcerpc_secondary_connection(p, &p2, b);
4055 torture_assert_ntstatus_ok(tctx, status, "Failed to create secondary connection");
4057 status = dcerpc_bind_auth_none(p2, &ndr_table_spoolss);
4058 torture_assert_ntstatus_ok(tctx, status, "Failed to create bind on secondary connection");
4060 cp.in.handle = handle;
4061 cp.out.handle = handle;
4063 status = dcerpc_spoolss_ClosePrinter_r(p2->binding_handle, tctx, &cp);
4064 torture_assert_ntstatus_equal(tctx, status, NT_STATUS_NET_WRITE_FAULT,
4065 "ERROR: Allowed close on secondary connection");
4067 torture_assert_int_equal(tctx, p2->last_fault_code, DCERPC_FAULT_CONTEXT_MISMATCH,
4068 "Unexpected fault code");
4070 talloc_free(p2);
4072 return true;
4075 static bool test_OpenPrinter_badname(struct torture_context *tctx,
4076 struct dcerpc_binding_handle *b, const char *name)
4078 NTSTATUS status;
4079 struct spoolss_OpenPrinter op;
4080 struct spoolss_OpenPrinterEx opEx;
4081 struct policy_handle handle;
4082 bool ret = true;
4084 op.in.printername = name;
4085 op.in.datatype = NULL;
4086 op.in.devmode_ctr.devmode= NULL;
4087 op.in.access_mask = 0;
4088 op.out.handle = &handle;
4090 torture_comment(tctx, "Testing OpenPrinter(%s) with bad name\n", op.in.printername);
4092 status = dcerpc_spoolss_OpenPrinter_r(b, tctx, &op);
4093 torture_assert_ntstatus_ok(tctx, status, "OpenPrinter failed");
4094 torture_assert_werr_equal(tctx, op.out.result, WERR_INVALID_PRINTER_NAME,
4095 "unexpected result");
4097 if (W_ERROR_IS_OK(op.out.result)) {
4098 ret &=test_ClosePrinter(tctx, b, &handle);
4101 opEx.in.printername = name;
4102 opEx.in.datatype = NULL;
4103 opEx.in.devmode_ctr.devmode = NULL;
4104 opEx.in.access_mask = 0;
4105 opEx.in.level = 1;
4106 opEx.in.userlevel.level1 = NULL;
4107 opEx.out.handle = &handle;
4109 torture_comment(tctx, "Testing OpenPrinterEx(%s) with bad name\n", opEx.in.printername);
4111 status = dcerpc_spoolss_OpenPrinterEx_r(b, tctx, &opEx);
4112 torture_assert_ntstatus_ok(tctx, status, "OpenPrinterEx failed");
4113 torture_assert_werr_equal(tctx, opEx.out.result, WERR_INVALID_PARAM,
4114 "unexpected result");
4116 if (W_ERROR_IS_OK(opEx.out.result)) {
4117 ret &=test_ClosePrinter(tctx, b, &handle);
4120 return ret;
4123 static bool test_OpenPrinter(struct torture_context *tctx,
4124 struct dcerpc_pipe *p,
4125 const char *name,
4126 const char *environment)
4128 NTSTATUS status;
4129 struct spoolss_OpenPrinter r;
4130 struct policy_handle handle;
4131 bool ret = true;
4132 struct dcerpc_binding_handle *b = p->binding_handle;
4134 r.in.printername = talloc_asprintf(tctx, "\\\\%s\\%s", dcerpc_server_name(p), name);
4135 r.in.datatype = NULL;
4136 r.in.devmode_ctr.devmode= NULL;
4137 r.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
4138 r.out.handle = &handle;
4140 torture_comment(tctx, "Testing OpenPrinter(%s)\n", r.in.printername);
4142 status = dcerpc_spoolss_OpenPrinter_r(b, tctx, &r);
4144 torture_assert_ntstatus_ok(tctx, status, "OpenPrinter failed");
4146 torture_assert_werr_ok(tctx, r.out.result, "OpenPrinter failed");
4148 if (!test_GetPrinter(tctx, b, &handle, environment)) {
4149 ret = false;
4152 if (!torture_setting_bool(tctx, "samba3", false)) {
4153 if (!test_SecondaryClosePrinter(tctx, p, &handle)) {
4154 ret = false;
4158 if (!test_ClosePrinter(tctx, b, &handle)) {
4159 ret = false;
4162 return ret;
4165 static bool call_OpenPrinterEx(struct torture_context *tctx,
4166 struct dcerpc_pipe *p,
4167 const char *name,
4168 struct spoolss_DeviceMode *devmode,
4169 struct policy_handle *handle)
4171 struct spoolss_OpenPrinterEx r;
4172 struct spoolss_UserLevel1 userlevel1;
4173 NTSTATUS status;
4174 struct dcerpc_binding_handle *b = p->binding_handle;
4176 if (name && name[0]) {
4177 r.in.printername = talloc_asprintf(tctx, "\\\\%s\\%s",
4178 dcerpc_server_name(p), name);
4179 } else {
4180 r.in.printername = talloc_asprintf(tctx, "\\\\%s",
4181 dcerpc_server_name(p));
4184 r.in.datatype = NULL;
4185 r.in.devmode_ctr.devmode= devmode;
4186 r.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
4187 r.in.level = 1;
4188 r.in.userlevel.level1 = &userlevel1;
4189 r.out.handle = handle;
4191 userlevel1.size = 1234;
4192 userlevel1.client = "hello";
4193 userlevel1.user = "spottyfoot!";
4194 userlevel1.build = 1;
4195 userlevel1.major = 2;
4196 userlevel1.minor = 3;
4197 userlevel1.processor = 4;
4199 torture_comment(tctx, "Testing OpenPrinterEx(%s)\n", r.in.printername);
4201 status = dcerpc_spoolss_OpenPrinterEx_r(b, tctx, &r);
4203 torture_assert_ntstatus_ok(tctx, status, "OpenPrinterEx failed");
4205 torture_assert_werr_ok(tctx, r.out.result, "OpenPrinterEx failed");
4207 return true;
4210 static bool test_printer_rename(struct torture_context *tctx,
4211 struct dcerpc_pipe *p,
4212 struct policy_handle *handle,
4213 const char *name)
4215 bool ret = true;
4216 union spoolss_PrinterInfo info;
4217 union spoolss_SetPrinterInfo sinfo;
4218 struct spoolss_SetPrinterInfoCtr info_ctr;
4219 struct spoolss_DevmodeContainer devmode_ctr;
4220 struct sec_desc_buf secdesc_ctr;
4221 const char *printer_name;
4222 const char *printer_name_orig;
4223 const char *printer_name_new = "SAMBA smbtorture Test Printer (Copy 2)";
4224 struct policy_handle new_handle;
4225 const char *q;
4226 struct dcerpc_binding_handle *b = p->binding_handle;
4228 ZERO_STRUCT(devmode_ctr);
4229 ZERO_STRUCT(secdesc_ctr);
4231 torture_comment(tctx, "Testing Printer rename operations\n");
4233 torture_assert(tctx,
4234 test_GetPrinter_level(tctx, b, handle, 2, &info),
4235 "failed to call GetPrinter level 2");
4237 printer_name_orig = talloc_strdup(tctx, info.info2.printername);
4239 q = strrchr(info.info2.printername, '\\');
4240 if (q) {
4241 torture_warning(tctx,
4242 "server returns printername %s incl. servername although we did not set servername", info.info2.printername);
4245 torture_assert(tctx,
4246 PrinterInfo_to_SetPrinterInfo(tctx, &info, 2, &sinfo), "");
4248 sinfo.info2->printername = printer_name_new;
4250 info_ctr.level = 2;
4251 info_ctr.info = sinfo;
4253 torture_assert(tctx,
4254 test_SetPrinter(tctx, b, handle, &info_ctr, &devmode_ctr, &secdesc_ctr, 0),
4255 "failed to call SetPrinter level 2");
4257 torture_assert(tctx,
4258 test_GetPrinter_level(tctx, b, handle, 2, &info),
4259 "failed to call GetPrinter level 2");
4261 printer_name = talloc_strdup(tctx, info.info2.printername);
4263 q = strrchr(info.info2.printername, '\\');
4264 if (q) {
4265 torture_warning(tctx,
4266 "server returns printername %s incl. servername although we did not set servername", info.info2.printername);
4267 q++;
4268 printer_name = q;
4271 torture_assert_str_equal(tctx, printer_name, printer_name_new,
4272 "new printer name was not set");
4274 /* samba currently cannot fully rename printers */
4275 if (!torture_setting_bool(tctx, "samba3", false)) {
4276 torture_assert(tctx,
4277 test_OpenPrinter_badname(tctx, b, printer_name_orig),
4278 "still can open printer with oldname after rename");
4279 } else {
4280 torture_warning(tctx, "*not* checking for open with oldname after rename for samba3");
4283 torture_assert(tctx,
4284 call_OpenPrinterEx(tctx, p, printer_name_new, NULL, &new_handle),
4285 "failed to open printer with new name");
4287 torture_assert(tctx,
4288 test_GetPrinter_level(tctx, b, &new_handle, 2, &info),
4289 "failed to call GetPrinter level 2");
4291 /* FIXME: we openend with servername! */
4292 printer_name = talloc_asprintf(tctx, "\\\\%s\\%s",
4293 dcerpc_server_name(p), printer_name_new);
4295 torture_assert_str_equal(tctx, info.info2.printername, printer_name,
4296 "new printer name was not set");
4298 torture_assert(tctx,
4299 test_ClosePrinter(tctx, b, &new_handle),
4300 "failed to close printer");
4302 torture_comment(tctx, "Printer rename operations test succeeded\n\n");
4304 return ret;
4308 static bool test_OpenPrinterEx(struct torture_context *tctx,
4309 struct dcerpc_pipe *p,
4310 const char *name,
4311 const char *environment)
4313 struct policy_handle handle;
4314 bool ret = true;
4315 struct dcerpc_binding_handle *b = p->binding_handle;
4317 if (!call_OpenPrinterEx(tctx, p, name, NULL, &handle)) {
4318 return false;
4321 if (!test_PrinterInfo_SD(tctx, b, &handle)) {
4322 ret = false;
4325 if (!test_GetPrinter(tctx, b, &handle, environment)) {
4326 ret = false;
4329 if (!test_EnumForms(tctx, b, &handle, false)) {
4330 ret = false;
4333 if (!test_AddForm(tctx, b, &handle, false)) {
4334 ret = false;
4337 if (!test_EnumPrinterData_all(tctx, p, &handle)) {
4338 ret = false;
4341 if (!test_EnumPrinterDataEx(tctx, b, &handle, "PrinterDriverData", NULL, NULL)) {
4342 ret = false;
4345 if (!test_EnumPrinterData_consistency(tctx, p, &handle)) {
4346 ret = false;
4349 if (!test_printer_keys(tctx, b, &handle)) {
4350 ret = false;
4353 if (!test_PausePrinter(tctx, b, &handle)) {
4354 ret = false;
4357 if (!test_DoPrintTest(tctx, b, &handle)) {
4358 ret = false;
4361 if (!test_ResumePrinter(tctx, b, &handle)) {
4362 ret = false;
4365 if (!test_SetPrinterData_matrix(tctx, b, &handle, name, NULL, NULL)) {
4366 ret = false;
4369 if (!test_SetPrinterDataEx_matrix(tctx, p, &handle, name, NULL, NULL)) {
4370 ret = false;
4373 if (!torture_setting_bool(tctx, "samba3", false)) {
4374 if (!test_SecondaryClosePrinter(tctx, p, &handle)) {
4375 ret = false;
4379 if (!test_ClosePrinter(tctx, b, &handle)) {
4380 ret = false;
4383 return ret;
4386 static bool test_EnumPrinters_old(struct torture_context *tctx,
4387 struct dcerpc_pipe *p,
4388 const char *environment)
4390 struct spoolss_EnumPrinters r;
4391 NTSTATUS status;
4392 uint16_t levels[] = {1, 2, 4, 5};
4393 int i;
4394 bool ret = true;
4395 struct dcerpc_binding_handle *b = p->binding_handle;
4397 for (i=0;i<ARRAY_SIZE(levels);i++) {
4398 union spoolss_PrinterInfo *info;
4399 int j;
4400 uint32_t needed;
4401 uint32_t count;
4403 r.in.flags = PRINTER_ENUM_LOCAL;
4404 r.in.server = "";
4405 r.in.level = levels[i];
4406 r.in.buffer = NULL;
4407 r.in.offered = 0;
4408 r.out.needed = &needed;
4409 r.out.count = &count;
4410 r.out.info = &info;
4412 torture_comment(tctx, "Testing EnumPrinters level %u\n", r.in.level);
4414 status = dcerpc_spoolss_EnumPrinters_r(b, tctx, &r);
4415 torture_assert_ntstatus_ok(tctx, status, "EnumPrinters failed");
4417 if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
4418 DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed);
4419 data_blob_clear(&blob);
4420 r.in.buffer = &blob;
4421 r.in.offered = needed;
4422 status = dcerpc_spoolss_EnumPrinters_r(b, tctx, &r);
4425 torture_assert_ntstatus_ok(tctx, status, "EnumPrinters failed");
4427 torture_assert_werr_ok(tctx, r.out.result, "EnumPrinters failed");
4429 CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumPrinters, info, r.in.level, count, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
4431 if (!info) {
4432 torture_comment(tctx, "No printers returned\n");
4433 return true;
4436 for (j=0;j<count;j++) {
4437 if (r.in.level == 1) {
4438 char *unc = talloc_strdup(tctx, info[j].info1.name);
4439 char *slash, *name;
4440 name = unc;
4441 if (unc[0] == '\\' && unc[1] == '\\') {
4442 unc +=2;
4444 slash = strchr(unc, '\\');
4445 if (slash) {
4446 slash++;
4447 name = slash;
4449 if (!test_OpenPrinter(tctx, p, name, environment)) {
4450 ret = false;
4452 if (!test_OpenPrinterEx(tctx, p, name, environment)) {
4453 ret = false;
4459 return ret;
4462 static bool test_GetPrinterDriver(struct torture_context *tctx,
4463 struct dcerpc_binding_handle *b,
4464 struct policy_handle *handle,
4465 const char *driver_name)
4467 struct spoolss_GetPrinterDriver r;
4468 uint32_t needed;
4470 r.in.handle = handle;
4471 r.in.architecture = "W32X86";
4472 r.in.level = 1;
4473 r.in.buffer = NULL;
4474 r.in.offered = 0;
4475 r.out.needed = &needed;
4477 torture_comment(tctx, "Testing GetPrinterDriver level %d\n", r.in.level);
4479 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_GetPrinterDriver_r(b, tctx, &r),
4480 "failed to call GetPrinterDriver");
4481 if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
4482 DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed);
4483 data_blob_clear(&blob);
4484 r.in.buffer = &blob;
4485 r.in.offered = needed;
4486 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_GetPrinterDriver_r(b, tctx, &r),
4487 "failed to call GetPrinterDriver");
4490 torture_assert_werr_ok(tctx, r.out.result,
4491 "failed to call GetPrinterDriver");
4493 CHECK_NEEDED_SIZE_LEVEL(spoolss_DriverInfo, r.out.info, r.in.level, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
4495 return true;
4498 static bool test_GetPrinterDriver2(struct torture_context *tctx,
4499 struct dcerpc_binding_handle *b,
4500 struct policy_handle *handle,
4501 const char *driver_name,
4502 const char *architecture)
4504 struct spoolss_GetPrinterDriver2 r;
4505 uint16_t levels[] = {1, 2, 3, 4, 5, 6, 8, 101 };
4506 uint32_t needed;
4507 uint32_t server_major_version;
4508 uint32_t server_minor_version;
4509 int i;
4511 r.in.handle = handle;
4512 r.in.architecture = architecture;
4513 r.in.client_major_version = 3;
4514 r.in.client_minor_version = 0;
4515 r.out.needed = &needed;
4516 r.out.server_major_version = &server_major_version;
4517 r.out.server_minor_version = &server_minor_version;
4519 for (i=0;i<ARRAY_SIZE(levels);i++) {
4521 r.in.buffer = NULL;
4522 r.in.offered = 0;
4523 r.in.level = levels[i];
4525 torture_comment(tctx, "Testing GetPrinterDriver2(%s) level %d\n",
4526 driver_name, r.in.level);
4528 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_GetPrinterDriver2_r(b, tctx, &r),
4529 "failed to call GetPrinterDriver2");
4530 if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
4531 DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed);
4532 data_blob_clear(&blob);
4533 r.in.buffer = &blob;
4534 r.in.offered = needed;
4535 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_GetPrinterDriver2_r(b, tctx, &r),
4536 "failed to call GetPrinterDriver2");
4539 if (W_ERROR_EQUAL(r.out.result, WERR_INVALID_LEVEL)) {
4540 switch (r.in.level) {
4541 case 101:
4542 case 8:
4543 continue;
4544 default:
4545 break;
4549 torture_assert_werr_ok(tctx, r.out.result,
4550 "failed to call GetPrinterDriver2");
4552 CHECK_NEEDED_SIZE_LEVEL(spoolss_DriverInfo, r.out.info, r.in.level, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
4555 return true;
4558 static bool test_EnumPrinterDrivers_old(struct torture_context *tctx,
4559 struct dcerpc_pipe *p,
4560 const char *environment)
4562 struct spoolss_EnumPrinterDrivers r;
4563 NTSTATUS status;
4564 uint16_t levels[] = {1, 2, 3, 4, 5, 6};
4565 int i;
4566 struct dcerpc_binding_handle *b = p->binding_handle;
4568 for (i=0;i<ARRAY_SIZE(levels);i++) {
4570 uint32_t needed;
4571 uint32_t count;
4572 union spoolss_DriverInfo *info;
4574 r.in.server = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
4575 r.in.environment = environment;
4576 r.in.level = levels[i];
4577 r.in.buffer = NULL;
4578 r.in.offered = 0;
4579 r.out.needed = &needed;
4580 r.out.count = &count;
4581 r.out.info = &info;
4583 torture_comment(tctx, "Testing EnumPrinterDrivers level %u\n", r.in.level);
4585 status = dcerpc_spoolss_EnumPrinterDrivers_r(b, tctx, &r);
4587 torture_assert_ntstatus_ok(tctx, status, "EnumPrinterDrivers failed");
4589 if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
4590 DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed);
4591 data_blob_clear(&blob);
4592 r.in.buffer = &blob;
4593 r.in.offered = needed;
4594 status = dcerpc_spoolss_EnumPrinterDrivers_r(b, tctx, &r);
4597 torture_assert_ntstatus_ok(tctx, status, "EnumPrinterDrivers failed");
4599 torture_assert_werr_ok(tctx, r.out.result, "EnumPrinterDrivers failed");
4601 if (!info) {
4602 torture_comment(tctx, "No printer drivers returned\n");
4603 break;
4606 CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumPrinterDrivers, info, r.in.level, count, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
4609 return true;
4612 static bool test_DeletePrinter(struct torture_context *tctx,
4613 struct dcerpc_binding_handle *b,
4614 struct policy_handle *handle)
4616 struct spoolss_DeletePrinter r;
4618 torture_comment(tctx, "Testing DeletePrinter\n");
4620 r.in.handle = handle;
4622 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_DeletePrinter_r(b, tctx, &r),
4623 "failed to delete printer");
4624 torture_assert_werr_ok(tctx, r.out.result,
4625 "failed to delete printer");
4627 return true;
4630 static bool test_EnumPrinters_findname(struct torture_context *tctx,
4631 struct dcerpc_binding_handle *b,
4632 uint32_t flags,
4633 uint32_t level,
4634 const char *name,
4635 bool *found)
4637 struct spoolss_EnumPrinters e;
4638 uint32_t count;
4639 union spoolss_PrinterInfo *info;
4640 uint32_t needed;
4641 int i;
4643 *found = false;
4645 e.in.flags = flags;
4646 e.in.server = NULL;
4647 e.in.level = level;
4648 e.in.buffer = NULL;
4649 e.in.offered = 0;
4650 e.out.count = &count;
4651 e.out.info = &info;
4652 e.out.needed = &needed;
4654 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_EnumPrinters_r(b, tctx, &e),
4655 "failed to enum printers");
4657 if (W_ERROR_EQUAL(e.out.result, WERR_INSUFFICIENT_BUFFER)) {
4658 DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed);
4659 data_blob_clear(&blob);
4660 e.in.buffer = &blob;
4661 e.in.offered = needed;
4663 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_EnumPrinters_r(b, tctx, &e),
4664 "failed to enum printers");
4667 torture_assert_werr_ok(tctx, e.out.result,
4668 "failed to enum printers");
4670 for (i=0; i < count; i++) {
4672 const char *current = NULL;
4673 const char *q;
4675 switch (level) {
4676 case 1:
4677 current = info[i].info1.name;
4678 break;
4681 if (strequal(current, name)) {
4682 *found = true;
4683 break;
4686 q = strrchr(current, '\\');
4687 if (q) {
4688 if (!e.in.server) {
4689 torture_warning(tctx,
4690 "server returns printername %s incl. servername although we did not set servername", current);
4692 q++;
4693 if (strequal(q, name)) {
4694 *found = true;
4695 break;
4700 return true;
4703 static bool test_AddPrinter_wellknown(struct torture_context *tctx,
4704 struct dcerpc_pipe *p,
4705 const char *printername,
4706 bool ex)
4708 WERROR result;
4709 struct spoolss_AddPrinter r;
4710 struct spoolss_AddPrinterEx rex;
4711 struct spoolss_SetPrinterInfoCtr info_ctr;
4712 struct spoolss_SetPrinterInfo1 info1;
4713 struct spoolss_DevmodeContainer devmode_ctr;
4714 struct sec_desc_buf secdesc_ctr;
4715 struct spoolss_UserLevelCtr userlevel_ctr;
4716 struct policy_handle handle;
4717 bool found = false;
4718 struct dcerpc_binding_handle *b = p->binding_handle;
4720 ZERO_STRUCT(devmode_ctr);
4721 ZERO_STRUCT(secdesc_ctr);
4722 ZERO_STRUCT(userlevel_ctr);
4723 ZERO_STRUCT(info1);
4725 torture_comment(tctx, "Testing AddPrinter%s level 1\n", ex ? "Ex":"");
4727 /* try to add printer to wellknown printer list (level 1) */
4729 userlevel_ctr.level = 1;
4731 info_ctr.info.info1 = &info1;
4732 info_ctr.level = 1;
4734 rex.in.server = NULL;
4735 rex.in.info_ctr = &info_ctr;
4736 rex.in.devmode_ctr = &devmode_ctr;
4737 rex.in.secdesc_ctr = &secdesc_ctr;
4738 rex.in.userlevel_ctr = &userlevel_ctr;
4739 rex.out.handle = &handle;
4741 r.in.server = NULL;
4742 r.in.info_ctr = &info_ctr;
4743 r.in.devmode_ctr = &devmode_ctr;
4744 r.in.secdesc_ctr = &secdesc_ctr;
4745 r.out.handle = &handle;
4747 torture_assert_ntstatus_ok(tctx, ex ? dcerpc_spoolss_AddPrinterEx_r(b, tctx, &rex) :
4748 dcerpc_spoolss_AddPrinter_r(b, tctx, &r),
4749 "failed to add printer");
4750 result = ex ? rex.out.result : r.out.result;
4751 torture_assert_werr_equal(tctx, result, WERR_INVALID_PRINTER_NAME,
4752 "unexpected result code");
4754 info1.name = printername;
4755 info1.flags = PRINTER_ATTRIBUTE_SHARED;
4757 torture_assert_ntstatus_ok(tctx, ex ? dcerpc_spoolss_AddPrinterEx_r(b, tctx, &rex) :
4758 dcerpc_spoolss_AddPrinter_r(b, tctx, &r),
4759 "failed to add printer");
4760 result = ex ? rex.out.result : r.out.result;
4761 torture_assert_werr_equal(tctx, result, WERR_PRINTER_ALREADY_EXISTS,
4762 "unexpected result code");
4764 /* bizarre protocol, WERR_PRINTER_ALREADY_EXISTS means success here,
4765 better do a real check to see the printer is really there */
4767 torture_assert(tctx, test_EnumPrinters_findname(tctx, b,
4768 PRINTER_ENUM_NETWORK, 1,
4769 printername,
4770 &found),
4771 "failed to enum printers");
4773 torture_assert(tctx, found, "failed to find newly added printer");
4775 info1.flags = 0;
4777 torture_assert_ntstatus_ok(tctx, ex ? dcerpc_spoolss_AddPrinterEx_r(b, tctx, &rex) :
4778 dcerpc_spoolss_AddPrinter_r(b, tctx, &r),
4779 "failed to add printer");
4780 result = ex ? rex.out.result : r.out.result;
4781 torture_assert_werr_equal(tctx, result, WERR_PRINTER_ALREADY_EXISTS,
4782 "unexpected result code");
4784 /* bizarre protocol, WERR_PRINTER_ALREADY_EXISTS means success here,
4785 better do a real check to see the printer has really been removed
4786 from the well known printer list */
4788 found = false;
4790 torture_assert(tctx, test_EnumPrinters_findname(tctx, b,
4791 PRINTER_ENUM_NETWORK, 1,
4792 printername,
4793 &found),
4794 "failed to enum printers");
4795 #if 0
4796 torture_assert(tctx, !found, "printer still in well known printer list");
4797 #endif
4798 return true;
4801 static bool test_AddPrinter_normal(struct torture_context *tctx,
4802 struct dcerpc_pipe *p,
4803 struct policy_handle *handle_p,
4804 const char *printername,
4805 const char *drivername,
4806 const char *portname,
4807 bool ex)
4809 WERROR result;
4810 struct spoolss_AddPrinter r;
4811 struct spoolss_AddPrinterEx rex;
4812 struct spoolss_SetPrinterInfoCtr info_ctr;
4813 struct spoolss_SetPrinterInfo2 info2;
4814 struct spoolss_DevmodeContainer devmode_ctr;
4815 struct sec_desc_buf secdesc_ctr;
4816 struct spoolss_UserLevelCtr userlevel_ctr;
4817 struct policy_handle handle;
4818 bool found = false;
4819 bool existing_printer_deleted = false;
4820 struct dcerpc_binding_handle *b = p->binding_handle;
4822 ZERO_STRUCT(devmode_ctr);
4823 ZERO_STRUCT(secdesc_ctr);
4824 ZERO_STRUCT(userlevel_ctr);
4826 torture_comment(tctx, "Testing AddPrinter%s level 2\n", ex ? "Ex":"");
4828 userlevel_ctr.level = 1;
4830 rex.in.server = NULL;
4831 rex.in.info_ctr = &info_ctr;
4832 rex.in.devmode_ctr = &devmode_ctr;
4833 rex.in.secdesc_ctr = &secdesc_ctr;
4834 rex.in.userlevel_ctr = &userlevel_ctr;
4835 rex.out.handle = &handle;
4837 r.in.server = NULL;
4838 r.in.info_ctr = &info_ctr;
4839 r.in.devmode_ctr = &devmode_ctr;
4840 r.in.secdesc_ctr = &secdesc_ctr;
4841 r.out.handle = &handle;
4843 again:
4845 /* try to add printer to printer list (level 2) */
4847 ZERO_STRUCT(info2);
4849 info_ctr.info.info2 = &info2;
4850 info_ctr.level = 2;
4852 torture_assert_ntstatus_ok(tctx, ex ? dcerpc_spoolss_AddPrinterEx_r(b, tctx, &rex) :
4853 dcerpc_spoolss_AddPrinter_r(b, tctx, &r),
4854 "failed to add printer");
4855 result = ex ? rex.out.result : r.out.result;
4856 torture_assert_werr_equal(tctx, result, WERR_INVALID_PRINTER_NAME,
4857 "unexpected result code");
4859 info2.printername = printername;
4861 torture_assert_ntstatus_ok(tctx, ex ? dcerpc_spoolss_AddPrinterEx_r(b, tctx, &rex) :
4862 dcerpc_spoolss_AddPrinter_r(b, tctx, &r),
4863 "failed to add printer");
4864 result = ex ? rex.out.result : r.out.result;
4866 if (W_ERROR_EQUAL(result, WERR_PRINTER_ALREADY_EXISTS)) {
4867 struct policy_handle printer_handle;
4869 if (existing_printer_deleted) {
4870 torture_fail(tctx, "already deleted printer still existing?");
4873 torture_assert(tctx, call_OpenPrinterEx(tctx, p, printername, NULL, &printer_handle),
4874 "failed to open printer handle");
4876 torture_assert(tctx, test_DeletePrinter(tctx, b, &printer_handle),
4877 "failed to delete printer");
4879 torture_assert(tctx, test_ClosePrinter(tctx, b, &printer_handle),
4880 "failed to close server handle");
4882 existing_printer_deleted = true;
4884 goto again;
4887 torture_assert_werr_equal(tctx, result, WERR_UNKNOWN_PORT,
4888 "unexpected result code");
4890 info2.portname = portname;
4892 torture_assert_ntstatus_ok(tctx, ex ? dcerpc_spoolss_AddPrinterEx_r(b, tctx, &rex) :
4893 dcerpc_spoolss_AddPrinter_r(b, tctx, &r),
4894 "failed to add printer");
4895 result = ex ? rex.out.result : r.out.result;
4896 torture_assert_werr_equal(tctx, result, WERR_UNKNOWN_PRINTER_DRIVER,
4897 "unexpected result code");
4899 info2.drivername = drivername;
4901 torture_assert_ntstatus_ok(tctx, ex ? dcerpc_spoolss_AddPrinterEx_r(b, tctx, &rex) :
4902 dcerpc_spoolss_AddPrinter_r(b, tctx, &r),
4903 "failed to add printer");
4904 result = ex ? rex.out.result : r.out.result;
4906 /* w2k8r2 allows to add printer w/o defining printprocessor */
4908 if (!W_ERROR_IS_OK(result)) {
4909 torture_assert_werr_equal(tctx, result, WERR_UNKNOWN_PRINTPROCESSOR,
4910 "unexpected result code");
4912 info2.printprocessor = "winprint";
4914 torture_assert_ntstatus_ok(tctx, ex ? dcerpc_spoolss_AddPrinterEx_r(b, tctx, &rex) :
4915 dcerpc_spoolss_AddPrinter_r(b, tctx, &r),
4916 "failed to add printer");
4917 result = ex ? rex.out.result : r.out.result;
4918 torture_assert_werr_ok(tctx, result,
4919 "failed to add printer");
4922 *handle_p = handle;
4924 /* we are paranoid, really check if the printer is there now */
4926 torture_assert(tctx, test_EnumPrinters_findname(tctx, b,
4927 PRINTER_ENUM_LOCAL, 1,
4928 printername,
4929 &found),
4930 "failed to enum printers");
4931 torture_assert(tctx, found, "failed to find newly added printer");
4933 torture_assert_ntstatus_ok(tctx, ex ? dcerpc_spoolss_AddPrinterEx_r(b, tctx, &rex) :
4934 dcerpc_spoolss_AddPrinter_r(b, tctx, &r),
4935 "failed to add printer");
4936 result = ex ? rex.out.result : r.out.result;
4937 torture_assert_werr_equal(tctx, result, WERR_PRINTER_ALREADY_EXISTS,
4938 "unexpected result code");
4940 return true;
4943 static bool test_AddPrinterEx(struct torture_context *tctx,
4944 struct dcerpc_pipe *p,
4945 struct policy_handle *handle_p,
4946 const char *printername,
4947 const char *drivername,
4948 const char *portname)
4950 bool ret = true;
4952 if (!torture_setting_bool(tctx, "samba3", false)) {
4953 if (!test_AddPrinter_wellknown(tctx, p, TORTURE_WELLKNOWN_PRINTER_EX, true)) {
4954 torture_comment(tctx, "failed to add printer to well known list\n");
4955 ret = false;
4959 if (!test_AddPrinter_normal(tctx, p, handle_p,
4960 printername, drivername, portname,
4961 true)) {
4962 torture_comment(tctx, "failed to add printer to printer list\n");
4963 ret = false;
4966 return ret;
4969 static bool test_AddPrinter(struct torture_context *tctx,
4970 struct dcerpc_pipe *p,
4971 struct policy_handle *handle_p,
4972 const char *printername,
4973 const char *drivername,
4974 const char *portname)
4976 bool ret = true;
4978 if (!torture_setting_bool(tctx, "samba3", false)) {
4979 if (!test_AddPrinter_wellknown(tctx, p, TORTURE_WELLKNOWN_PRINTER, false)) {
4980 torture_comment(tctx, "failed to add printer to well known list\n");
4981 ret = false;
4985 if (!test_AddPrinter_normal(tctx, p, handle_p,
4986 printername, drivername, portname,
4987 false)) {
4988 torture_comment(tctx, "failed to add printer to printer list\n");
4989 ret = false;
4992 return ret;
4995 static bool test_printer_info(struct torture_context *tctx,
4996 struct dcerpc_binding_handle *b,
4997 struct policy_handle *handle)
4999 bool ret = true;
5001 if (torture_setting_bool(tctx, "samba3", false)) {
5002 torture_skip(tctx, "skipping printer info cross tests against samba 3");
5005 if (!test_PrinterInfo(tctx, b, handle)) {
5006 ret = false;
5009 if (!test_SetPrinter_errors(tctx, b, handle)) {
5010 ret = false;
5013 return ret;
5016 static bool test_EnumPrinterKey(struct torture_context *tctx,
5017 struct dcerpc_binding_handle *b,
5018 struct policy_handle *handle,
5019 const char *key_name,
5020 const char ***array)
5022 struct spoolss_EnumPrinterKey r;
5023 uint32_t needed = 0;
5024 union spoolss_KeyNames key_buffer;
5025 int32_t offered[] = { 0, 1, 2, 3, 4, 5, -1, -2, -3, -4, -5, 256, 512, 1024, 2048 };
5026 uint32_t _ndr_size;
5027 int i;
5029 r.in.handle = handle;
5030 r.in.key_name = key_name;
5031 r.out.key_buffer = &key_buffer;
5032 r.out.needed = &needed;
5033 r.out._ndr_size = &_ndr_size;
5035 for (i=0; i < ARRAY_SIZE(offered); i++) {
5037 if (offered[i] < 0 && needed) {
5038 if (needed <= 4) {
5039 continue;
5041 r.in.offered = needed + offered[i];
5042 } else {
5043 r.in.offered = offered[i];
5046 ZERO_STRUCT(key_buffer);
5048 torture_comment(tctx, "Testing EnumPrinterKey(%s) with %d offered\n", r.in.key_name, r.in.offered);
5050 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_EnumPrinterKey_r(b, tctx, &r),
5051 "failed to call EnumPrinterKey");
5052 if (W_ERROR_EQUAL(r.out.result, WERR_MORE_DATA)) {
5054 torture_assert(tctx, (_ndr_size == r.in.offered/2),
5055 talloc_asprintf(tctx, "EnumPrinterKey size mismatch, _ndr_size %d (expected %d)",
5056 _ndr_size, r.in.offered/2));
5058 r.in.offered = needed;
5059 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_EnumPrinterKey_r(b, tctx, &r),
5060 "failed to call EnumPrinterKey");
5063 if (offered[i] > 0) {
5064 torture_assert_werr_ok(tctx, r.out.result,
5065 "failed to call EnumPrinterKey");
5068 torture_assert(tctx, (_ndr_size == r.in.offered/2),
5069 talloc_asprintf(tctx, "EnumPrinterKey size mismatch, _ndr_size %d (expected %d)",
5070 _ndr_size, r.in.offered/2));
5072 torture_assert(tctx, (*r.out.needed <= r.in.offered),
5073 talloc_asprintf(tctx, "EnumPrinterKey size mismatch: needed %d is not <= offered %d", *r.out.needed, r.in.offered));
5075 torture_assert(tctx, (*r.out.needed <= _ndr_size * 2),
5076 talloc_asprintf(tctx, "EnumPrinterKey size mismatch: needed %d is not <= _ndr_size %d * 2", *r.out.needed, _ndr_size));
5078 if (key_buffer.string_array) {
5079 uint32_t calc_needed = 0;
5080 int s;
5081 for (s=0; key_buffer.string_array[s]; s++) {
5082 calc_needed += strlen_m_term(key_buffer.string_array[s])*2;
5084 if (!key_buffer.string_array[0]) {
5085 calc_needed += 2;
5087 calc_needed += 2;
5089 torture_assert_int_equal(tctx, *r.out.needed, calc_needed,
5090 "EnumPrinterKey unexpected size");
5094 if (array) {
5095 *array = key_buffer.string_array;
5098 return true;
5101 bool test_printer_keys(struct torture_context *tctx,
5102 struct dcerpc_binding_handle *b,
5103 struct policy_handle *handle)
5105 const char **key_array = NULL;
5106 int i;
5108 torture_comment(tctx, "Testing Printer Keys\n");
5110 torture_assert(tctx, test_EnumPrinterKey(tctx, b, handle, "", &key_array),
5111 "failed to call test_EnumPrinterKey");
5113 for (i=0; key_array && key_array[i]; i++) {
5114 torture_assert(tctx, test_EnumPrinterKey(tctx, b, handle, key_array[i], NULL),
5115 "failed to call test_EnumPrinterKey");
5117 for (i=0; key_array && key_array[i]; i++) {
5118 torture_assert(tctx, test_EnumPrinterDataEx(tctx, b, handle, key_array[i], NULL, NULL),
5119 "failed to call test_EnumPrinterDataEx");
5122 torture_comment(tctx, "Printer Keys test succeeded\n\n");
5124 return true;
5127 static bool test_one_printer(struct torture_context *tctx,
5128 struct dcerpc_pipe *p,
5129 struct policy_handle *handle,
5130 const char *name)
5132 bool ret = true;
5133 struct dcerpc_binding_handle *b = p->binding_handle;
5135 if (!test_printer_info(tctx, b, handle)) {
5136 ret = false;
5139 if (!test_PrinterInfo_SD(tctx, b, handle)) {
5140 ret = false;
5143 if (!test_PrinterInfo_DevMode(tctx, p, handle, name)) {
5144 ret = false;
5147 if (!test_ChangeID(tctx, p, handle)) {
5148 ret = false;
5151 if (!test_printer_keys(tctx, b, handle)) {
5152 ret = false;
5155 if (!test_EnumPrinterData_consistency(tctx, p, handle)) {
5156 ret = false;
5159 if (!test_SetPrinterDataEx_matrix(tctx, p, handle, name, NULL, NULL)) {
5160 ret = false;
5163 if (!test_PrinterData_winreg(tctx, p, handle, name)) {
5164 ret = false;
5167 if (!test_printer_rename(tctx, p, handle, name)) {
5168 ret = false;
5171 return ret;
5174 static bool test_printer(struct torture_context *tctx,
5175 struct dcerpc_pipe *p)
5177 bool ret = true;
5178 struct policy_handle handle[2];
5179 bool found = false;
5180 const char *drivername = "Microsoft XPS Document Writer";
5181 const char *portname = "LPT1:";
5182 struct dcerpc_binding_handle *b = p->binding_handle;
5184 /* test printer created via AddPrinter */
5186 if (!test_AddPrinter(tctx, p, &handle[0], TORTURE_PRINTER, drivername, portname)) {
5187 return false;
5190 if (!test_one_printer(tctx, p, &handle[0], TORTURE_PRINTER)) {
5191 ret = false;
5194 if (!test_DeletePrinter(tctx, b, &handle[0])) {
5195 ret = false;
5198 if (!test_EnumPrinters_findname(tctx, b, PRINTER_ENUM_LOCAL, 1,
5199 TORTURE_PRINTER, &found)) {
5200 ret = false;
5203 torture_assert(tctx, !found, "deleted printer still there");
5205 /* test printer created via AddPrinterEx */
5207 if (!test_AddPrinterEx(tctx, p, &handle[1], TORTURE_PRINTER_EX, drivername, portname)) {
5208 return false;
5211 if (!test_one_printer(tctx, p, &handle[1], TORTURE_PRINTER_EX)) {
5212 ret = false;
5215 if (!test_DeletePrinter(tctx, b, &handle[1])) {
5216 ret = false;
5219 if (!test_EnumPrinters_findname(tctx, b, PRINTER_ENUM_LOCAL, 1,
5220 TORTURE_PRINTER_EX, &found)) {
5221 ret = false;
5224 torture_assert(tctx, !found, "deleted printer still there");
5226 return ret;
5229 static bool test_architecture_buffer(struct torture_context *tctx,
5230 struct dcerpc_pipe *p)
5232 struct spoolss_OpenPrinterEx r;
5233 struct spoolss_UserLevel1 u1;
5234 struct policy_handle handle;
5235 uint32_t architectures[] = {
5236 PROCESSOR_ARCHITECTURE_INTEL,
5237 PROCESSOR_ARCHITECTURE_IA64,
5238 PROCESSOR_ARCHITECTURE_AMD64
5240 uint32_t needed[3];
5241 int i;
5242 struct dcerpc_binding_handle *b = p->binding_handle;
5244 for (i=0; i < ARRAY_SIZE(architectures); i++) {
5246 torture_comment(tctx, "Testing OpenPrinterEx with architecture %d\n", architectures[i]);
5248 u1.size = 0;
5249 u1.client = NULL;
5250 u1.user = NULL;
5251 u1.build = 0;
5252 u1.major = 3;
5253 u1.minor = 0;
5254 u1.processor = architectures[i];
5256 r.in.printername = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
5257 r.in.datatype = NULL;
5258 r.in.devmode_ctr.devmode= NULL;
5259 r.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
5260 r.in.level = 1;
5261 r.in.userlevel.level1 = &u1;
5262 r.out.handle = &handle;
5264 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_OpenPrinterEx_r(b, tctx, &r), "");
5265 torture_assert_werr_ok(tctx, r.out.result, "");
5268 struct spoolss_EnumPrinters e;
5269 uint32_t count;
5270 union spoolss_PrinterInfo *info;
5272 e.in.flags = PRINTER_ENUM_LOCAL;
5273 e.in.server = NULL;
5274 e.in.level = 2;
5275 e.in.buffer = NULL;
5276 e.in.offered = 0;
5277 e.out.count = &count;
5278 e.out.info = &info;
5279 e.out.needed = &needed[i];
5281 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_EnumPrinters_r(b, tctx, &e), "");
5282 #if 0
5283 torture_comment(tctx, "needed was %d\n", needed[i]);
5284 #endif
5287 torture_assert(tctx, test_ClosePrinter(tctx, b, &handle), "");
5290 for (i=1; i < ARRAY_SIZE(architectures); i++) {
5291 if (needed[i-1] != needed[i]) {
5292 torture_fail(tctx,
5293 talloc_asprintf(tctx, "needed size %d for architecture %d != needed size %d for architecture %d\n",
5294 needed[i-1], architectures[i-1], needed[i], architectures[i]));
5298 return true;
5301 bool torture_rpc_spoolss(struct torture_context *torture)
5303 NTSTATUS status;
5304 struct dcerpc_pipe *p;
5305 struct dcerpc_binding_handle *b;
5306 bool ret = true;
5307 struct test_spoolss_context *ctx;
5308 const char *environment = SPOOLSS_ARCHITECTURE_NT_X86;
5310 status = torture_rpc_connection(torture, &p, &ndr_table_spoolss);
5311 if (!NT_STATUS_IS_OK(status)) {
5312 return false;
5314 b = p->binding_handle;
5316 ctx = talloc_zero(torture, struct test_spoolss_context);
5318 ret &= test_OpenPrinter_server(torture, p, &ctx->server_handle);
5319 ret &= test_GetPrinterData_list(torture, p, &ctx->server_handle, &environment);
5320 ret &= test_EnumForms(torture, b, &ctx->server_handle, true);
5321 ret &= test_AddForm(torture, b, &ctx->server_handle, true);
5322 ret &= test_EnumPorts(torture, b, ctx);
5323 ret &= test_GetPrinterDriverDirectory(torture, p, ctx, environment);
5324 ret &= test_GetPrintProcessorDirectory(torture, p, ctx, environment);
5325 ret &= test_EnumPrinterDrivers(torture, p, ctx, environment);
5326 ret &= test_EnumPrinterDrivers(torture, p, ctx, SPOOLSS_ARCHITECTURE_ALL);
5327 ret &= test_EnumMonitors(torture, b, ctx);
5328 ret &= test_EnumPrintProcessors(torture, b, ctx, environment);
5329 ret &= test_EnumPrintProcDataTypes(torture, b, ctx);
5330 ret &= test_EnumPrinters(torture, b, ctx);
5331 ret &= test_OpenPrinter_badname(torture, b, "__INVALID_PRINTER__");
5332 ret &= test_OpenPrinter_badname(torture, b, "\\\\__INVALID_HOST__");
5333 ret &= test_OpenPrinter_badname(torture, b, "");
5334 ret &= test_OpenPrinter_badname(torture, b, "\\\\\\");
5335 ret &= test_OpenPrinter_badname(torture, b, "\\\\\\__INVALID_PRINTER__");
5336 ret &= test_OpenPrinter_badname(torture, b, talloc_asprintf(torture, "\\\\%s\\", dcerpc_server_name(p)));
5337 ret &= test_OpenPrinter_badname(torture, b,
5338 talloc_asprintf(torture, "\\\\%s\\__INVALID_PRINTER__", dcerpc_server_name(p)));
5341 ret &= test_AddPort(torture, p);
5342 ret &= test_EnumPorts_old(torture, p);
5343 ret &= test_EnumPrinters_old(torture, p, environment);
5344 ret &= test_EnumPrinterDrivers_old(torture, p, environment);
5345 ret &= test_architecture_buffer(torture, p);
5347 return ret;
5350 struct torture_suite *torture_rpc_spoolss_printer(TALLOC_CTX *mem_ctx)
5352 struct torture_suite *suite = torture_suite_create(mem_ctx, "SPOOLSS-PRINTER");
5354 struct torture_rpc_tcase *tcase = torture_suite_add_rpc_iface_tcase(suite,
5355 "printer", &ndr_table_spoolss);
5357 torture_rpc_tcase_add_test(tcase, "printer", test_printer);
5359 return suite;