82469e9ef39cd513d2799a6e08464fbbe922976d
[ira/wip.git] / source4 / torture / rpc / spoolss.c
1 /*
2    Unix SMB/CIFS implementation.
3    test suite for spoolss rpc operations
4
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
9
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.
14
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.
19
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/>.
22 */
23
24 #include "includes.h"
25 #include "torture/torture.h"
26 #include "librpc/gen_ndr/ndr_misc.h"
27 #include "librpc/gen_ndr/ndr_spoolss.h"
28 #include "librpc/gen_ndr/ndr_spoolss_c.h"
29 #include "librpc/gen_ndr/ndr_security.h"
30 #include "libcli/security/security.h"
31 #include "torture/rpc/rpc.h"
32 #include "param/param.h"
33
34 #define TORTURE_WELLKNOWN_PRINTER       "torture_wkn_printer"
35 #define TORTURE_PRINTER                 "torture_printer"
36 #define TORTURE_WELLKNOWN_PRINTER_EX    "torture_wkn_printer_ex"
37 #define TORTURE_PRINTER_EX              "torture_printer_ex"
38
39 struct test_spoolss_context {
40         /* print server handle */
41         struct policy_handle server_handle;
42
43         /* for EnumPorts */
44         uint32_t port_count[3];
45         union spoolss_PortInfo *ports[3];
46
47         /* for EnumPrinterDrivers */
48         uint32_t driver_count[8];
49         union spoolss_DriverInfo *drivers[8];
50
51         /* for EnumMonitors */
52         uint32_t monitor_count[3];
53         union spoolss_MonitorInfo *monitors[3];
54
55         /* for EnumPrintProcessors */
56         uint32_t print_processor_count[2];
57         union spoolss_PrintProcessorInfo *print_processors[2];
58
59         /* for EnumPrinters */
60         uint32_t printer_count[6];
61         union spoolss_PrinterInfo *printers[6];
62 };
63
64 #define COMPARE_STRING(tctx, c,r,e) \
65         torture_assert_str_equal(tctx, c.e, r.e, "invalid value")
66
67 /* not every compiler supports __typeof__() */
68 #if (__GNUC__ >= 3)
69 #define _CHECK_FIELD_SIZE(c,r,e,type) do {\
70         if (sizeof(__typeof__(c.e)) != sizeof(type)) { \
71                 torture_fail(tctx, #c "." #e "field is not " #type "\n"); \
72         }\
73         if (sizeof(__typeof__(r.e)) != sizeof(type)) { \
74                 torture_fail(tctx, #r "." #e "field is not " #type "\n"); \
75         }\
76 } while(0)
77 #else
78 #define _CHECK_FIELD_SIZE(c,r,e,type) do {} while(0)
79 #endif
80
81 #define COMPARE_UINT32(tctx, c, r, e) do {\
82         _CHECK_FIELD_SIZE(c, r, e, uint32_t); \
83         torture_assert_int_equal(tctx, c.e, r.e, "invalid value"); \
84 } while(0)
85
86 #define COMPARE_UINT64(tctx, c, r, e) do {\
87         _CHECK_FIELD_SIZE(c, r, e, uint64_t); \
88         torture_assert_int_equal(tctx, c.e, r.e, "invalid value"); \
89 } while(0)
90
91
92 #define COMPARE_NTTIME(tctx, c, r, e) do {\
93         _CHECK_FIELD_SIZE(c, r, e, NTTIME); \
94         torture_assert_int_equal(tctx, c.e, r.e, "invalid value"); \
95 } while(0)
96
97 #define COMPARE_STRING_ARRAY(tctx, c,r,e) do {\
98         int __i; \
99         if (!c.e && !r.e) { \
100                 break; \
101         } \
102         if (c.e && !r.e) { \
103                 torture_fail(tctx, #r "." #e " field is NULL and " #c "." #e " is not\n"); \
104         } \
105         if (!c.e && r.e) { \
106                 torture_fail(tctx, #c "." #e " field is NULL and " #r "." #e " is not\n"); \
107         } \
108         for (__i=0;c.e[__i] != NULL; __i++) { \
109                 torture_assert_str_equal(tctx, c.e[__i], r.e[__i], "invalid value"); \
110         } \
111 } while(0)
112
113 #define CHECK_ALIGN(size, n) do {\
114         if (size % n) {\
115                 torture_warning(tctx, "%d is *NOT* %d byte aligned, should be %d",\
116                         size, n, size + n - (size % n));\
117         }\
118 } while(0)
119
120 #define DO_ROUND(size, n) (((size)+((n)-1)) & ~((n)-1))
121
122 #define CHECK_NEEDED_SIZE_ENUM_LEVEL(fn, info, level, count, ic, needed, align) do { \
123         uint32_t size = ndr_size_##fn##_info(tctx, ic, level, count, info);\
124         uint32_t round_size = DO_ROUND(size, align);\
125         if (round_size != needed) {\
126                 torture_warning(tctx, __location__": "#fn" level %d (count: %d) got unexpected needed size: %d, we calculated: %d", level, count, needed, round_size);\
127                 CHECK_ALIGN(size, align);\
128         }\
129 } while(0)
130
131 #define CHECK_NEEDED_SIZE_ENUM(fn, info, count, ic, needed, align) do { \
132         uint32_t size = ndr_size_##fn##_info(tctx, ic, count, info);\
133         uint32_t round_size = DO_ROUND(size, align);\
134         if (round_size != needed) {\
135                 torture_warning(tctx, __location__": "#fn" (count: %d) got unexpected needed size: %d, we calculated: %d", count, needed, round_size);\
136                 CHECK_ALIGN(size, align);\
137         }\
138 } while(0)
139
140 #define CHECK_NEEDED_SIZE_LEVEL(fn, info, level, ic, needed, align) do { \
141         uint32_t size = ndr_size_##fn(info, level, ic, 0);\
142         uint32_t round_size = DO_ROUND(size, align);\
143         if (round_size != needed) {\
144                 torture_warning(tctx, __location__": "#fn" level %d got unexpected needed size: %d, we calculated: %d", level, needed, round_size);\
145                 CHECK_ALIGN(size, align);\
146         }\
147 } while(0)
148
149 static bool test_OpenPrinter_server(struct torture_context *tctx,
150                                     struct dcerpc_pipe *p,
151                                     struct policy_handle *server_handle)
152 {
153         NTSTATUS status;
154         struct spoolss_OpenPrinter op;
155
156         op.in.printername       = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
157         op.in.datatype          = NULL;
158         op.in.devmode_ctr.devmode= NULL;
159         op.in.access_mask       = 0;
160         op.out.handle           = server_handle;
161
162         torture_comment(tctx, "Testing OpenPrinter(%s)\n", op.in.printername);
163
164         status = dcerpc_spoolss_OpenPrinter(p, tctx, &op);
165         torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_OpenPrinter failed");
166         torture_assert_werr_ok(tctx, op.out.result, "dcerpc_spoolss_OpenPrinter failed");
167
168         return true;
169 }
170
171 static bool test_EnumPorts(struct torture_context *tctx,
172                            struct dcerpc_pipe *p,
173                            struct test_spoolss_context *ctx)
174 {
175         NTSTATUS status;
176         struct spoolss_EnumPorts r;
177         uint16_t levels[] = { 1, 2 };
178         int i, j;
179
180         for (i=0;i<ARRAY_SIZE(levels);i++) {
181                 int level = levels[i];
182                 DATA_BLOB blob;
183                 uint32_t needed;
184                 uint32_t count;
185                 union spoolss_PortInfo *info;
186
187                 r.in.servername = "";
188                 r.in.level = level;
189                 r.in.buffer = NULL;
190                 r.in.offered = 0;
191                 r.out.needed = &needed;
192                 r.out.count = &count;
193                 r.out.info = &info;
194
195                 torture_comment(tctx, "Testing EnumPorts level %u\n", r.in.level);
196
197                 status = dcerpc_spoolss_EnumPorts(p, ctx, &r);
198                 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EnumPorts failed");
199                 if (W_ERROR_IS_OK(r.out.result)) {
200                         /* TODO: do some more checks here */
201                         continue;
202                 }
203                 torture_assert_werr_equal(tctx, r.out.result, WERR_INSUFFICIENT_BUFFER,
204                         "EnumPorts unexpected return code");
205
206                 blob = data_blob_talloc(ctx, NULL, needed);
207                 data_blob_clear(&blob);
208                 r.in.buffer = &blob;
209                 r.in.offered = needed;
210
211                 status = dcerpc_spoolss_EnumPorts(p, ctx, &r);
212                 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EnumPorts failed");
213
214                 torture_assert_werr_ok(tctx, r.out.result, "EnumPorts failed");
215
216                 torture_assert(tctx, info, "EnumPorts returned no info");
217
218                 CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumPorts, info, r.in.level, count, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
219
220                 ctx->port_count[level]  = count;
221                 ctx->ports[level]       = info;
222         }
223
224         for (i=1;i<ARRAY_SIZE(levels);i++) {
225                 int level = levels[i];
226                 int old_level = levels[i-1];
227                 torture_assert_int_equal(tctx, ctx->port_count[level], ctx->port_count[old_level],
228                         "EnumPorts invalid value");
229         }
230         /* if the array sizes are not the same we would maybe segfault in the following code */
231
232         for (i=0;i<ARRAY_SIZE(levels);i++) {
233                 int level = levels[i];
234                 for (j=0;j<ctx->port_count[level];j++) {
235                         union spoolss_PortInfo *cur = &ctx->ports[level][j];
236                         union spoolss_PortInfo *ref = &ctx->ports[2][j];
237                         switch (level) {
238                         case 1:
239                                 COMPARE_STRING(tctx, cur->info1, ref->info2, port_name);
240                                 break;
241                         case 2:
242                                 /* level 2 is our reference, and it makes no sense to compare it to itself */
243                                 break;
244                         }
245                 }
246         }
247
248         return true;
249 }
250
251 static bool test_GetPrintProcessorDirectory(struct torture_context *tctx,
252                                             struct dcerpc_pipe *p,
253                                             struct test_spoolss_context *ctx)
254 {
255         NTSTATUS status;
256         struct spoolss_GetPrintProcessorDirectory r;
257         struct {
258                 uint16_t level;
259                 const char *server;
260         } levels[] = {{
261                         .level  = 1,
262                         .server = NULL
263                 },{
264                         .level  = 1,
265                         .server = ""
266                 },{
267                         .level  = 78,
268                         .server = ""
269                 },{
270                         .level  = 1,
271                         .server = talloc_asprintf(ctx, "\\\\%s", dcerpc_server_name(p))
272                 },{
273                         .level  = 1024,
274                         .server = talloc_asprintf(ctx, "\\\\%s", dcerpc_server_name(p))
275                 }
276         };
277         int i;
278         uint32_t needed;
279
280         for (i=0;i<ARRAY_SIZE(levels);i++) {
281                 int level = levels[i].level;
282                 DATA_BLOB blob;
283
284                 r.in.server             = levels[i].server;
285                 r.in.environment        = SPOOLSS_ARCHITECTURE_NT_X86;
286                 r.in.level              = level;
287                 r.in.buffer             = NULL;
288                 r.in.offered            = 0;
289                 r.out.needed            = &needed;
290
291                 torture_comment(tctx, "Testing GetPrintProcessorDirectory level %u\n", r.in.level);
292
293                 status = dcerpc_spoolss_GetPrintProcessorDirectory(p, ctx, &r);
294                 torture_assert_ntstatus_ok(tctx, status,
295                         "dcerpc_spoolss_GetPrintProcessorDirectory failed");
296                 torture_assert_werr_equal(tctx, r.out.result, WERR_INSUFFICIENT_BUFFER,
297                         "GetPrintProcessorDirectory unexpected return code");
298
299                 blob = data_blob_talloc(ctx, NULL, needed);
300                 data_blob_clear(&blob);
301                 r.in.buffer = &blob;
302                 r.in.offered = needed;
303
304                 status = dcerpc_spoolss_GetPrintProcessorDirectory(p, ctx, &r);
305                 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_GetPrintProcessorDirectory failed");
306
307                 torture_assert_werr_ok(tctx, r.out.result, "GetPrintProcessorDirectory failed");
308
309                 CHECK_NEEDED_SIZE_LEVEL(spoolss_PrintProcessorDirectoryInfo, r.out.info, r.in.level, lp_iconv_convenience(tctx->lp_ctx), needed, 2);
310         }
311
312         return true;
313 }
314
315
316 static bool test_GetPrinterDriverDirectory(struct torture_context *tctx,
317                                            struct dcerpc_pipe *p,
318                                            struct test_spoolss_context *ctx)
319 {
320         NTSTATUS status;
321         struct spoolss_GetPrinterDriverDirectory r;
322         struct {
323                 uint16_t level;
324                 const char *server;
325         } levels[] = {{
326                         .level  = 1,
327                         .server = NULL
328                 },{
329                         .level  = 1,
330                         .server = ""
331                 },{
332                         .level  = 78,
333                         .server = ""
334                 },{
335                         .level  = 1,
336                         .server = talloc_asprintf(ctx, "\\\\%s", dcerpc_server_name(p))
337                 },{
338                         .level  = 1024,
339                         .server = talloc_asprintf(ctx, "\\\\%s", dcerpc_server_name(p))
340                 }
341         };
342         int i;
343         uint32_t needed;
344
345         for (i=0;i<ARRAY_SIZE(levels);i++) {
346                 int level = levels[i].level;
347                 DATA_BLOB blob;
348
349                 r.in.server             = levels[i].server;
350                 r.in.environment        = SPOOLSS_ARCHITECTURE_NT_X86;
351                 r.in.level              = level;
352                 r.in.buffer             = NULL;
353                 r.in.offered            = 0;
354                 r.out.needed            = &needed;
355
356                 torture_comment(tctx, "Testing GetPrinterDriverDirectory level %u\n", r.in.level);
357
358                 status = dcerpc_spoolss_GetPrinterDriverDirectory(p, ctx, &r);
359                 torture_assert_ntstatus_ok(tctx, status,
360                         "dcerpc_spoolss_GetPrinterDriverDirectory failed");
361                 torture_assert_werr_equal(tctx, r.out.result, WERR_INSUFFICIENT_BUFFER,
362                         "GetPrinterDriverDirectory unexpected return code");
363
364                 blob = data_blob_talloc(ctx, NULL, needed);
365                 data_blob_clear(&blob);
366                 r.in.buffer = &blob;
367                 r.in.offered = needed;
368
369                 status = dcerpc_spoolss_GetPrinterDriverDirectory(p, ctx, &r);
370                 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_GetPrinterDriverDirectory failed");
371
372                 torture_assert_werr_ok(tctx, r.out.result, "GetPrinterDriverDirectory failed");
373
374                 CHECK_NEEDED_SIZE_LEVEL(spoolss_DriverDirectoryInfo, r.out.info, r.in.level, lp_iconv_convenience(tctx->lp_ctx), needed, 2);
375         }
376
377         return true;
378 }
379
380 static bool test_EnumPrinterDrivers(struct torture_context *tctx,
381                                     struct dcerpc_pipe *p,
382                                     struct test_spoolss_context *ctx,
383                                     const char *architecture)
384 {
385         NTSTATUS status;
386         struct spoolss_EnumPrinterDrivers r;
387         uint16_t levels[] = { 1, 2, 3, 4, 5, 6, 8 };
388         int i, j;
389
390         for (i=0;i<ARRAY_SIZE(levels);i++) {
391                 int level = levels[i];
392                 DATA_BLOB blob;
393                 uint32_t needed;
394                 uint32_t count;
395                 union spoolss_DriverInfo *info;
396
397                 /* FIXME: gd, come back and fix "" as server, and handle
398                  * priority of returned error codes in torture test and samba 3
399                  * server */
400
401                 r.in.server             = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
402                 r.in.environment        = architecture;
403                 r.in.level              = level;
404                 r.in.buffer             = NULL;
405                 r.in.offered            = 0;
406                 r.out.needed            = &needed;
407                 r.out.count             = &count;
408                 r.out.info              = &info;
409
410                 torture_comment(tctx, "Testing EnumPrinterDrivers level %u (%s)\n", r.in.level, r.in.environment);
411
412                 status = dcerpc_spoolss_EnumPrinterDrivers(p, ctx, &r);
413                 torture_assert_ntstatus_ok(tctx, status,
414                                            "dcerpc_spoolss_EnumPrinterDrivers failed");
415                 if (W_ERROR_IS_OK(r.out.result)) {
416                         /* TODO: do some more checks here */
417                         continue;
418                 }
419                 if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
420                         blob = data_blob_talloc(ctx, NULL, needed);
421                         data_blob_clear(&blob);
422                         r.in.buffer = &blob;
423                         r.in.offered = needed;
424
425                         status = dcerpc_spoolss_EnumPrinterDrivers(p, ctx, &r);
426                         torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EnumPrinterDrivers failed");
427                 }
428
429                 torture_assert_werr_ok(tctx, r.out.result, "EnumPrinterDrivers failed");
430
431                 CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumPrinterDrivers, info, r.in.level, count, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
432
433                 ctx->driver_count[level]        = count;
434                 ctx->drivers[level]             = info;
435         }
436
437         for (i=1;i<ARRAY_SIZE(levels);i++) {
438                 int level = levels[i];
439                 int old_level = levels[i-1];
440
441                 torture_assert_int_equal(tctx, ctx->driver_count[level], ctx->driver_count[old_level],
442                         "EnumPrinterDrivers invalid value");
443         }
444
445         for (i=0;i<ARRAY_SIZE(levels);i++) {
446                 int level = levels[i];
447
448                 for (j=0;j<ctx->driver_count[level];j++) {
449                         union spoolss_DriverInfo *cur = &ctx->drivers[level][j];
450                         union spoolss_DriverInfo *ref = &ctx->drivers[8][j];
451
452                         switch (level) {
453                         case 1:
454                                 COMPARE_STRING(tctx, cur->info1, ref->info8, driver_name);
455                                 break;
456                         case 2:
457                                 COMPARE_UINT32(tctx, cur->info2, ref->info8, version);
458                                 COMPARE_STRING(tctx, cur->info2, ref->info8, driver_name);
459                                 COMPARE_STRING(tctx, cur->info2, ref->info8, architecture);
460                                 COMPARE_STRING(tctx, cur->info2, ref->info8, driver_path);
461                                 COMPARE_STRING(tctx, cur->info2, ref->info8, data_file);
462                                 COMPARE_STRING(tctx, cur->info2, ref->info8, config_file);
463                                 break;
464                         case 3:
465                                 COMPARE_UINT32(tctx, cur->info3, ref->info8, version);
466                                 COMPARE_STRING(tctx, cur->info3, ref->info8, driver_name);
467                                 COMPARE_STRING(tctx, cur->info3, ref->info8, architecture);
468                                 COMPARE_STRING(tctx, cur->info3, ref->info8, driver_path);
469                                 COMPARE_STRING(tctx, cur->info3, ref->info8, data_file);
470                                 COMPARE_STRING(tctx, cur->info3, ref->info8, config_file);
471                                 COMPARE_STRING(tctx, cur->info3, ref->info8, help_file);
472                                 COMPARE_STRING_ARRAY(tctx, cur->info3, ref->info8, dependent_files);
473                                 COMPARE_STRING(tctx, cur->info3, ref->info8, monitor_name);
474                                 COMPARE_STRING(tctx, cur->info3, ref->info8, default_datatype);
475                                 break;
476                         case 4:
477                                 COMPARE_UINT32(tctx, cur->info4, ref->info8, version);
478                                 COMPARE_STRING(tctx, cur->info4, ref->info8, driver_name);
479                                 COMPARE_STRING(tctx, cur->info4, ref->info8, architecture);
480                                 COMPARE_STRING(tctx, cur->info4, ref->info8, driver_path);
481                                 COMPARE_STRING(tctx, cur->info4, ref->info8, data_file);
482                                 COMPARE_STRING(tctx, cur->info4, ref->info8, config_file);
483                                 COMPARE_STRING(tctx, cur->info4, ref->info8, help_file);
484                                 COMPARE_STRING_ARRAY(tctx, cur->info4, ref->info8, dependent_files);
485                                 COMPARE_STRING(tctx, cur->info4, ref->info8, monitor_name);
486                                 COMPARE_STRING(tctx, cur->info4, ref->info8, default_datatype);
487                                 COMPARE_STRING_ARRAY(tctx, cur->info4, ref->info8, previous_names);
488                                 break;
489                         case 5:
490                                 COMPARE_UINT32(tctx, cur->info5, ref->info8, version);
491                                 COMPARE_STRING(tctx, cur->info5, ref->info8, driver_name);
492                                 COMPARE_STRING(tctx, cur->info5, ref->info8, architecture);
493                                 COMPARE_STRING(tctx, cur->info5, ref->info8, driver_path);
494                                 COMPARE_STRING(tctx, cur->info5, ref->info8, data_file);
495                                 COMPARE_STRING(tctx, cur->info5, ref->info8, config_file);
496                                 /*COMPARE_UINT32(tctx, cur->info5, ref->info8, driver_attributes);*/
497                                 /*COMPARE_UINT32(tctx, cur->info5, ref->info8, config_version);*/
498                                 /*TODO: ! COMPARE_UINT32(tctx, cur->info5, ref->info8, driver_version); */
499                                 break;
500                         case 6:
501                                 COMPARE_UINT32(tctx, cur->info6, ref->info8, version);
502                                 COMPARE_STRING(tctx, cur->info6, ref->info8, driver_name);
503                                 COMPARE_STRING(tctx, cur->info6, ref->info8, architecture);
504                                 COMPARE_STRING(tctx, cur->info6, ref->info8, driver_path);
505                                 COMPARE_STRING(tctx, cur->info6, ref->info8, data_file);
506                                 COMPARE_STRING(tctx, cur->info6, ref->info8, config_file);
507                                 COMPARE_STRING(tctx, cur->info6, ref->info8, help_file);
508                                 COMPARE_STRING_ARRAY(tctx, cur->info6, ref->info8, dependent_files);
509                                 COMPARE_STRING(tctx, cur->info6, ref->info8, monitor_name);
510                                 COMPARE_STRING(tctx, cur->info6, ref->info8, default_datatype);
511                                 COMPARE_STRING_ARRAY(tctx, cur->info6, ref->info8, previous_names);
512                                 COMPARE_NTTIME(tctx, cur->info6, ref->info8, driver_date);
513                                 COMPARE_UINT64(tctx, cur->info6, ref->info8, driver_version);
514                                 COMPARE_STRING(tctx, cur->info6, ref->info8, manufacturer_name);
515                                 COMPARE_STRING(tctx, cur->info6, ref->info8, manufacturer_url);
516                                 COMPARE_STRING(tctx, cur->info6, ref->info8, hardware_id);
517                                 COMPARE_STRING(tctx, cur->info6, ref->info8, provider);
518                                 break;
519                         case 8:
520                                 /* level 8 is our reference, and it makes no sense to compare it to itself */
521                                 break;
522                         }
523                 }
524         }
525
526         return true;
527 }
528
529 static bool test_EnumMonitors(struct torture_context *tctx,
530                               struct dcerpc_pipe *p,
531                               struct test_spoolss_context *ctx)
532 {
533         NTSTATUS status;
534         struct spoolss_EnumMonitors r;
535         uint16_t levels[] = { 1, 2 };
536         int i, j;
537
538         for (i=0;i<ARRAY_SIZE(levels);i++) {
539                 int level = levels[i];
540                 DATA_BLOB blob;
541                 uint32_t needed;
542                 uint32_t count;
543                 union spoolss_MonitorInfo *info;
544
545                 r.in.servername = "";
546                 r.in.level = level;
547                 r.in.buffer = NULL;
548                 r.in.offered = 0;
549                 r.out.needed = &needed;
550                 r.out.count = &count;
551                 r.out.info = &info;
552
553                 torture_comment(tctx, "Testing EnumMonitors level %u\n", r.in.level);
554
555                 status = dcerpc_spoolss_EnumMonitors(p, ctx, &r);
556                 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EnumMonitors failed");
557                 if (W_ERROR_IS_OK(r.out.result)) {
558                         /* TODO: do some more checks here */
559                         continue;
560                 }
561                 torture_assert_werr_equal(tctx, r.out.result, WERR_INSUFFICIENT_BUFFER,
562                         "EnumMonitors failed");
563
564                 blob = data_blob_talloc(ctx, NULL, needed);
565                 data_blob_clear(&blob);
566                 r.in.buffer = &blob;
567                 r.in.offered = needed;
568
569                 status = dcerpc_spoolss_EnumMonitors(p, ctx, &r);
570                 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EnumMonitors failed");
571
572                 torture_assert_werr_ok(tctx, r.out.result, "EnumMonitors failed");
573
574                 CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumMonitors, info, r.in.level, count, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
575
576                 ctx->monitor_count[level]       = count;
577                 ctx->monitors[level]            = info;
578         }
579
580         for (i=1;i<ARRAY_SIZE(levels);i++) {
581                 int level = levels[i];
582                 int old_level = levels[i-1];
583                 torture_assert_int_equal(tctx, ctx->monitor_count[level], ctx->monitor_count[old_level],
584                                          "EnumMonitors invalid value");
585         }
586
587         for (i=0;i<ARRAY_SIZE(levels);i++) {
588                 int level = levels[i];
589                 for (j=0;j<ctx->monitor_count[level];j++) {
590                         union spoolss_MonitorInfo *cur = &ctx->monitors[level][j];
591                         union spoolss_MonitorInfo *ref = &ctx->monitors[2][j];
592                         switch (level) {
593                         case 1:
594                                 COMPARE_STRING(tctx, cur->info1, ref->info2, monitor_name);
595                                 break;
596                         case 2:
597                                 /* level 2 is our reference, and it makes no sense to compare it to itself */
598                                 break;
599                         }
600                 }
601         }
602
603         return true;
604 }
605
606 static bool test_EnumPrintProcessors(struct torture_context *tctx,
607                                      struct dcerpc_pipe *p,
608                                      struct test_spoolss_context *ctx)
609 {
610         NTSTATUS status;
611         struct spoolss_EnumPrintProcessors r;
612         uint16_t levels[] = { 1 };
613         int i, j;
614
615         for (i=0;i<ARRAY_SIZE(levels);i++) {
616                 int level = levels[i];
617                 DATA_BLOB blob;
618                 uint32_t needed;
619                 uint32_t count;
620                 union spoolss_PrintProcessorInfo *info;
621
622                 r.in.servername = "";
623                 r.in.environment = SPOOLSS_ARCHITECTURE_NT_X86;
624                 r.in.level = level;
625                 r.in.buffer = NULL;
626                 r.in.offered = 0;
627                 r.out.needed = &needed;
628                 r.out.count = &count;
629                 r.out.info = &info;
630
631                 torture_comment(tctx, "Testing EnumPrintProcessors level %u\n", r.in.level);
632
633                 status = dcerpc_spoolss_EnumPrintProcessors(p, ctx, &r);
634                 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EnumPrintProcessors failed");
635                 if (W_ERROR_IS_OK(r.out.result)) {
636                         /* TODO: do some more checks here */
637                         continue;
638                 }
639                 torture_assert_werr_equal(tctx, r.out.result, WERR_INSUFFICIENT_BUFFER,
640                         "EnumPrintProcessors unexpected return code");
641
642                 blob = data_blob_talloc(ctx, NULL, needed);
643                 data_blob_clear(&blob);
644                 r.in.buffer = &blob;
645                 r.in.offered = needed;
646
647                 status = dcerpc_spoolss_EnumPrintProcessors(p, ctx, &r);
648                 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EnumPrintProcessors failed");
649
650                 torture_assert_werr_ok(tctx, r.out.result, "EnumPrintProcessors failed");
651
652                 CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumPrintProcessors, info, r.in.level, count, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
653
654                 ctx->print_processor_count[level]       = count;
655                 ctx->print_processors[level]            = info;
656         }
657
658         for (i=1;i<ARRAY_SIZE(levels);i++) {
659                 int level = levels[i];
660                 int old_level = levels[i-1];
661                 torture_assert_int_equal(tctx, ctx->print_processor_count[level], ctx->print_processor_count[old_level],
662                         "EnumPrintProcessors failed");
663         }
664
665         for (i=0;i<ARRAY_SIZE(levels);i++) {
666                 int level = levels[i];
667                 for (j=0;j<ctx->print_processor_count[level];j++) {
668 #if 0
669                         union spoolss_PrintProcessorInfo *cur = &ctx->print_processors[level][j];
670                         union spoolss_PrintProcessorInfo *ref = &ctx->print_processors[1][j];
671 #endif
672                         switch (level) {
673                         case 1:
674                                 /* level 1 is our reference, and it makes no sense to compare it to itself */
675                                 break;
676                         }
677                 }
678         }
679
680         return true;
681 }
682
683 static bool test_EnumPrintProcDataTypes(struct torture_context *tctx,
684                                         struct dcerpc_pipe *p,
685                                         struct test_spoolss_context *ctx)
686 {
687         NTSTATUS status;
688         struct spoolss_EnumPrintProcDataTypes r;
689         uint16_t levels[] = { 1 };
690         int i;
691
692         for (i=0;i<ARRAY_SIZE(levels);i++) {
693                 int level = levels[i];
694                 DATA_BLOB blob;
695                 uint32_t needed;
696                 uint32_t count;
697                 union spoolss_PrintProcDataTypesInfo *info;
698
699                 r.in.servername = "";
700                 r.in.print_processor_name = "winprint";
701                 r.in.level = level;
702                 r.in.buffer = NULL;
703                 r.in.offered = 0;
704                 r.out.needed = &needed;
705                 r.out.count = &count;
706                 r.out.info = &info;
707
708                 torture_comment(tctx, "Testing EnumPrintProcDataTypes level %u\n", r.in.level);
709
710                 status = dcerpc_spoolss_EnumPrintProcDataTypes(p, ctx, &r);
711                 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EnumPrintProcDataType failed");
712                 if (W_ERROR_IS_OK(r.out.result)) {
713                         /* TODO: do some more checks here */
714                         continue;
715                 }
716                 torture_assert_werr_equal(tctx, r.out.result, WERR_INSUFFICIENT_BUFFER,
717                         "EnumPrintProcDataTypes unexpected return code");
718
719                 blob = data_blob_talloc(ctx, NULL, needed);
720                 data_blob_clear(&blob);
721                 r.in.buffer = &blob;
722                 r.in.offered = needed;
723
724                 status = dcerpc_spoolss_EnumPrintProcDataTypes(p, ctx, &r);
725                 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EnumPrintProcDataTypes failed");
726
727                 torture_assert_werr_ok(tctx, r.out.result, "EnumPrintProcDataTypes failed");
728
729                 CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumPrintProcDataTypes, info, r.in.level, count, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
730
731         }
732
733         return true;
734 }
735
736
737 static bool test_EnumPrinters(struct torture_context *tctx,
738                               struct dcerpc_pipe *p,
739                               struct test_spoolss_context *ctx)
740 {
741         struct spoolss_EnumPrinters r;
742         NTSTATUS status;
743         uint16_t levels[] = { 0, 1, 2, 4, 5 };
744         int i, j;
745
746         for (i=0;i<ARRAY_SIZE(levels);i++) {
747                 int level = levels[i];
748                 DATA_BLOB blob;
749                 uint32_t needed;
750                 uint32_t count;
751                 union spoolss_PrinterInfo *info;
752
753                 r.in.flags      = PRINTER_ENUM_LOCAL;
754                 r.in.server     = "";
755                 r.in.level      = level;
756                 r.in.buffer     = NULL;
757                 r.in.offered    = 0;
758                 r.out.needed    = &needed;
759                 r.out.count     = &count;
760                 r.out.info      = &info;
761
762                 torture_comment(tctx, "Testing EnumPrinters level %u\n", r.in.level);
763
764                 status = dcerpc_spoolss_EnumPrinters(p, ctx, &r);
765                 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EnumPrinters failed");
766                 if (W_ERROR_IS_OK(r.out.result)) {
767                         /* TODO: do some more checks here */
768                         continue;
769                 }
770                 torture_assert_werr_equal(tctx, r.out.result, WERR_INSUFFICIENT_BUFFER,
771                         "EnumPrinters unexpected return code");
772
773                 blob = data_blob_talloc(ctx, NULL, needed);
774                 data_blob_clear(&blob);
775                 r.in.buffer = &blob;
776                 r.in.offered = needed;
777
778                 status = dcerpc_spoolss_EnumPrinters(p, ctx, &r);
779                 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EnumPrinters failed");
780
781                 torture_assert_werr_ok(tctx, r.out.result, "EnumPrinters failed");
782
783                 CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumPrinters, info, r.in.level, count, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
784
785                 ctx->printer_count[level]       = count;
786                 ctx->printers[level]            = info;
787         }
788
789         for (i=1;i<ARRAY_SIZE(levels);i++) {
790                 int level = levels[i];
791                 int old_level = levels[i-1];
792                 torture_assert_int_equal(tctx, ctx->printer_count[level], ctx->printer_count[old_level],
793                                          "EnumPrinters invalid value");
794         }
795
796         for (i=0;i<ARRAY_SIZE(levels);i++) {
797                 int level = levels[i];
798                 for (j=0;j<ctx->printer_count[level];j++) {
799                         union spoolss_PrinterInfo *cur = &ctx->printers[level][j];
800                         union spoolss_PrinterInfo *ref = &ctx->printers[2][j];
801                         switch (level) {
802                         case 0:
803                                 COMPARE_STRING(tctx, cur->info0, ref->info2, printername);
804                                 COMPARE_STRING(tctx, cur->info0, ref->info2, servername);
805                                 COMPARE_UINT32(tctx, cur->info0, ref->info2, cjobs);
806                                 /*COMPARE_UINT32(tctx, cur->info0, ref->info2, total_jobs);
807                                 COMPARE_UINT32(tctx, cur->info0, ref->info2, total_bytes);
808                                 COMPARE_SPOOLSS_TIME(cur->info0, ref->info2, spoolss_Time time);
809                                 COMPARE_UINT32(tctx, cur->info0, ref->info2, global_counter);
810                                 COMPARE_UINT32(tctx, cur->info0, ref->info2, total_pages);
811                                 COMPARE_UINT32(tctx, cur->info0, ref->info2, version);
812                                 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown10);
813                                 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown11);
814                                 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown12);
815                                 COMPARE_UINT32(tctx, cur->info0, ref->info2, session_counter);
816                                 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown14);
817                                 COMPARE_UINT32(tctx, cur->info0, ref->info2, printer_errors);
818                                 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown16);
819                                 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown17);
820                                 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown18);
821                                 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown19);
822                                 COMPARE_UINT32(tctx, cur->info0, ref->info2, change_id);
823                                 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown21);*/
824                                 COMPARE_UINT32(tctx, cur->info0, ref->info2, status);
825                                 /*COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown23);
826                                 COMPARE_UINT32(tctx, cur->info0, ref->info2, c_setprinter);
827                                 COMPARE_UINT16(cur->info0, ref->info2, unknown25);
828                                 COMPARE_UINT16(cur->info0, ref->info2, unknown26);
829                                 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown27);
830                                 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown28);
831                                 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown29);*/
832                                 break;
833                         case 1:
834                                 /*COMPARE_UINT32(tctx, cur->info1, ref->info2, flags);*/
835                                 /*COMPARE_STRING(tctx, cur->info1, ref->info2, name);*/
836                                 /*COMPARE_STRING(tctx, cur->info1, ref->info2, description);*/
837                                 COMPARE_STRING(tctx, cur->info1, ref->info2, comment);
838                                 break;
839                         case 2:
840                                 /* level 2 is our reference, and it makes no sense to compare it to itself */
841                                 break;
842                         case 4:
843                                 COMPARE_STRING(tctx, cur->info4, ref->info2, printername);
844                                 COMPARE_STRING(tctx, cur->info4, ref->info2, servername);
845                                 COMPARE_UINT32(tctx, cur->info4, ref->info2, attributes);
846                                 break;
847                         case 5:
848                                 COMPARE_STRING(tctx, cur->info5, ref->info2, printername);
849                                 COMPARE_STRING(tctx, cur->info5, ref->info2, portname);
850                                 COMPARE_UINT32(tctx, cur->info5, ref->info2, attributes);
851                                 /*COMPARE_UINT32(tctx, cur->info5, ref->info2, device_not_selected_timeout);
852                                 COMPARE_UINT32(tctx, cur->info5, ref->info2, transmission_retry_timeout);*/
853                                 break;
854                         }
855                 }
856         }
857
858         /* TODO:
859          *      - verify that the port of a printer was in the list returned by EnumPorts
860          */
861
862         return true;
863 }
864
865 static bool test_GetPrinterDriver2(struct torture_context *tctx,
866                                    struct dcerpc_pipe *p,
867                                    struct policy_handle *handle,
868                                    const char *driver_name);
869
870 bool test_GetPrinter_level(struct torture_context *tctx,
871                            struct dcerpc_pipe *p,
872                            struct policy_handle *handle,
873                            uint32_t level,
874                            union spoolss_PrinterInfo *info)
875 {
876         struct spoolss_GetPrinter r;
877         uint32_t needed;
878
879         r.in.handle = handle;
880         r.in.level = level;
881         r.in.buffer = NULL;
882         r.in.offered = 0;
883         r.out.needed = &needed;
884
885         torture_comment(tctx, "Testing GetPrinter level %u\n", r.in.level);
886
887         torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_GetPrinter(p, tctx, &r),
888                 "GetPrinter failed");
889
890         if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
891                 DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed);
892                 data_blob_clear(&blob);
893                 r.in.buffer = &blob;
894                 r.in.offered = needed;
895
896                 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_GetPrinter(p, tctx, &r),
897                         "GetPrinter failed");
898         }
899
900         torture_assert_werr_ok(tctx, r.out.result, "GetPrinter failed");
901
902         CHECK_NEEDED_SIZE_LEVEL(spoolss_PrinterInfo, r.out.info, r.in.level, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
903
904         if (info && r.out.info) {
905                 *info = *r.out.info;
906         }
907
908         return true;
909 }
910
911
912 static bool test_GetPrinter(struct torture_context *tctx,
913                             struct dcerpc_pipe *p,
914                             struct policy_handle *handle)
915 {
916         uint32_t levels[] = {0, 1, 2, 3, 4, 5, 6, 7, 8};
917         int i;
918
919         for (i=0;i<ARRAY_SIZE(levels);i++) {
920
921                 union spoolss_PrinterInfo info;
922
923                 ZERO_STRUCT(info);
924
925                 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, levels[i], &info),
926                         "failed to call GetPrinter");
927
928                 if ((levels[i] == 2) && info.info2.drivername && strlen(info.info2.drivername)) {
929                         torture_assert(tctx,
930                                 test_GetPrinterDriver2(tctx, p, handle, info.info2.drivername),
931                                 "failed to call test_GetPrinterDriver2");
932                 }
933         }
934
935         return true;
936 }
937
938 static bool test_SetPrinter(struct torture_context *tctx,
939                             struct dcerpc_pipe *p,
940                             struct policy_handle *handle,
941                             struct spoolss_SetPrinterInfoCtr *info_ctr,
942                             struct spoolss_DevmodeContainer *devmode_ctr,
943                             struct sec_desc_buf *secdesc_ctr,
944                             enum spoolss_PrinterControl command)
945 {
946         struct spoolss_SetPrinter r;
947
948         r.in.handle = handle;
949         r.in.info_ctr = info_ctr;
950         r.in.devmode_ctr = devmode_ctr;
951         r.in.secdesc_ctr = secdesc_ctr;
952         r.in.command = command;
953
954         torture_comment(tctx, "Testing SetPrinter level %d\n", r.in.info_ctr->level);
955
956         torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_SetPrinter(p, tctx, &r),
957                 "failed to call SetPrinter");
958         torture_assert_werr_ok(tctx, r.out.result,
959                 "failed to call SetPrinter");
960
961         return true;
962 }
963
964 static bool test_SetPrinter_errors(struct torture_context *tctx,
965                                    struct dcerpc_pipe *p,
966                                    struct policy_handle *handle)
967 {
968         struct spoolss_SetPrinter r;
969         uint16_t levels[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
970         int i;
971
972         struct spoolss_SetPrinterInfoCtr info_ctr;
973         struct spoolss_DevmodeContainer devmode_ctr;
974         struct sec_desc_buf secdesc_ctr;
975
976         info_ctr.level = 0;
977         info_ctr.info.info0 = NULL;
978
979         ZERO_STRUCT(devmode_ctr);
980         ZERO_STRUCT(secdesc_ctr);
981
982         r.in.handle = handle;
983         r.in.info_ctr = &info_ctr;
984         r.in.devmode_ctr = &devmode_ctr;
985         r.in.secdesc_ctr = &secdesc_ctr;
986         r.in.command = 0;
987
988         torture_comment(tctx, "Testing SetPrinter all zero\n");
989
990         torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_SetPrinter(p, tctx, &r),
991                 "failed to call SetPrinter");
992         torture_assert_werr_equal(tctx, r.out.result, WERR_INVALID_PARAM,
993                 "failed to call SetPrinter");
994
995  again:
996         for (i=0; i < ARRAY_SIZE(levels); i++) {
997
998                 struct spoolss_SetPrinterInfo0 info0;
999                 struct spoolss_SetPrinterInfo1 info1;
1000                 struct spoolss_SetPrinterInfo2 info2;
1001                 struct spoolss_SetPrinterInfo3 info3;
1002                 struct spoolss_SetPrinterInfo4 info4;
1003                 struct spoolss_SetPrinterInfo5 info5;
1004                 struct spoolss_SetPrinterInfo6 info6;
1005                 struct spoolss_SetPrinterInfo7 info7;
1006                 struct spoolss_SetPrinterInfo8 info8;
1007                 struct spoolss_SetPrinterInfo9 info9;
1008
1009
1010                 info_ctr.level = levels[i];
1011                 switch (levels[i]) {
1012                 case 0:
1013                         ZERO_STRUCT(info0);
1014                         info_ctr.info.info0 = &info0;
1015                         break;
1016                 case 1:
1017                         ZERO_STRUCT(info1);
1018                         info_ctr.info.info1 = &info1;
1019                         break;
1020                 case 2:
1021                         ZERO_STRUCT(info2);
1022                         info_ctr.info.info2 = &info2;
1023                         break;
1024                 case 3:
1025                         ZERO_STRUCT(info3);
1026                         info_ctr.info.info3 = &info3;
1027                         break;
1028                 case 4:
1029                         ZERO_STRUCT(info4);
1030                         info_ctr.info.info4 = &info4;
1031                         break;
1032                 case 5:
1033                         ZERO_STRUCT(info5);
1034                         info_ctr.info.info5 = &info5;
1035                         break;
1036                 case 6:
1037                         ZERO_STRUCT(info6);
1038                         info_ctr.info.info6 = &info6;
1039                         break;
1040                 case 7:
1041                         ZERO_STRUCT(info7);
1042                         info_ctr.info.info7 = &info7;
1043                         break;
1044                 case 8:
1045                         ZERO_STRUCT(info8);
1046                         info_ctr.info.info8 = &info8;
1047                         break;
1048                 case 9:
1049                         ZERO_STRUCT(info9);
1050                         info_ctr.info.info9 = &info9;
1051                         break;
1052                 }
1053
1054                 torture_comment(tctx, "Testing SetPrinter level %d, command %d\n",
1055                         info_ctr.level, r.in.command);
1056
1057                 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_SetPrinter(p, tctx, &r),
1058                         "failed to call SetPrinter");
1059
1060                 switch (r.in.command) {
1061                 case SPOOLSS_PRINTER_CONTROL_UNPAUSE: /* 0 */
1062                         /* is ignored for all levels other then 0 */
1063                         if (info_ctr.level > 0) {
1064                                 /* ignored then */
1065                                 break;
1066                         }
1067                 case SPOOLSS_PRINTER_CONTROL_PAUSE: /* 1 */
1068                 case SPOOLSS_PRINTER_CONTROL_RESUME: /* 2 */
1069                 case SPOOLSS_PRINTER_CONTROL_PURGE: /* 3 */
1070                         if (info_ctr.level > 0) {
1071                                 /* is invalid for all levels other then 0 */
1072                                 torture_assert_werr_equal(tctx, r.out.result, WERR_INVALID_PRINTER_COMMAND,
1073                                         "unexpected error code returned");
1074                                 continue;
1075                         } else {
1076                                 torture_assert_werr_ok(tctx, r.out.result,
1077                                         "failed to call SetPrinter with non 0 command");
1078                                 continue;
1079                         }
1080                         break;
1081
1082                 case SPOOLSS_PRINTER_CONTROL_SET_STATUS: /* 4 */
1083                         /* FIXME: gd needs further investigation */
1084                 default:
1085                         torture_assert_werr_equal(tctx, r.out.result, WERR_INVALID_PRINTER_COMMAND,
1086                                 "unexpected error code returned");
1087                         continue;
1088                 }
1089
1090                 switch (info_ctr.level) {
1091                 case 1:
1092                         torture_assert_werr_equal(tctx, r.out.result, WERR_UNKNOWN_LEVEL,
1093                                 "unexpected error code returned");
1094                         break;
1095                 case 2:
1096                         torture_assert_werr_equal(tctx, r.out.result, WERR_UNKNOWN_PRINTER_DRIVER,
1097                                 "unexpected error code returned");
1098                         break;
1099                 case 3:
1100                 case 4:
1101                 case 5:
1102                 case 7:
1103                         torture_assert_werr_equal(tctx, r.out.result, WERR_INVALID_PARAM,
1104                                 "unexpected error code returned");
1105                         break;
1106                 case 9:
1107                         torture_assert_werr_equal(tctx, r.out.result, WERR_NOT_SUPPORTED,
1108                                 "unexpected error code returned");
1109                         break;
1110                 default:
1111                         torture_assert_werr_ok(tctx, r.out.result,
1112                                 "failed to call SetPrinter");
1113                         break;
1114                 }
1115         }
1116
1117         if (r.in.command < 5) {
1118                 r.in.command++;
1119                 goto again;
1120         }
1121
1122         return true;
1123 }
1124
1125 static void clear_info2(struct spoolss_SetPrinterInfoCtr *r)
1126 {
1127         if ((r->level == 2) && (r->info.info2)) {
1128                 r->info.info2->secdesc_ptr = 0;
1129                 r->info.info2->devmode_ptr = 0;
1130         }
1131 }
1132
1133 static bool test_PrinterInfo(struct torture_context *tctx,
1134                              struct dcerpc_pipe *p,
1135                              struct policy_handle *handle)
1136 {
1137         NTSTATUS status;
1138         struct spoolss_SetPrinter s;
1139         struct spoolss_GetPrinter q;
1140         struct spoolss_GetPrinter q0;
1141         struct spoolss_SetPrinterInfoCtr info_ctr;
1142         union spoolss_PrinterInfo info;
1143         struct spoolss_DevmodeContainer devmode_ctr;
1144         struct sec_desc_buf secdesc_ctr;
1145         uint32_t needed;
1146         bool ret = true;
1147         int i;
1148
1149         uint32_t status_list[] = {
1150                 /* these do not stick
1151                 PRINTER_STATUS_PAUSED,
1152                 PRINTER_STATUS_ERROR,
1153                 PRINTER_STATUS_PENDING_DELETION, */
1154                 PRINTER_STATUS_PAPER_JAM,
1155                 PRINTER_STATUS_PAPER_OUT,
1156                 PRINTER_STATUS_MANUAL_FEED,
1157                 PRINTER_STATUS_PAPER_PROBLEM,
1158                 PRINTER_STATUS_OFFLINE,
1159                 PRINTER_STATUS_IO_ACTIVE,
1160                 PRINTER_STATUS_BUSY,
1161                 PRINTER_STATUS_PRINTING,
1162                 PRINTER_STATUS_OUTPUT_BIN_FULL,
1163                 PRINTER_STATUS_NOT_AVAILABLE,
1164                 PRINTER_STATUS_WAITING,
1165                 PRINTER_STATUS_PROCESSING,
1166                 PRINTER_STATUS_INITIALIZING,
1167                 PRINTER_STATUS_WARMING_UP,
1168                 PRINTER_STATUS_TONER_LOW,
1169                 PRINTER_STATUS_NO_TONER,
1170                 PRINTER_STATUS_PAGE_PUNT,
1171                 PRINTER_STATUS_USER_INTERVENTION,
1172                 PRINTER_STATUS_OUT_OF_MEMORY,
1173                 PRINTER_STATUS_DOOR_OPEN,
1174                 PRINTER_STATUS_SERVER_UNKNOWN,
1175                 PRINTER_STATUS_POWER_SAVE,
1176                 /* these do not stick
1177                 0x02000000,
1178                 0x04000000,
1179                 0x08000000,
1180                 0x10000000,
1181                 0x20000000,
1182                 0x40000000,
1183                 0x80000000 */
1184         };
1185         uint32_t default_attribute = PRINTER_ATTRIBUTE_LOCAL;
1186         uint32_t attribute_list[] = {
1187                 PRINTER_ATTRIBUTE_QUEUED,
1188                 /* fails with WERR_INVALID_DATATYPE:
1189                 PRINTER_ATTRIBUTE_DIRECT, */
1190                 /* does not stick
1191                 PRINTER_ATTRIBUTE_DEFAULT, */
1192                 PRINTER_ATTRIBUTE_SHARED,
1193                 /* does not stick
1194                 PRINTER_ATTRIBUTE_NETWORK, */
1195                 PRINTER_ATTRIBUTE_HIDDEN,
1196                 PRINTER_ATTRIBUTE_LOCAL,
1197                 PRINTER_ATTRIBUTE_ENABLE_DEVQ,
1198                 PRINTER_ATTRIBUTE_KEEPPRINTEDJOBS,
1199                 PRINTER_ATTRIBUTE_DO_COMPLETE_FIRST,
1200                 PRINTER_ATTRIBUTE_WORK_OFFLINE,
1201                 /* does not stick
1202                 PRINTER_ATTRIBUTE_ENABLE_BIDI, */
1203                 /* fails with WERR_INVALID_DATATYPE:
1204                 PRINTER_ATTRIBUTE_RAW_ONLY, */
1205                 /* these do not stick
1206                 PRINTER_ATTRIBUTE_PUBLISHED,
1207                 PRINTER_ATTRIBUTE_FAX,
1208                 PRINTER_ATTRIBUTE_TS,
1209                 0x00010000,
1210                 0x00020000,
1211                 0x00040000,
1212                 0x00080000,
1213                 0x00100000,
1214                 0x00200000,
1215                 0x00400000,
1216                 0x00800000,
1217                 0x01000000,
1218                 0x02000000,
1219                 0x04000000,
1220                 0x08000000,
1221                 0x10000000,
1222                 0x20000000,
1223                 0x40000000,
1224                 0x80000000 */
1225         };
1226
1227         ZERO_STRUCT(devmode_ctr);
1228         ZERO_STRUCT(secdesc_ctr);
1229
1230         s.in.handle = handle;
1231         s.in.command = 0;
1232         s.in.info_ctr = &info_ctr;
1233         s.in.devmode_ctr = &devmode_ctr;
1234         s.in.secdesc_ctr = &secdesc_ctr;
1235
1236         q.in.handle = handle;
1237         q.out.info = &info;
1238         q0 = q;
1239
1240 #define TESTGETCALL(call, r) \
1241                 r.in.buffer = NULL; \
1242                 r.in.offered = 0;\
1243                 r.out.needed = &needed; \
1244                 status = dcerpc_spoolss_ ##call(p, tctx, &r); \
1245                 if (!NT_STATUS_IS_OK(status)) { \
1246                         torture_comment(tctx, #call " level %u failed - %s (%s)\n", \
1247                                r.in.level, nt_errstr(status), __location__); \
1248                         ret = false; \
1249                         break; \
1250                 }\
1251                 if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {\
1252                         DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed); \
1253                         data_blob_clear(&blob); \
1254                         r.in.buffer = &blob; \
1255                         r.in.offered = needed; \
1256                 }\
1257                 status = dcerpc_spoolss_ ##call(p, tctx, &r); \
1258                 if (!NT_STATUS_IS_OK(status)) { \
1259                         torture_comment(tctx, #call " level %u failed - %s (%s)\n", \
1260                                r.in.level, nt_errstr(status), __location__); \
1261                         ret = false; \
1262                         break; \
1263                 } \
1264                 if (!W_ERROR_IS_OK(r.out.result)) { \
1265                         torture_comment(tctx, #call " level %u failed - %s (%s)\n", \
1266                                r.in.level, win_errstr(r.out.result), __location__); \
1267                         ret = false; \
1268                         break; \
1269                 }
1270
1271
1272 #define TESTSETCALL_EXP(call, r, err) \
1273                 clear_info2(&info_ctr);\
1274                 status = dcerpc_spoolss_ ##call(p, tctx, &r); \
1275                 if (!NT_STATUS_IS_OK(status)) { \
1276                         torture_comment(tctx, #call " level %u failed - %s (%s)\n", \
1277                                r.in.info_ctr->level, nt_errstr(status), __location__); \
1278                         ret = false; \
1279                         break; \
1280                 } \
1281                 if (!W_ERROR_IS_OK(err)) { \
1282                         if (!W_ERROR_EQUAL(err, r.out.result)) { \
1283                                 torture_comment(tctx, #call " level %u failed - %s, expected %s (%s)\n", \
1284                                        r.in.info_ctr->level, win_errstr(r.out.result), win_errstr(err), __location__); \
1285                                 ret = false; \
1286                         } \
1287                         break; \
1288                 } \
1289                 if (!W_ERROR_IS_OK(r.out.result)) { \
1290                         torture_comment(tctx, #call " level %u failed - %s (%s)\n", \
1291                                r.in.info_ctr->level, win_errstr(r.out.result), __location__); \
1292                         ret = false; \
1293                         break; \
1294                 }
1295
1296 #define TESTSETCALL(call, r) \
1297         TESTSETCALL_EXP(call, r, WERR_OK)
1298
1299 #define STRING_EQUAL(s1, s2, field) \
1300                 if ((s1 && !s2) || (s2 && !s1) || strcmp(s1, s2)) { \
1301                         torture_comment(tctx, "Failed to set %s to '%s' (%s)\n", \
1302                                #field, s2, __location__); \
1303                         ret = false; \
1304                         break; \
1305                 }
1306
1307 #define MEM_EQUAL(s1, s2, length, field) \
1308                 if ((s1 && !s2) || (s2 && !s1) || memcmp(s1, s2, length)) { \
1309                         torture_comment(tctx, "Failed to set %s to '%s' (%s)\n", \
1310                                #field, (const char *)s2, __location__); \
1311                         ret = false; \
1312                         break; \
1313                 }
1314
1315 #define INT_EQUAL(i1, i2, field) \
1316                 if (i1 != i2) { \
1317                         torture_comment(tctx, "Failed to set %s to 0x%llx - got 0x%llx (%s)\n", \
1318                                #field, (unsigned long long)i2, (unsigned long long)i1, __location__); \
1319                         ret = false; \
1320                         break; \
1321                 }
1322
1323 #define SD_EQUAL(sd1, sd2, field) \
1324                 if (!security_descriptor_equal(sd1, sd2)) { \
1325                         torture_comment(tctx, "Failed to set %s (%s)\n", \
1326                                #field, __location__); \
1327                         ret = false; \
1328                         break; \
1329                 }
1330
1331 #define TEST_PRINTERINFO_STRING_EXP_ERR(lvl1, field1, lvl2, field2, value, err) do { \
1332                 torture_comment(tctx, "field test %d/%s vs %d/%s\n", lvl1, #field1, lvl2, #field2); \
1333                 q.in.level = lvl1; \
1334                 TESTGETCALL(GetPrinter, q) \
1335                 info_ctr.level = lvl1; \
1336                 info_ctr.info.info ## lvl1 = (struct spoolss_SetPrinterInfo ## lvl1 *)&q.out.info->info ## lvl1; \
1337                 info_ctr.info.info ## lvl1->field1 = value;\
1338                 TESTSETCALL_EXP(SetPrinter, s, err) \
1339                 info_ctr.info.info ## lvl1->field1 = ""; \
1340                 TESTGETCALL(GetPrinter, q) \
1341                 info_ctr.info.info ## lvl1->field1 = value; \
1342                 STRING_EQUAL(info_ctr.info.info ## lvl1->field1, value, field1); \
1343                 q.in.level = lvl2; \
1344                 TESTGETCALL(GetPrinter, q) \
1345                 info_ctr.info.info ## lvl2 = (struct spoolss_SetPrinterInfo ## lvl2 *)&q.out.info->info ## lvl2; \
1346                 STRING_EQUAL(info_ctr.info.info ## lvl2->field2, value, field2); \
1347         } while (0)
1348
1349 #define TEST_PRINTERINFO_STRING(lvl1, field1, lvl2, field2, value) do { \
1350         TEST_PRINTERINFO_STRING_EXP_ERR(lvl1, field1, lvl2, field2, value, WERR_OK); \
1351         } while (0);
1352
1353 #define TEST_PRINTERINFO_INT_EXP(lvl1, field1, lvl2, field2, value, exp_value) do { \
1354                 torture_comment(tctx, "field test %d/%s vs %d/%s\n", lvl1, #field1, lvl2, #field2); \
1355                 q.in.level = lvl1; \
1356                 TESTGETCALL(GetPrinter, q) \
1357                 info_ctr.level = lvl1; \
1358                 info_ctr.info.info ## lvl1 = (struct spoolss_SetPrinterInfo ## lvl1 *)&q.out.info->info ## lvl1; \
1359                 info_ctr.info.info ## lvl1->field1 = value; \
1360                 TESTSETCALL(SetPrinter, s) \
1361                 info_ctr.info.info ## lvl1->field1 = 0; \
1362                 TESTGETCALL(GetPrinter, q) \
1363                 info_ctr.info.info ## lvl1 = (struct spoolss_SetPrinterInfo ## lvl1 *)&q.out.info->info ## lvl1; \
1364                 INT_EQUAL(info_ctr.info.info ## lvl1->field1, exp_value, field1); \
1365                 q.in.level = lvl2; \
1366                 TESTGETCALL(GetPrinter, q) \
1367                 info_ctr.info.info ## lvl2 = (struct spoolss_SetPrinterInfo ## lvl2 *)&q.out.info->info ## lvl2; \
1368                 INT_EQUAL(info_ctr.info.info ## lvl2->field2, exp_value, field1); \
1369         } while (0)
1370
1371 #define TEST_PRINTERINFO_INT(lvl1, field1, lvl2, field2, value) do { \
1372         TEST_PRINTERINFO_INT_EXP(lvl1, field1, lvl2, field2, value, value); \
1373         } while (0)
1374
1375         q0.in.level = 0;
1376         do { TESTGETCALL(GetPrinter, q0) } while (0);
1377
1378         TEST_PRINTERINFO_STRING(2, comment,  1, comment, "xx2-1 comment");
1379         TEST_PRINTERINFO_STRING(2, comment,  2, comment, "xx2-2 comment");
1380
1381         /* level 0 printername does not stick */
1382 /*      TEST_PRINTERINFO_STRING(2, printername,  0, printername, "xx2-0 printer"); */
1383         TEST_PRINTERINFO_STRING(2, printername,  1, name,        "xx2-1 printer");
1384         TEST_PRINTERINFO_STRING(2, printername,  2, printername, "xx2-2 printer");
1385         TEST_PRINTERINFO_STRING(2, printername,  4, printername, "xx2-4 printer");
1386         TEST_PRINTERINFO_STRING(2, printername,  5, printername, "xx2-5 printer");
1387 /*      TEST_PRINTERINFO_STRING(4, printername,  0, printername, "xx4-0 printer"); */
1388         TEST_PRINTERINFO_STRING(4, printername,  1, name,        "xx4-1 printer");
1389         TEST_PRINTERINFO_STRING(4, printername,  2, printername, "xx4-2 printer");
1390         TEST_PRINTERINFO_STRING(4, printername,  4, printername, "xx4-4 printer");
1391         TEST_PRINTERINFO_STRING(4, printername,  5, printername, "xx4-5 printer");
1392 /*      TEST_PRINTERINFO_STRING(5, printername,  0, printername, "xx5-0 printer"); */
1393         TEST_PRINTERINFO_STRING(5, printername,  1, name,        "xx5-1 printer");
1394         TEST_PRINTERINFO_STRING(5, printername,  2, printername, "xx5-2 printer");
1395         TEST_PRINTERINFO_STRING(5, printername,  4, printername, "xx5-4 printer");
1396         TEST_PRINTERINFO_STRING(5, printername,  5, printername, "xx5-5 printer");
1397
1398         /* servername can be set but does not stick
1399         TEST_PRINTERINFO_STRING(2, servername,  0, servername, "xx2-0 servername");
1400         TEST_PRINTERINFO_STRING(2, servername,  2, servername, "xx2-2 servername");
1401         TEST_PRINTERINFO_STRING(2, servername,  4, servername, "xx2-4 servername");
1402         */
1403
1404         /* passing an invalid port will result in WERR_UNKNOWN_PORT */
1405         TEST_PRINTERINFO_STRING_EXP_ERR(2, portname,  2, portname, "xx2-2 portname", WERR_UNKNOWN_PORT);
1406         TEST_PRINTERINFO_STRING_EXP_ERR(2, portname,  5, portname, "xx2-5 portname", WERR_UNKNOWN_PORT);
1407         TEST_PRINTERINFO_STRING_EXP_ERR(5, portname,  2, portname, "xx5-2 portname", WERR_UNKNOWN_PORT);
1408         TEST_PRINTERINFO_STRING_EXP_ERR(5, portname,  5, portname, "xx5-5 portname", WERR_UNKNOWN_PORT);
1409
1410         TEST_PRINTERINFO_STRING(2, sharename,   2, sharename,   "xx2-2 sharename");
1411         /* passing an invalid driver will result in WERR_UNKNOWN_PRINTER_DRIVER */
1412         TEST_PRINTERINFO_STRING_EXP_ERR(2, drivername,  2, drivername,  "xx2-2 drivername", WERR_UNKNOWN_PRINTER_DRIVER);
1413         TEST_PRINTERINFO_STRING(2, location,    2, location,    "xx2-2 location");
1414         /* passing an invalid sepfile will result in WERR_INVALID_SEPARATOR_FILE */
1415         TEST_PRINTERINFO_STRING_EXP_ERR(2, sepfile,     2, sepfile,     "xx2-2 sepfile", WERR_INVALID_SEPARATOR_FILE);
1416         /* passing an invalid printprocessor will result in WERR_UNKNOWN_PRINTPROCESSOR */
1417         TEST_PRINTERINFO_STRING_EXP_ERR(2, printprocessor, 2, printprocessor, "xx2-2 printprocessor", WERR_UNKNOWN_PRINTPROCESSOR);
1418         TEST_PRINTERINFO_STRING(2, datatype,    2, datatype,    "xx2-2 datatype");
1419         TEST_PRINTERINFO_STRING(2, parameters,  2, parameters,  "xx2-2 parameters");
1420
1421         for (i=0; i < ARRAY_SIZE(attribute_list); i++) {
1422 /*              TEST_PRINTERINFO_INT_EXP(2, attributes, 1, flags,
1423                         attribute_list[i],
1424                         (attribute_list[i] | default_attribute)
1425                         ); */
1426                 TEST_PRINTERINFO_INT_EXP(2, attributes, 2, attributes,
1427                         attribute_list[i],
1428                         (attribute_list[i] | default_attribute)
1429                         );
1430                 TEST_PRINTERINFO_INT_EXP(2, attributes, 4, attributes,
1431                         attribute_list[i],
1432                         (attribute_list[i] | default_attribute)
1433                         );
1434                 TEST_PRINTERINFO_INT_EXP(2, attributes, 5, attributes,
1435                         attribute_list[i],
1436                         (attribute_list[i] | default_attribute)
1437                         );
1438 /*              TEST_PRINTERINFO_INT_EXP(4, attributes, 1, flags,
1439                         attribute_list[i],
1440                         (attribute_list[i] | default_attribute)
1441                         ); */
1442                 TEST_PRINTERINFO_INT_EXP(4, attributes, 2, attributes,
1443                         attribute_list[i],
1444                         (attribute_list[i] | default_attribute)
1445                         );
1446                 TEST_PRINTERINFO_INT_EXP(4, attributes, 4, attributes,
1447                         attribute_list[i],
1448                         (attribute_list[i] | default_attribute)
1449                         );
1450                 TEST_PRINTERINFO_INT_EXP(4, attributes, 5, attributes,
1451                         attribute_list[i],
1452                         (attribute_list[i] | default_attribute)
1453                         );
1454 /*              TEST_PRINTERINFO_INT_EXP(5, attributes, 1, flags,
1455                         attribute_list[i],
1456                         (attribute_list[i] | default_attribute)
1457                         ); */
1458                 TEST_PRINTERINFO_INT_EXP(5, attributes, 2, attributes,
1459                         attribute_list[i],
1460                         (attribute_list[i] | default_attribute)
1461                         );
1462                 TEST_PRINTERINFO_INT_EXP(5, attributes, 4, attributes,
1463                         attribute_list[i],
1464                         (attribute_list[i] | default_attribute)
1465                         );
1466                 TEST_PRINTERINFO_INT_EXP(5, attributes, 5, attributes,
1467                         attribute_list[i],
1468                         (attribute_list[i] | default_attribute)
1469                         );
1470         }
1471
1472         for (i=0; i < ARRAY_SIZE(status_list); i++) {
1473                 /* level 2 sets do not stick
1474                 TEST_PRINTERINFO_INT(2, status, 0, status, status_list[i]);
1475                 TEST_PRINTERINFO_INT(2, status, 2, status, status_list[i]);
1476                 TEST_PRINTERINFO_INT(2, status, 6, status, status_list[i]); */
1477                 TEST_PRINTERINFO_INT(6, status, 0, status, status_list[i]);
1478                 TEST_PRINTERINFO_INT(6, status, 2, status, status_list[i]);
1479                 TEST_PRINTERINFO_INT(6, status, 6, status, status_list[i]);
1480         }
1481
1482         /* priorities need to be between 0 and 99
1483            passing an invalid priority will result in WERR_INVALID_PRIORITY */
1484         TEST_PRINTERINFO_INT(2, priority,       2, priority, 0);
1485         TEST_PRINTERINFO_INT(2, priority,       2, priority, 1);
1486         TEST_PRINTERINFO_INT(2, priority,       2, priority, 99);
1487         /* TEST_PRINTERINFO_INT(2, priority,    2, priority, 100); */
1488         TEST_PRINTERINFO_INT(2, defaultpriority,2, defaultpriority, 0);
1489         TEST_PRINTERINFO_INT(2, defaultpriority,2, defaultpriority, 1);
1490         TEST_PRINTERINFO_INT(2, defaultpriority,2, defaultpriority, 99);
1491         /* TEST_PRINTERINFO_INT(2, defaultpriority,2, defaultpriority, 100); */
1492
1493         TEST_PRINTERINFO_INT(2, starttime,      2, starttime, __LINE__);
1494         TEST_PRINTERINFO_INT(2, untiltime,      2, untiltime, __LINE__);
1495
1496         /* does not stick
1497         TEST_PRINTERINFO_INT(2, cjobs,          2, cjobs, __LINE__);
1498         TEST_PRINTERINFO_INT(2, averageppm,     2, averageppm, __LINE__); */
1499
1500         /* does not stick
1501         TEST_PRINTERINFO_INT(5, device_not_selected_timeout, 5, device_not_selected_timeout, __LINE__);
1502         TEST_PRINTERINFO_INT(5, transmission_retry_timeout, 5, transmission_retry_timeout, __LINE__); */
1503
1504         /* FIXME: gd also test devmode and secdesc behavior */
1505
1506         {
1507                 /* verify composition of level 1 description field */
1508                 const char *description;
1509                 const char *tmp;
1510
1511                 q0.in.level = 1;
1512                 do { TESTGETCALL(GetPrinter, q0) } while (0);
1513
1514                 description = talloc_strdup(tctx, q0.out.info->info1.description);
1515
1516                 q0.in.level = 2;
1517                 do { TESTGETCALL(GetPrinter, q0) } while (0);
1518
1519                 tmp = talloc_asprintf(tctx, "%s,%s,%s",
1520                         q0.out.info->info2.printername,
1521                         q0.out.info->info2.drivername,
1522                         q0.out.info->info2.location);
1523
1524                 do { STRING_EQUAL(description, tmp, "description")} while (0);
1525         }
1526
1527         return ret;
1528 }
1529
1530 #define torture_assert_sid_equal(torture_ctx,got,expected,cmt)\
1531         do { struct dom_sid *__got = (got), *__expected = (expected); \
1532         if (!dom_sid_equal(__got, __expected)) { \
1533                 torture_result(torture_ctx, TORTURE_FAIL, \
1534                                            __location__": "#got" was %s, expected %s: %s", \
1535                                            dom_sid_string(torture_ctx, __got), dom_sid_string(torture_ctx, __expected), cmt); \
1536                 return false; \
1537         } \
1538         } while(0)
1539
1540 static bool test_security_descriptor_equal(struct torture_context *tctx,
1541                                            const struct security_descriptor *sd1,
1542                                            const struct security_descriptor *sd2)
1543 {
1544         if (sd1 == sd2) {
1545                 return true;
1546         }
1547
1548         if (!sd1 || !sd2) {
1549                 torture_comment(tctx, "%s\n", __location__);
1550                 return false;
1551         }
1552
1553         torture_assert_int_equal(tctx, sd1->revision, sd2->revision, "revision mismatch");
1554         torture_assert_int_equal(tctx, sd1->type, sd2->type, "type mismatch");
1555
1556         torture_assert_sid_equal(tctx, sd1->owner_sid, sd2->owner_sid, "owner mismatch");
1557         torture_assert_sid_equal(tctx, sd1->group_sid, sd2->group_sid, "group mismatch");
1558
1559         if (!security_acl_equal(sd1->sacl, sd2->sacl)) {
1560                 torture_comment(tctx, "%s: sacl mismatch\n", __location__);
1561                 NDR_PRINT_DEBUG(security_acl, sd1->sacl);
1562                 NDR_PRINT_DEBUG(security_acl, sd2->sacl);
1563                 return false;
1564         }
1565         if (!security_acl_equal(sd1->dacl, sd2->dacl)) {
1566                 torture_comment(tctx, "%s: dacl mismatch\n", __location__);
1567                 NDR_PRINT_DEBUG(security_acl, sd1->dacl);
1568                 NDR_PRINT_DEBUG(security_acl, sd2->dacl);
1569                 return false;
1570         }
1571
1572         return true;
1573 }
1574
1575 static bool test_sd_set_level(struct torture_context *tctx,
1576                               struct dcerpc_pipe *p,
1577                               struct policy_handle *handle,
1578                               uint32_t level,
1579                               struct security_descriptor *sd)
1580 {
1581         struct spoolss_SetPrinterInfoCtr info_ctr;
1582         struct spoolss_DevmodeContainer devmode_ctr;
1583         struct sec_desc_buf secdesc_ctr;
1584
1585         ZERO_STRUCT(devmode_ctr);
1586         ZERO_STRUCT(secdesc_ctr);
1587
1588         switch (level) {
1589         case 2: {
1590                 union spoolss_PrinterInfo info;
1591                 struct spoolss_SetPrinterInfo2 info2;
1592                 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 2, &info), "");
1593
1594                 info2.servername        = info.info2.servername;
1595                 info2.printername       = info.info2.printername;
1596                 info2.sharename         = info.info2.sharename;
1597                 info2.portname          = info.info2.portname;
1598                 info2.drivername        = info.info2.drivername;
1599                 info2.comment           = info.info2.comment;
1600                 info2.location          = info.info2.location;
1601                 info2.devmode_ptr       = 0;
1602                 info2.sepfile           = info.info2.sepfile;
1603                 info2.printprocessor    = info.info2.printprocessor;
1604                 info2.datatype          = info.info2.datatype;
1605                 info2.parameters        = info.info2.parameters;
1606                 info2.secdesc_ptr       = 0;
1607                 info2.attributes        = info.info2.attributes;
1608                 info2.priority          = info.info2.priority;
1609                 info2.defaultpriority   = info.info2.defaultpriority;
1610                 info2.starttime         = info.info2.starttime;
1611                 info2.untiltime         = info.info2.untiltime;
1612                 info2.status            = info.info2.status;
1613                 info2.cjobs             = info.info2.cjobs;
1614                 info2.averageppm        = info.info2.averageppm;
1615
1616                 info_ctr.level = 2;
1617                 info_ctr.info.info2 = &info2;
1618
1619                 break;
1620         }
1621         case 3: {
1622                 struct spoolss_SetPrinterInfo3 info3;
1623
1624                 info3.sec_desc_ptr = 0;
1625
1626                 info_ctr.level = 3;
1627                 info_ctr.info.info3 = &info3;
1628
1629                 break;
1630         }
1631         default:
1632                 return false;
1633         }
1634
1635         secdesc_ctr.sd = sd;
1636
1637         torture_assert(tctx,
1638                 test_SetPrinter(tctx, p, handle, &info_ctr, &devmode_ctr, &secdesc_ctr, 0), "");
1639
1640         return true;
1641 }
1642
1643 static bool test_PrinterInfo_SDs(struct torture_context *tctx,
1644                                  struct dcerpc_pipe *p,
1645                                  struct policy_handle *handle)
1646 {
1647         union spoolss_PrinterInfo info;
1648         struct security_descriptor *sd1, *sd2;
1649         int i;
1650
1651         /* just compare level 2 and level 3 */
1652
1653         torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 2, &info), "");
1654
1655         sd1 = info.info2.secdesc;
1656
1657         torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 3, &info), "");
1658
1659         sd2 = info.info3.secdesc;
1660
1661         torture_assert(tctx, test_security_descriptor_equal(tctx, sd1, sd2), "");
1662
1663
1664         /* query level 2, set level 2, query level 2 */
1665
1666         torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 2, &info), "");
1667
1668         sd1 = info.info2.secdesc;
1669
1670         torture_assert(tctx, test_sd_set_level(tctx, p, handle, 2, sd1), "");
1671
1672         torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 2, &info), "");
1673
1674         sd2 = info.info2.secdesc;
1675         if (sd1->type & SEC_DESC_DACL_DEFAULTED) {
1676                 torture_comment(tctx, "removing SEC_DESC_DACL_DEFAULTED\n");
1677                 sd1->type &= ~SEC_DESC_DACL_DEFAULTED;
1678         }
1679
1680         torture_assert(tctx, test_security_descriptor_equal(tctx, sd1, sd2), "");
1681
1682
1683         /* query level 2, set level 3, query level 2 */
1684
1685         torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 2, &info), "");
1686
1687         sd1 = info.info2.secdesc;
1688
1689         torture_assert(tctx, test_sd_set_level(tctx, p, handle, 3, sd1), "");
1690
1691         torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 2, &info), "");
1692
1693         sd2 = info.info2.secdesc;
1694
1695         torture_assert(tctx, test_security_descriptor_equal(tctx, sd1, sd2), "");
1696
1697
1698         /* set modified sd level 3, query level 2 */
1699
1700         for (i=0; i < 93; i++) {
1701                 struct security_ace a;
1702                 const char *sid_string = talloc_asprintf(tctx, "S-1-5-32-9999%i", i);
1703                 a.type = SEC_ACE_TYPE_ACCESS_ALLOWED;
1704                 a.flags = 0;
1705                 a.size = 0; /* autogenerated */
1706                 a.access_mask = 0;
1707                 a.trustee = *dom_sid_parse_talloc(tctx, sid_string);
1708                 torture_assert_ntstatus_ok(tctx, security_descriptor_dacl_add(sd1, &a), "");
1709         }
1710
1711         torture_assert(tctx, test_sd_set_level(tctx, p, handle, 3, sd1), "");
1712
1713         torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 2, &info), "");
1714         sd2 = info.info2.secdesc;
1715
1716         if (sd1->type & SEC_DESC_DACL_DEFAULTED) {
1717                 torture_comment(tctx, "removing SEC_DESC_DACL_DEFAULTED\n");
1718                 sd1->type &= ~SEC_DESC_DACL_DEFAULTED;
1719         }
1720
1721         torture_assert(tctx, test_security_descriptor_equal(tctx, sd1, sd2), "");
1722
1723         return true;
1724 }
1725
1726 /*
1727  * wrapper call that saves original sd, runs tests, and restores sd
1728  */
1729
1730 static bool test_PrinterInfo_SD(struct torture_context *tctx,
1731                                 struct dcerpc_pipe *p,
1732                                 struct policy_handle *handle)
1733 {
1734         union spoolss_PrinterInfo info;
1735         struct spoolss_SetPrinterInfo3 info3;
1736         struct spoolss_SetPrinterInfoCtr info_ctr;
1737         struct spoolss_DevmodeContainer devmode_ctr;
1738         struct sec_desc_buf secdesc_ctr;
1739         struct security_descriptor *sd;
1740         bool ret = true;
1741
1742         /* save original sd */
1743
1744         torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 2, &info), "");
1745
1746         sd = security_descriptor_copy(tctx, info.info2.secdesc);
1747
1748         /* run tests */
1749
1750         ret = test_PrinterInfo_SDs(tctx, p, handle);
1751
1752         /* restore original sd */
1753
1754         ZERO_STRUCT(devmode_ctr);
1755         ZERO_STRUCT(secdesc_ctr);
1756
1757         info3.sec_desc_ptr = 0;
1758
1759         info_ctr.level = 3;
1760         info_ctr.info.info3 = &info3;
1761
1762         secdesc_ctr.sd = sd;
1763
1764         torture_assert(tctx,
1765                 test_SetPrinter(tctx, p, handle, &info_ctr, &devmode_ctr, &secdesc_ctr, 0), "");
1766
1767         return ret;
1768 }
1769
1770 static bool test_devmode_set_level(struct torture_context *tctx,
1771                                    struct dcerpc_pipe *p,
1772                                    struct policy_handle *handle,
1773                                    uint32_t level,
1774                                    struct spoolss_DeviceMode *devmode)
1775 {
1776         struct spoolss_SetPrinterInfoCtr info_ctr;
1777         struct spoolss_DevmodeContainer devmode_ctr;
1778         struct sec_desc_buf secdesc_ctr;
1779
1780         ZERO_STRUCT(devmode_ctr);
1781         ZERO_STRUCT(secdesc_ctr);
1782
1783         switch (level) {
1784         case 2: {
1785                 union spoolss_PrinterInfo info;
1786                 struct spoolss_SetPrinterInfo2 info2;
1787                 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 2, &info), "");
1788
1789                 info2.servername        = info.info2.servername;
1790                 info2.printername       = info.info2.printername;
1791                 info2.sharename         = info.info2.sharename;
1792                 info2.portname          = info.info2.portname;
1793                 info2.drivername        = info.info2.drivername;
1794                 info2.comment           = info.info2.comment;
1795                 info2.location          = info.info2.location;
1796                 info2.devmode_ptr       = 0;
1797                 info2.sepfile           = info.info2.sepfile;
1798                 info2.printprocessor    = info.info2.printprocessor;
1799                 info2.datatype          = info.info2.datatype;
1800                 info2.parameters        = info.info2.parameters;
1801                 info2.secdesc_ptr       = 0;
1802                 info2.attributes        = info.info2.attributes;
1803                 info2.priority          = info.info2.priority;
1804                 info2.defaultpriority   = info.info2.defaultpriority;
1805                 info2.starttime         = info.info2.starttime;
1806                 info2.untiltime         = info.info2.untiltime;
1807                 info2.status            = info.info2.status;
1808                 info2.cjobs             = info.info2.cjobs;
1809                 info2.averageppm        = info.info2.averageppm;
1810
1811                 info_ctr.level = 2;
1812                 info_ctr.info.info2 = &info2;
1813
1814                 break;
1815         }
1816         case 8: {
1817                 struct spoolss_SetPrinterInfo8 info8;
1818
1819                 info8.devmode_ptr = 0;
1820
1821                 info_ctr.level = 8;
1822                 info_ctr.info.info8 = &info8;
1823
1824                 break;
1825         }
1826         default:
1827                 return false;
1828         }
1829
1830         devmode_ctr.devmode = devmode;
1831
1832         torture_assert(tctx,
1833                 test_SetPrinter(tctx, p, handle, &info_ctr, &devmode_ctr, &secdesc_ctr, 0), "");
1834
1835         return true;
1836 }
1837
1838
1839 static bool test_devicemode_equal(struct torture_context *tctx,
1840                                   const struct spoolss_DeviceMode *d1,
1841                                   const struct spoolss_DeviceMode *d2)
1842 {
1843         if (d1 == d2) {
1844                 return true;
1845         }
1846
1847         if (!d1 || !d2) {
1848                 torture_comment(tctx, "%s\n", __location__);
1849                 return false;
1850         }
1851         torture_assert_str_equal(tctx, d1->devicename, d2->devicename, "devicename mismatch");
1852         torture_assert_int_equal(tctx, d1->specversion, d2->specversion, "specversion mismatch");
1853         torture_assert_int_equal(tctx, d1->driverversion, d2->driverversion, "driverversion mismatch");
1854         torture_assert_int_equal(tctx, d1->size, d2->size, "size mismatch");
1855         torture_assert_int_equal(tctx, d1->__driverextra_length, d2->__driverextra_length, "__driverextra_length mismatch");
1856         torture_assert_int_equal(tctx, d1->fields, d2->fields, "fields mismatch");
1857         torture_assert_int_equal(tctx, d1->orientation, d2->orientation, "orientation mismatch");
1858         torture_assert_int_equal(tctx, d1->papersize, d2->papersize, "papersize mismatch");
1859         torture_assert_int_equal(tctx, d1->paperlength, d2->paperlength, "paperlength mismatch");
1860         torture_assert_int_equal(tctx, d1->paperwidth, d2->paperwidth, "paperwidth mismatch");
1861         torture_assert_int_equal(tctx, d1->scale, d2->scale, "scale mismatch");
1862         torture_assert_int_equal(tctx, d1->copies, d2->copies, "copies mismatch");
1863         torture_assert_int_equal(tctx, d1->defaultsource, d2->defaultsource, "defaultsource mismatch");
1864         torture_assert_int_equal(tctx, d1->printquality, d2->printquality, "printquality mismatch");
1865         torture_assert_int_equal(tctx, d1->color, d2->color, "color mismatch");
1866         torture_assert_int_equal(tctx, d1->duplex, d2->duplex, "duplex mismatch");
1867         torture_assert_int_equal(tctx, d1->yresolution, d2->yresolution, "yresolution mismatch");
1868         torture_assert_int_equal(tctx, d1->ttoption, d2->ttoption, "ttoption mismatch");
1869         torture_assert_int_equal(tctx, d1->collate, d2->collate, "collate mismatch");
1870         torture_assert_str_equal(tctx, d1->formname, d2->formname, "formname mismatch");
1871         torture_assert_int_equal(tctx, d1->logpixels, d2->logpixels, "logpixels mismatch");
1872         torture_assert_int_equal(tctx, d1->bitsperpel, d2->bitsperpel, "bitsperpel mismatch");
1873         torture_assert_int_equal(tctx, d1->pelswidth, d2->pelswidth, "pelswidth mismatch");
1874         torture_assert_int_equal(tctx, d1->pelsheight, d2->pelsheight, "pelsheight mismatch");
1875         torture_assert_int_equal(tctx, d1->displayflags, d2->displayflags, "displayflags mismatch");
1876         torture_assert_int_equal(tctx, d1->displayfrequency, d2->displayfrequency, "displayfrequency mismatch");
1877         torture_assert_int_equal(tctx, d1->icmmethod, d2->icmmethod, "icmmethod mismatch");
1878         torture_assert_int_equal(tctx, d1->icmintent, d2->icmintent, "icmintent mismatch");
1879         torture_assert_int_equal(tctx, d1->mediatype, d2->mediatype, "mediatype mismatch");
1880         torture_assert_int_equal(tctx, d1->dithertype, d2->dithertype, "dithertype mismatch");
1881         torture_assert_int_equal(tctx, d1->reserved1, d2->reserved1, "reserved1 mismatch");
1882         torture_assert_int_equal(tctx, d1->reserved2, d2->reserved2, "reserved2 mismatch");
1883         torture_assert_int_equal(tctx, d1->panningwidth, d2->panningwidth, "panningwidth mismatch");
1884         torture_assert_int_equal(tctx, d1->panningheight, d2->panningheight, "panningheight mismatch");
1885         torture_assert_data_blob_equal(tctx, d1->driverextra_data, d2->driverextra_data, "driverextra_data mismatch");
1886
1887         return true;
1888 }
1889
1890 static bool call_OpenPrinterEx(struct torture_context *tctx,
1891                                struct dcerpc_pipe *p,
1892                                const char *name,
1893                                struct spoolss_DeviceMode *devmode,
1894                                struct policy_handle *handle);
1895
1896 static bool test_ClosePrinter(struct torture_context *tctx,
1897                               struct dcerpc_pipe *p,
1898                               struct policy_handle *handle);
1899
1900 static bool test_PrinterInfo_DevModes(struct torture_context *tctx,
1901                                       struct dcerpc_pipe *p,
1902                                       struct policy_handle *handle,
1903                                       const char *name)
1904 {
1905         union spoolss_PrinterInfo info;
1906         struct spoolss_DeviceMode *devmode;
1907         struct spoolss_DeviceMode *devmode2;
1908         struct policy_handle handle_devmode;
1909
1910         /* simply compare level8 and level2 devmode */
1911
1912         torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 8, &info), "");
1913
1914         devmode = info.info8.devmode;
1915
1916         torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 2, &info), "");
1917
1918         devmode2 = info.info2.devmode;
1919
1920         torture_assert(tctx, test_devicemode_equal(tctx, devmode, devmode2), "");
1921
1922
1923         /* change formname upon open and see if it persists in getprinter calls */
1924
1925         devmode->formname = talloc_strdup(tctx, "A4");
1926
1927         torture_assert(tctx, call_OpenPrinterEx(tctx, p, name, devmode, &handle_devmode),
1928                 "failed to open printer handle");
1929
1930         torture_assert(tctx, test_GetPrinter_level(tctx, p, &handle_devmode, 8, &info), "");
1931
1932         devmode2 = info.info8.devmode;
1933
1934         if (strequal(devmode->devicename, devmode2->devicename)) {
1935                 torture_fail(tctx, "devicename is the same");
1936         }
1937
1938         if (strequal(devmode->formname, devmode2->formname)) {
1939                 torture_fail(tctx, "formname is the same");
1940         }
1941
1942         torture_assert(tctx, test_GetPrinter_level(tctx, p, &handle_devmode, 2, &info), "");
1943
1944         devmode2 = info.info2.devmode;
1945
1946         if (strequal(devmode->devicename, devmode2->devicename)) {
1947                 torture_fail(tctx, "devicename is the same");
1948         }
1949
1950         if (strequal(devmode->formname, devmode2->formname)) {
1951                 torture_fail(tctx, "formname is the same");
1952         }
1953
1954         test_ClosePrinter(tctx, p, &handle_devmode);
1955
1956
1957         /* set devicemode level 8 and see if it persists */
1958
1959         devmode->copies = 93;
1960         devmode->formname = talloc_strdup(tctx, "Legal");
1961
1962         torture_assert(tctx, test_devmode_set_level(tctx, p, handle, 8, devmode), "");
1963
1964         torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 8, &info), "");
1965
1966         devmode2 = info.info8.devmode;
1967
1968         torture_assert(tctx, test_devicemode_equal(tctx, devmode, devmode2), "");
1969
1970         torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 2, &info), "");
1971
1972         devmode2 = info.info2.devmode;
1973
1974         torture_assert(tctx, test_devicemode_equal(tctx, devmode, devmode2), "");
1975
1976
1977         /* set devicemode level 2 and see if it persists */
1978
1979         devmode->copies = 39;
1980         devmode->formname = talloc_strdup(tctx, "Letter");
1981
1982         torture_assert(tctx, test_devmode_set_level(tctx, p, handle, 8, devmode), "");
1983
1984         torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 8, &info), "");
1985
1986         devmode2 = info.info8.devmode;
1987
1988         torture_assert(tctx, test_devicemode_equal(tctx, devmode, devmode2), "");
1989
1990         torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 2, &info), "");
1991
1992         devmode2 = info.info2.devmode;
1993
1994         torture_assert(tctx, test_devicemode_equal(tctx, devmode, devmode2), "");
1995
1996
1997         return true;
1998 }
1999
2000 /*
2001  * wrapper call that saves original devmode, runs tests, and restores devmode
2002  */
2003
2004 static bool test_PrinterInfo_DevMode(struct torture_context *tctx,
2005                                      struct dcerpc_pipe *p,
2006                                      struct policy_handle *handle,
2007                                      const char *name)
2008 {
2009         union spoolss_PrinterInfo info;
2010         struct spoolss_SetPrinterInfo8 info8;
2011         struct spoolss_SetPrinterInfoCtr info_ctr;
2012         struct spoolss_DevmodeContainer devmode_ctr;
2013         struct sec_desc_buf secdesc_ctr;
2014         struct spoolss_DeviceMode *devmode;
2015         bool ret = true;
2016
2017         /* save original devmode */
2018
2019         torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 8, &info), "");
2020
2021         devmode = info.info8.devmode;
2022
2023         /* run tests */
2024
2025         ret = test_PrinterInfo_DevModes(tctx, p, handle, name);
2026
2027         /* restore original devmode */
2028
2029         ZERO_STRUCT(devmode_ctr);
2030         ZERO_STRUCT(secdesc_ctr);
2031
2032         info8.devmode_ptr = 0;
2033
2034         info_ctr.level = 8;
2035         info_ctr.info.info8 = &info8;
2036
2037         devmode_ctr.devmode = devmode;
2038
2039         torture_assert(tctx,
2040                 test_SetPrinter(tctx, p, handle, &info_ctr, &devmode_ctr, &secdesc_ctr, 0), "");
2041
2042         return ret;
2043 }
2044
2045 static bool test_ClosePrinter(struct torture_context *tctx,
2046                               struct dcerpc_pipe *p,
2047                               struct policy_handle *handle)
2048 {
2049         NTSTATUS status;
2050         struct spoolss_ClosePrinter r;
2051
2052         r.in.handle = handle;
2053         r.out.handle = handle;
2054
2055         torture_comment(tctx, "Testing ClosePrinter\n");
2056
2057         status = dcerpc_spoolss_ClosePrinter(p, tctx, &r);
2058         torture_assert_ntstatus_ok(tctx, status, "ClosePrinter failed");
2059         torture_assert_werr_ok(tctx, r.out.result, "ClosePrinter failed");
2060
2061         return true;
2062 }
2063
2064 static bool test_GetForm(struct torture_context *tctx,
2065                          struct dcerpc_pipe *p,
2066                          struct policy_handle *handle,
2067                          const char *form_name,
2068                          uint32_t level)
2069 {
2070         NTSTATUS status;
2071         struct spoolss_GetForm r;
2072         uint32_t needed;
2073
2074         r.in.handle = handle;
2075         r.in.form_name = form_name;
2076         r.in.level = level;
2077         r.in.buffer = NULL;
2078         r.in.offered = 0;
2079         r.out.needed = &needed;
2080
2081         torture_comment(tctx, "Testing GetForm level %d\n", r.in.level);
2082
2083         status = dcerpc_spoolss_GetForm(p, tctx, &r);
2084         torture_assert_ntstatus_ok(tctx, status, "GetForm failed");
2085
2086         if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
2087                 DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed);
2088                 data_blob_clear(&blob);
2089                 r.in.buffer = &blob;
2090                 r.in.offered = needed;
2091                 status = dcerpc_spoolss_GetForm(p, tctx, &r);
2092                 torture_assert_ntstatus_ok(tctx, status, "GetForm failed");
2093
2094                 torture_assert_werr_ok(tctx, r.out.result, "GetForm failed");
2095
2096                 torture_assert(tctx, r.out.info, "No form info returned");
2097         }
2098
2099         torture_assert_werr_ok(tctx, r.out.result, "GetForm failed");
2100
2101         CHECK_NEEDED_SIZE_LEVEL(spoolss_FormInfo, r.out.info, r.in.level, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
2102
2103         return true;
2104 }
2105
2106 static bool test_EnumForms(struct torture_context *tctx,
2107                            struct dcerpc_pipe *p,
2108                            struct policy_handle *handle, bool print_server)
2109 {
2110         NTSTATUS status;
2111         struct spoolss_EnumForms r;
2112         bool ret = true;
2113         uint32_t needed;
2114         uint32_t count;
2115         uint32_t levels[] = { 1, 2 };
2116         int i;
2117
2118         for (i=0; i<ARRAY_SIZE(levels); i++) {
2119
2120                 union spoolss_FormInfo *info;
2121
2122                 r.in.handle = handle;
2123                 r.in.level = levels[i];
2124                 r.in.buffer = NULL;
2125                 r.in.offered = 0;
2126                 r.out.needed = &needed;
2127                 r.out.count = &count;
2128                 r.out.info = &info;
2129
2130                 torture_comment(tctx, "Testing EnumForms level %d\n", levels[i]);
2131
2132                 status = dcerpc_spoolss_EnumForms(p, tctx, &r);
2133                 torture_assert_ntstatus_ok(tctx, status, "EnumForms failed");
2134
2135                 if ((r.in.level == 2) && (W_ERROR_EQUAL(r.out.result, WERR_UNKNOWN_LEVEL))) {
2136                         break;
2137                 }
2138
2139                 if (print_server && W_ERROR_EQUAL(r.out.result, WERR_BADFID))
2140                         torture_fail(tctx, "EnumForms on the PrintServer isn't supported by test server (NT4)");
2141
2142                 if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
2143                         int j;
2144                         DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed);
2145                         data_blob_clear(&blob);
2146                         r.in.buffer = &blob;
2147                         r.in.offered = needed;
2148
2149                         status = dcerpc_spoolss_EnumForms(p, tctx, &r);
2150
2151                         torture_assert(tctx, info, "No forms returned");
2152
2153                         for (j = 0; j < count; j++) {
2154                                 if (!print_server)
2155                                         ret &= test_GetForm(tctx, p, handle, info[j].info1.form_name, levels[i]);
2156                         }
2157                 }
2158
2159                 torture_assert_ntstatus_ok(tctx, status, "EnumForms failed");
2160
2161                 torture_assert_werr_ok(tctx, r.out.result, "EnumForms failed");
2162
2163                 CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumForms, info, r.in.level, count, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
2164         }
2165
2166         return true;
2167 }
2168
2169 static bool test_DeleteForm(struct torture_context *tctx,
2170                             struct dcerpc_pipe *p,
2171                             struct policy_handle *handle,
2172                             const char *form_name)
2173 {
2174         NTSTATUS status;
2175         struct spoolss_DeleteForm r;
2176
2177         r.in.handle = handle;
2178         r.in.form_name = form_name;
2179
2180         status = dcerpc_spoolss_DeleteForm(p, tctx, &r);
2181
2182         torture_assert_ntstatus_ok(tctx, status, "DeleteForm failed");
2183
2184         torture_assert_werr_ok(tctx, r.out.result, "DeleteForm failed");
2185
2186         return true;
2187 }
2188
2189 static bool test_AddForm(struct torture_context *tctx,
2190                          struct dcerpc_pipe *p,
2191                          struct policy_handle *handle, bool print_server)
2192 {
2193         struct spoolss_AddForm r;
2194         struct spoolss_AddFormInfo1 addform;
2195         const char *form_name = "testform3";
2196         NTSTATUS status;
2197         bool ret = true;
2198
2199         r.in.handle     = handle;
2200         r.in.level      = 1;
2201         r.in.info.info1 = &addform;
2202         addform.flags           = SPOOLSS_FORM_USER;
2203         addform.form_name       = form_name;
2204         addform.size.width      = 50;
2205         addform.size.height     = 25;
2206         addform.area.left       = 5;
2207         addform.area.top        = 10;
2208         addform.area.right      = 45;
2209         addform.area.bottom     = 15;
2210
2211         status = dcerpc_spoolss_AddForm(p, tctx, &r);
2212
2213         torture_assert_ntstatus_ok(tctx, status, "AddForm failed");
2214
2215         torture_assert_werr_ok(tctx, r.out.result, "AddForm failed");
2216
2217         if (!print_server) ret &= test_GetForm(tctx, p, handle, form_name, 1);
2218
2219         {
2220                 struct spoolss_SetForm sf;
2221                 struct spoolss_AddFormInfo1 setform;
2222
2223                 sf.in.handle    = handle;
2224                 sf.in.form_name = form_name;
2225                 sf.in.level     = 1;
2226                 sf.in.info.info1= &setform;
2227                 setform.flags           = addform.flags;
2228                 setform.form_name       = addform.form_name;
2229                 setform.size            = addform.size;
2230                 setform.area            = addform.area;
2231
2232                 setform.size.width      = 1234;
2233
2234                 status = dcerpc_spoolss_SetForm(p, tctx, &sf);
2235
2236                 torture_assert_ntstatus_ok(tctx, status, "SetForm failed");
2237
2238                 torture_assert_werr_ok(tctx, r.out.result, "SetForm failed");
2239         }
2240
2241         if (!print_server) ret &= test_GetForm(tctx, p, handle, form_name, 1);
2242
2243         {
2244                 struct spoolss_EnumForms e;
2245                 union spoolss_FormInfo *info;
2246                 uint32_t needed;
2247                 uint32_t count;
2248                 bool found = false;
2249
2250                 e.in.handle = handle;
2251                 e.in.level = 1;
2252                 e.in.buffer = NULL;
2253                 e.in.offered = 0;
2254                 e.out.needed = &needed;
2255                 e.out.count = &count;
2256                 e.out.info = &info;
2257
2258                 torture_comment(tctx, "Testing EnumForms level 1\n");
2259
2260                 status = dcerpc_spoolss_EnumForms(p, tctx, &e);
2261                 torture_assert_ntstatus_ok(tctx, status, "EnumForms failed");
2262
2263                 if (print_server && W_ERROR_EQUAL(e.out.result, WERR_BADFID))
2264                         torture_fail(tctx, "EnumForms on the PrintServer isn't supported by test server (NT4)");
2265
2266                 if (W_ERROR_EQUAL(e.out.result, WERR_INSUFFICIENT_BUFFER)) {
2267                         int j;
2268                         DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed);
2269                         data_blob_clear(&blob);
2270                         e.in.buffer = &blob;
2271                         e.in.offered = needed;
2272
2273                         status = dcerpc_spoolss_EnumForms(p, tctx, &e);
2274
2275                         torture_assert(tctx, info, "No forms returned");
2276
2277                         for (j = 0; j < count; j++) {
2278                                 if (strequal(form_name, info[j].info1.form_name)) {
2279                                         found = true;
2280                                         break;
2281                                 }
2282                         }
2283                 }
2284                 torture_assert(tctx, found, "Newly added form not found in enum call");
2285         }
2286
2287         if (!test_DeleteForm(tctx, p, handle, form_name)) {
2288                 ret = false;
2289         }
2290
2291         return ret;
2292 }
2293
2294 static bool test_EnumPorts_old(struct torture_context *tctx,
2295                                struct dcerpc_pipe *p)
2296 {
2297         NTSTATUS status;
2298         struct spoolss_EnumPorts r;
2299         uint32_t needed;
2300         uint32_t count;
2301         union spoolss_PortInfo *info;
2302
2303         r.in.servername = talloc_asprintf(tctx, "\\\\%s",
2304                                           dcerpc_server_name(p));
2305         r.in.level = 2;
2306         r.in.buffer = NULL;
2307         r.in.offered = 0;
2308         r.out.needed = &needed;
2309         r.out.count = &count;
2310         r.out.info = &info;
2311
2312         torture_comment(tctx, "Testing EnumPorts\n");
2313
2314         status = dcerpc_spoolss_EnumPorts(p, tctx, &r);
2315
2316         torture_assert_ntstatus_ok(tctx, status, "EnumPorts failed");
2317
2318         if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
2319                 DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed);
2320                 data_blob_clear(&blob);
2321                 r.in.buffer = &blob;
2322                 r.in.offered = needed;
2323
2324                 status = dcerpc_spoolss_EnumPorts(p, tctx, &r);
2325                 torture_assert_ntstatus_ok(tctx, status, "EnumPorts failed");
2326                 torture_assert_werr_ok(tctx, r.out.result, "EnumPorts failed");
2327
2328                 torture_assert(tctx, info, "No ports returned");
2329         }
2330
2331         torture_assert_werr_ok(tctx, r.out.result, "EnumPorts failed");
2332
2333         CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumPorts, info, 2, count, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
2334
2335         return true;
2336 }
2337
2338 static bool test_AddPort(struct torture_context *tctx,
2339                          struct dcerpc_pipe *p)
2340 {
2341         NTSTATUS status;
2342         struct spoolss_AddPort r;
2343
2344         r.in.server_name = talloc_asprintf(tctx, "\\\\%s",
2345                                            dcerpc_server_name(p));
2346         r.in.unknown = 0;
2347         r.in.monitor_name = "foo";
2348
2349         torture_comment(tctx, "Testing AddPort\n");
2350
2351         status = dcerpc_spoolss_AddPort(p, tctx, &r);
2352
2353         torture_assert_ntstatus_ok(tctx, status, "AddPort failed");
2354
2355         /* win2k3 returns WERR_NOT_SUPPORTED */
2356
2357 #if 0
2358
2359         if (!W_ERROR_IS_OK(r.out.result)) {
2360                 printf("AddPort failed - %s\n", win_errstr(r.out.result));
2361                 return false;
2362         }
2363
2364 #endif
2365
2366         return true;
2367 }
2368
2369 static bool test_GetJob(struct torture_context *tctx,
2370                         struct dcerpc_pipe *p,
2371                         struct policy_handle *handle, uint32_t job_id)
2372 {
2373         NTSTATUS status;
2374         struct spoolss_GetJob r;
2375         union spoolss_JobInfo info;
2376         uint32_t needed;
2377         uint32_t levels[] = {1, 2 /* 3, 4 */};
2378         uint32_t i;
2379
2380         r.in.handle = handle;
2381         r.in.job_id = job_id;
2382         r.in.level = 0;
2383         r.in.buffer = NULL;
2384         r.in.offered = 0;
2385         r.out.needed = &needed;
2386         r.out.info = &info;
2387
2388         torture_comment(tctx, "Testing GetJob level %d\n", r.in.level);
2389
2390         status = dcerpc_spoolss_GetJob(p, tctx, &r);
2391         torture_assert_werr_equal(tctx, r.out.result, WERR_UNKNOWN_LEVEL, "Unexpected return code");
2392
2393         for (i = 0; i < ARRAY_SIZE(levels); i++) {
2394
2395                 torture_comment(tctx, "Testing GetJob level %d\n", r.in.level);
2396
2397                 needed = 0;
2398
2399                 r.in.level = levels[i];
2400                 r.in.offered = 0;
2401                 r.in.buffer = NULL;
2402
2403                 status = dcerpc_spoolss_GetJob(p, tctx, &r);
2404                 torture_assert_ntstatus_ok(tctx, status, "GetJob failed");
2405
2406                 if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
2407                         DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed);
2408                         data_blob_clear(&blob);
2409                         r.in.buffer = &blob;
2410                         r.in.offered = needed;
2411
2412                         status = dcerpc_spoolss_GetJob(p, tctx, &r);
2413                         torture_assert_ntstatus_ok(tctx, status, "GetJob failed");
2414
2415                 }
2416                 torture_assert(tctx, r.out.info, "No job info returned");
2417                 torture_assert_werr_ok(tctx, r.out.result, "GetJob failed");
2418
2419                 CHECK_NEEDED_SIZE_LEVEL(spoolss_JobInfo, r.out.info, r.in.level, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
2420         }
2421
2422         return true;
2423 }
2424
2425 static bool test_SetJob(struct torture_context *tctx,
2426                         struct dcerpc_pipe *p,
2427                         struct policy_handle *handle, uint32_t job_id,
2428                         enum spoolss_JobControl command)
2429 {
2430         NTSTATUS status;
2431         struct spoolss_SetJob r;
2432
2433         r.in.handle     = handle;
2434         r.in.job_id     = job_id;
2435         r.in.ctr        = NULL;
2436         r.in.command    = command;
2437
2438         switch (command) {
2439         case SPOOLSS_JOB_CONTROL_PAUSE:
2440                 torture_comment(tctx, "Testing SetJob: SPOOLSS_JOB_CONTROL_PAUSE\n");
2441                 break;
2442         case SPOOLSS_JOB_CONTROL_RESUME:
2443                 torture_comment(tctx, "Testing SetJob: SPOOLSS_JOB_CONTROL_RESUME\n");
2444                 break;
2445         case SPOOLSS_JOB_CONTROL_CANCEL:
2446                 torture_comment(tctx, "Testing SetJob: SPOOLSS_JOB_CONTROL_CANCEL\n");
2447                 break;
2448         case SPOOLSS_JOB_CONTROL_RESTART:
2449                 torture_comment(tctx, "Testing SetJob: SPOOLSS_JOB_CONTROL_RESTART\n");
2450                 break;
2451         case SPOOLSS_JOB_CONTROL_DELETE:
2452                 torture_comment(tctx, "Testing SetJob: SPOOLSS_JOB_CONTROL_DELETE\n");
2453                 break;
2454         case SPOOLSS_JOB_CONTROL_SEND_TO_PRINTER:
2455                 torture_comment(tctx, "Testing SetJob: SPOOLSS_JOB_CONTROL_SEND_TO_PRINTER\n");
2456                 break;
2457         case SPOOLSS_JOB_CONTROL_LAST_PAGE_EJECTED:
2458                 torture_comment(tctx, "Testing SetJob: SPOOLSS_JOB_CONTROL_LAST_PAGE_EJECTED\n");
2459                 break;
2460         case SPOOLSS_JOB_CONTROL_RETAIN:
2461                 torture_comment(tctx, "Testing SetJob: SPOOLSS_JOB_CONTROL_RETAIN\n");
2462                 break;
2463         case SPOOLSS_JOB_CONTROL_RELEASE:
2464                 torture_comment(tctx, "Testing SetJob: SPOOLSS_JOB_CONTROL_RELEASE\n");
2465                 break;
2466         default:
2467                 torture_comment(tctx, "Testing SetJob\n");
2468                 break;
2469         }
2470
2471         status = dcerpc_spoolss_SetJob(p, tctx, &r);
2472         torture_assert_ntstatus_ok(tctx, status, "SetJob failed");
2473         torture_assert_werr_ok(tctx, r.out.result, "SetJob failed");
2474
2475         return true;
2476 }
2477
2478 static bool test_AddJob(struct torture_context *tctx,
2479                         struct dcerpc_pipe *p,
2480                         struct policy_handle *handle)
2481 {
2482         NTSTATUS status;
2483         struct spoolss_AddJob r;
2484         uint32_t needed;
2485
2486         r.in.level = 0;
2487         r.in.handle = handle;
2488         r.in.offered = 0;
2489         r.out.needed = &needed;
2490         r.in.buffer = r.out.buffer = NULL;
2491
2492         torture_comment(tctx, "Testing AddJob\n");
2493
2494         status = dcerpc_spoolss_AddJob(p, tctx, &r);
2495         torture_assert_werr_equal(tctx, r.out.result, WERR_UNKNOWN_LEVEL, "AddJob failed");
2496
2497         r.in.level = 1;
2498
2499         status = dcerpc_spoolss_AddJob(p, tctx, &r);
2500         torture_assert_werr_equal(tctx, r.out.result, WERR_INVALID_PARAM, "AddJob failed");
2501
2502         return true;
2503 }
2504
2505
2506 static bool test_EnumJobs(struct torture_context *tctx,
2507                           struct dcerpc_pipe *p,
2508                           struct policy_handle *handle)
2509 {
2510         NTSTATUS status;
2511         struct spoolss_EnumJobs r;
2512         uint32_t needed;
2513         uint32_t count;
2514         union spoolss_JobInfo *info;
2515
2516         r.in.handle = handle;
2517         r.in.firstjob = 0;
2518         r.in.numjobs = 0xffffffff;
2519         r.in.level = 1;
2520         r.in.buffer = NULL;
2521         r.in.offered = 0;
2522         r.out.needed = &needed;
2523         r.out.count = &count;
2524         r.out.info = &info;
2525
2526         torture_comment(tctx, "Testing EnumJobs\n");
2527
2528         status = dcerpc_spoolss_EnumJobs(p, tctx, &r);
2529
2530         torture_assert_ntstatus_ok(tctx, status, "EnumJobs failed");
2531
2532         if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
2533                 int j;
2534                 DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed);
2535                 data_blob_clear(&blob);
2536                 r.in.buffer = &blob;
2537                 r.in.offered = needed;
2538
2539                 status = dcerpc_spoolss_EnumJobs(p, tctx, &r);
2540
2541                 torture_assert_ntstatus_ok(tctx, status, "EnumJobs failed");
2542                 torture_assert_werr_ok(tctx, r.out.result, "EnumJobs failed");
2543                 torture_assert(tctx, info, "No jobs returned");
2544
2545                 CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumJobs, *r.out.info, r.in.level, count, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
2546
2547                 for (j = 0; j < count; j++) {
2548
2549                         torture_assert(tctx, test_GetJob(tctx, p, handle, info[j].info1.job_id),
2550                                 "failed to call test_GetJob");
2551
2552                         /* FIXME - gd */
2553                         if (!torture_setting_bool(tctx, "samba3", false)) {
2554                                 test_SetJob(tctx, p, handle, info[j].info1.job_id, SPOOLSS_JOB_CONTROL_PAUSE);
2555                                 test_SetJob(tctx, p, handle, info[j].info1.job_id, SPOOLSS_JOB_CONTROL_RESUME);
2556                         }
2557                 }
2558
2559         } else {
2560                 torture_assert_werr_ok(tctx, r.out.result, "EnumJobs failed");
2561         }
2562
2563         return true;
2564 }
2565
2566 static bool test_DoPrintTest(struct torture_context *tctx,
2567                              struct dcerpc_pipe *p,
2568                              struct policy_handle *handle)
2569 {
2570         bool ret = true;
2571         NTSTATUS status;
2572         struct spoolss_StartDocPrinter s;
2573         struct spoolss_DocumentInfo1 info1;
2574         struct spoolss_StartPagePrinter sp;
2575         struct spoolss_WritePrinter w;
2576         struct spoolss_EndPagePrinter ep;
2577         struct spoolss_EndDocPrinter e;
2578         int i;
2579         uint32_t job_id;
2580         uint32_t num_written;
2581
2582         torture_comment(tctx, "Testing StartDocPrinter\n");
2583
2584         s.in.handle             = handle;
2585         s.in.level              = 1;
2586         s.in.info.info1         = &info1;
2587         s.out.job_id            = &job_id;
2588         info1.document_name     = "TorturePrintJob";
2589         info1.output_file       = NULL;
2590         info1.datatype          = "RAW";
2591
2592         status = dcerpc_spoolss_StartDocPrinter(p, tctx, &s);
2593         torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_StartDocPrinter failed");
2594         torture_assert_werr_ok(tctx, s.out.result, "StartDocPrinter failed");
2595
2596         for (i=1; i < 4; i++) {
2597                 torture_comment(tctx, "Testing StartPagePrinter: Page[%d]\n", i);
2598
2599                 sp.in.handle            = handle;
2600
2601                 status = dcerpc_spoolss_StartPagePrinter(p, tctx, &sp);
2602                 torture_assert_ntstatus_ok(tctx, status,
2603                                            "dcerpc_spoolss_StartPagePrinter failed");
2604                 torture_assert_werr_ok(tctx, sp.out.result, "StartPagePrinter failed");
2605
2606                 torture_comment(tctx, "Testing WritePrinter: Page[%d]\n", i);
2607
2608                 w.in.handle             = handle;
2609                 w.in.data               = data_blob_string_const(talloc_asprintf(tctx,"TortureTestPage: %d\nData\n",i));
2610                 w.out.num_written       = &num_written;
2611
2612                 status = dcerpc_spoolss_WritePrinter(p, tctx, &w);
2613                 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_WritePrinter failed");
2614                 torture_assert_werr_ok(tctx, w.out.result, "WritePrinter failed");
2615
2616                 torture_comment(tctx, "Testing EndPagePrinter: Page[%d]\n", i);
2617
2618                 ep.in.handle            = handle;
2619
2620                 status = dcerpc_spoolss_EndPagePrinter(p, tctx, &ep);
2621                 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EndPagePrinter failed");
2622                 torture_assert_werr_ok(tctx, ep.out.result, "EndPagePrinter failed");
2623         }
2624
2625         torture_comment(tctx, "Testing EndDocPrinter\n");
2626
2627         e.in.handle = handle;
2628
2629         status = dcerpc_spoolss_EndDocPrinter(p, tctx, &e);
2630         torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EndDocPrinter failed");
2631         torture_assert_werr_ok(tctx, e.out.result, "EndDocPrinter failed");
2632
2633         ret &= test_AddJob(tctx, p, handle);
2634         ret &= test_EnumJobs(tctx, p, handle);
2635
2636         ret &= test_SetJob(tctx, p, handle, job_id, SPOOLSS_JOB_CONTROL_DELETE);
2637
2638         return ret;
2639 }
2640
2641 static bool test_PausePrinter(struct torture_context *tctx,
2642                               struct dcerpc_pipe *p,
2643                               struct policy_handle *handle)
2644 {
2645         NTSTATUS status;
2646         struct spoolss_SetPrinter r;
2647         struct spoolss_SetPrinterInfoCtr info_ctr;
2648         struct spoolss_DevmodeContainer devmode_ctr;
2649         struct sec_desc_buf secdesc_ctr;
2650
2651         info_ctr.level = 0;
2652         info_ctr.info.info0 = NULL;
2653
2654         ZERO_STRUCT(devmode_ctr);
2655         ZERO_STRUCT(secdesc_ctr);
2656
2657         r.in.handle             = handle;
2658         r.in.info_ctr           = &info_ctr;
2659         r.in.devmode_ctr        = &devmode_ctr;
2660         r.in.secdesc_ctr        = &secdesc_ctr;
2661         r.in.command            = SPOOLSS_PRINTER_CONTROL_PAUSE;
2662
2663         torture_comment(tctx, "Testing SetPrinter: SPOOLSS_PRINTER_CONTROL_PAUSE\n");
2664
2665         status = dcerpc_spoolss_SetPrinter(p, tctx, &r);
2666
2667         torture_assert_ntstatus_ok(tctx, status, "SetPrinter failed");
2668
2669         torture_assert_werr_ok(tctx, r.out.result, "SetPrinter failed");
2670
2671         return true;
2672 }
2673
2674 static bool test_ResumePrinter(struct torture_context *tctx,
2675                                struct dcerpc_pipe *p,
2676                                struct policy_handle *handle)
2677 {
2678         NTSTATUS status;
2679         struct spoolss_SetPrinter r;
2680         struct spoolss_SetPrinterInfoCtr info_ctr;
2681         struct spoolss_DevmodeContainer devmode_ctr;
2682         struct sec_desc_buf secdesc_ctr;
2683
2684         info_ctr.level = 0;
2685         info_ctr.info.info0 = NULL;
2686
2687         ZERO_STRUCT(devmode_ctr);
2688         ZERO_STRUCT(secdesc_ctr);
2689
2690         r.in.handle             = handle;
2691         r.in.info_ctr           = &info_ctr;
2692         r.in.devmode_ctr        = &devmode_ctr;
2693         r.in.secdesc_ctr        = &secdesc_ctr;
2694         r.in.command            = SPOOLSS_PRINTER_CONTROL_RESUME;
2695
2696         torture_comment(tctx, "Testing SetPrinter: SPOOLSS_PRINTER_CONTROL_RESUME\n");
2697
2698         status = dcerpc_spoolss_SetPrinter(p, tctx, &r);
2699
2700         torture_assert_ntstatus_ok(tctx, status, "SetPrinter failed");
2701
2702         torture_assert_werr_ok(tctx, r.out.result, "SetPrinter failed");
2703
2704         return true;
2705 }
2706
2707 static bool test_GetPrinterData(struct torture_context *tctx,
2708                                 struct dcerpc_pipe *p,
2709                                 struct policy_handle *handle,
2710                                 const char *value_name,
2711                                 enum winreg_Type *type_p,
2712                                 union spoolss_PrinterData *data_p)
2713 {
2714         NTSTATUS status;
2715         struct spoolss_GetPrinterData r;
2716         uint32_t needed;
2717         enum winreg_Type type;
2718         union spoolss_PrinterData data;
2719
2720         r.in.handle = handle;
2721         r.in.value_name = value_name;
2722         r.in.offered = 0;
2723         r.out.needed = &needed;
2724         r.out.type = &type;
2725         r.out.data = &data;
2726
2727         torture_comment(tctx, "Testing GetPrinterData(%s)\n", r.in.value_name);
2728
2729         status = dcerpc_spoolss_GetPrinterData(p, tctx, &r);
2730         torture_assert_ntstatus_ok(tctx, status, "GetPrinterData failed");
2731
2732         if (W_ERROR_EQUAL(r.out.result, WERR_MORE_DATA)) {
2733                 r.in.offered = needed;
2734
2735                 status = dcerpc_spoolss_GetPrinterData(p, tctx, &r);
2736                 torture_assert_ntstatus_ok(tctx, status, "GetPrinterData failed");
2737         }
2738
2739         torture_assert_werr_ok(tctx, r.out.result,
2740                 talloc_asprintf(tctx, "GetPrinterData(%s) failed", r.in.value_name));
2741
2742         CHECK_NEEDED_SIZE_LEVEL(spoolss_PrinterData, &data, type, lp_iconv_convenience(tctx->lp_ctx), needed, 1);
2743
2744         if (type_p) {
2745                 *type_p = type;
2746         }
2747
2748         if (data_p) {
2749                 *data_p = data;
2750         }
2751
2752         return true;
2753 }
2754
2755 static bool test_GetPrinterDataEx(struct torture_context *tctx,
2756                                   struct dcerpc_pipe *p,
2757                                   struct policy_handle *handle,
2758                                   const char *key_name,
2759                                   const char *value_name,
2760                                   enum winreg_Type *type_p,
2761                                   union spoolss_PrinterData *data_p)
2762 {
2763         NTSTATUS status;
2764         struct spoolss_GetPrinterDataEx r;
2765         enum winreg_Type type;
2766         uint32_t needed;
2767         union spoolss_PrinterData data;
2768
2769         r.in.handle = handle;
2770         r.in.key_name = key_name;
2771         r.in.value_name = value_name;
2772         r.in.offered = 0;
2773         r.out.type = &type;
2774         r.out.needed = &needed;
2775         r.out.data = &data;
2776
2777         torture_comment(tctx, "Testing GetPrinterDataEx(%s - %s)\n",
2778                 r.in.key_name, r.in.value_name);
2779
2780         status = dcerpc_spoolss_GetPrinterDataEx(p, tctx, &r);
2781         if (!NT_STATUS_IS_OK(status)) {
2782                 if (NT_STATUS_EQUAL(status,NT_STATUS_NET_WRITE_FAULT) &&
2783                     p->last_fault_code == DCERPC_FAULT_OP_RNG_ERROR) {
2784                         torture_skip(tctx, "GetPrinterDataEx not supported by server\n");
2785                 }
2786                 torture_assert_ntstatus_ok(tctx, status, "GetPrinterDataEx failed");
2787         }
2788
2789         if (W_ERROR_EQUAL(r.out.result, WERR_MORE_DATA)) {
2790                 r.in.offered = needed;
2791                 status = dcerpc_spoolss_GetPrinterDataEx(p, tctx, &r);
2792                 torture_assert_ntstatus_ok(tctx, status, "GetPrinterDataEx failed");
2793         }
2794
2795         torture_assert_werr_ok(tctx, r.out.result,
2796                 talloc_asprintf(tctx, "GetPrinterDataEx(%s - %s) failed", r.in.key_name, r.in.value_name));
2797
2798         CHECK_NEEDED_SIZE_LEVEL(spoolss_PrinterData, &data, type, lp_iconv_convenience(tctx->lp_ctx), needed, 1);
2799
2800         if (type_p) {
2801                 *type_p = type;
2802         }
2803
2804         if (data_p) {
2805                 *data_p = data;
2806         }
2807
2808         return true;
2809 }
2810
2811 static bool test_GetPrinterData_list(struct torture_context *tctx,
2812                                      struct dcerpc_pipe *p,
2813                                      struct policy_handle *handle)
2814 {
2815         const char *list[] = {
2816                 "W3SvcInstalled",
2817                 "BeepEnabled",
2818                 "EventLog",
2819                 /* "NetPopup", not on w2k8 */
2820                 /* "NetPopupToComputer", not on w2k8 */
2821                 "MajorVersion",
2822                 "MinorVersion",
2823                 "DefaultSpoolDirectory",
2824                 "Architecture",
2825                 "DsPresent",
2826                 "OSVersion",
2827                 /* "OSVersionEx", not on s3 */
2828                 "DNSMachineName"
2829         };
2830         int i;
2831
2832         for (i=0; i < ARRAY_SIZE(list); i++) {
2833                 enum winreg_Type type, type_ex;
2834                 union spoolss_PrinterData data, data_ex;
2835
2836                 torture_assert(tctx, test_GetPrinterData(tctx, p, handle, list[i], &type, &data),
2837                         talloc_asprintf(tctx, "GetPrinterData failed on %s\n", list[i]));
2838                 torture_assert(tctx, test_GetPrinterDataEx(tctx, p, handle, "random_string", list[i], &type_ex, &data_ex),
2839                         talloc_asprintf(tctx, "GetPrinterDataEx failed on %s\n", list[i]));
2840                 torture_assert_int_equal(tctx, type, type_ex, "type mismatch");
2841                 switch (type) {
2842                 case REG_SZ:
2843                         torture_assert_str_equal(tctx, data.string, data_ex.string, "REG_SZ mismatch");
2844                         break;
2845                 case REG_DWORD:
2846                         torture_assert_int_equal(tctx, data.value, data_ex.value, "REG_DWORD mismatch");
2847                         break;
2848                 case REG_BINARY:
2849                         torture_assert_data_blob_equal(tctx, data.binary, data_ex.binary, "REG_BINARY mismatch");
2850                         break;
2851                 default:
2852                         break;
2853                 }
2854         }
2855
2856         return true;
2857 }
2858
2859 static bool test_EnumPrinterData(struct torture_context *tctx, struct dcerpc_pipe *p,
2860                                  struct policy_handle *handle)
2861 {
2862         NTSTATUS status;
2863         struct spoolss_EnumPrinterData r;
2864
2865         ZERO_STRUCT(r);
2866         r.in.handle = handle;
2867         r.in.enum_index = 0;
2868
2869         do {
2870                 uint32_t value_size = 0;
2871                 uint32_t data_size = 0;
2872                 enum winreg_Type type = 0;
2873
2874                 r.in.value_offered = value_size;
2875                 r.out.value_needed = &value_size;
2876                 r.in.data_offered = data_size;
2877                 r.out.data_needed = &data_size;
2878
2879                 r.out.type = &type;
2880                 r.out.data = talloc_zero_array(tctx, uint8_t, 0);
2881
2882                 torture_comment(tctx, "Testing EnumPrinterData\n");
2883
2884                 status = dcerpc_spoolss_EnumPrinterData(p, tctx, &r);
2885
2886                 torture_assert_ntstatus_ok(tctx, status, "EnumPrinterData failed");
2887                 if (W_ERROR_EQUAL(r.out.result, WERR_NO_MORE_ITEMS)) {
2888                         break;
2889                 }
2890                 torture_assert_werr_ok(tctx, r.out.result, "EnumPrinterData");
2891
2892                 r.in.value_offered = value_size;
2893                 r.out.value_name = talloc_zero_array(tctx, const char, value_size);
2894                 r.in.data_offered = data_size;
2895                 r.out.data = talloc_zero_array(tctx, uint8_t, data_size);
2896
2897                 status = dcerpc_spoolss_EnumPrinterData(p, tctx, &r);
2898
2899                 torture_assert_ntstatus_ok(tctx, status, "EnumPrinterData failed");
2900                 if (W_ERROR_EQUAL(r.out.result, WERR_NO_MORE_ITEMS)) {
2901                         break;
2902                 }
2903
2904                 torture_assert_werr_ok(tctx, r.out.result, "EnumPrinterData failed");
2905
2906                 torture_assert(tctx, test_GetPrinterData(tctx, p, handle, r.out.value_name, NULL, NULL),
2907                         talloc_asprintf(tctx, "failed to call GetPrinterData for %s\n", r.out.value_name));
2908
2909                 torture_assert(tctx, test_GetPrinterDataEx(tctx, p, handle, "PrinterDriverData", r.out.value_name, NULL, NULL),
2910                         talloc_asprintf(tctx, "failed to call GetPrinterDataEx on PrinterDriverData for %s\n", r.out.value_name));
2911
2912                 r.in.enum_index++;
2913
2914         } while (W_ERROR_IS_OK(r.out.result));
2915
2916         return true;
2917 }
2918
2919 static bool test_EnumPrinterDataEx(struct torture_context *tctx,
2920                                    struct dcerpc_pipe *p,
2921                                    struct policy_handle *handle,
2922                                    const char *key_name)
2923 {
2924         struct spoolss_EnumPrinterDataEx r;
2925         struct spoolss_PrinterEnumValues *info;
2926         uint32_t needed;
2927         uint32_t count;
2928
2929         r.in.handle = handle;
2930         r.in.key_name = key_name;
2931         r.in.offered = 0;
2932         r.out.needed = &needed;
2933         r.out.count = &count;
2934         r.out.info = &info;
2935
2936         torture_comment(tctx, "Testing EnumPrinterDataEx(%s)\n", key_name);
2937
2938         torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_EnumPrinterDataEx(p, tctx, &r),
2939                 "EnumPrinterDataEx failed");
2940         if (W_ERROR_EQUAL(r.out.result, WERR_MORE_DATA)) {
2941                 r.in.offered = needed;
2942                 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_EnumPrinterDataEx(p, tctx, &r),
2943                         "EnumPrinterDataEx failed");
2944         }
2945
2946         torture_assert_werr_ok(tctx, r.out.result, "EnumPrinterDataEx failed");
2947
2948         CHECK_NEEDED_SIZE_ENUM(spoolss_EnumPrinterDataEx, info, count, lp_iconv_convenience(tctx->lp_ctx), needed, 1);
2949
2950         return true;
2951 }
2952
2953
2954 static bool test_DeletePrinterData(struct torture_context *tctx,
2955                                    struct dcerpc_pipe *p,
2956                                    struct policy_handle *handle,
2957                                    const char *value_name)
2958 {
2959         NTSTATUS status;
2960         struct spoolss_DeletePrinterData r;
2961
2962         r.in.handle = handle;
2963         r.in.value_name = value_name;
2964
2965         torture_comment(tctx, "Testing DeletePrinterData(%s)\n",
2966                 r.in.value_name);
2967
2968         status = dcerpc_spoolss_DeletePrinterData(p, tctx, &r);
2969
2970         torture_assert_ntstatus_ok(tctx, status, "DeletePrinterData failed");
2971         torture_assert_werr_ok(tctx, r.out.result, "DeletePrinterData failed");
2972
2973         return true;
2974 }
2975
2976 static bool test_DeletePrinterDataEx(struct torture_context *tctx,
2977                                      struct dcerpc_pipe *p,
2978                                      struct policy_handle *handle,
2979                                      const char *key_name,
2980                                      const char *value_name)
2981 {
2982         struct spoolss_DeletePrinterDataEx r;
2983
2984         r.in.handle = handle;
2985         r.in.key_name = key_name;
2986         r.in.value_name = value_name;
2987
2988         torture_comment(tctx, "Testing DeletePrinterDataEx(%s - %s)\n",
2989                 r.in.key_name, r.in.value_name);
2990
2991         torture_assert_ntstatus_ok(tctx,
2992                 dcerpc_spoolss_DeletePrinterDataEx(p, tctx, &r),
2993                 "DeletePrinterDataEx failed");
2994         torture_assert_werr_ok(tctx, r.out.result,
2995                 "DeletePrinterDataEx failed");
2996
2997         return true;
2998 }
2999
3000 static bool test_DeletePrinterKey(struct torture_context *tctx,
3001                                   struct dcerpc_pipe *p,
3002                                   struct policy_handle *handle,
3003                                   const char *key_name)
3004 {
3005         struct spoolss_DeletePrinterKey r;
3006
3007         r.in.handle = handle;
3008         r.in.key_name = key_name;
3009
3010         torture_comment(tctx, "Testing DeletePrinterKey(%s)\n", r.in.key_name);
3011
3012         if (strequal(key_name, "") && !torture_setting_bool(tctx, "dangerous", false)) {
3013                 torture_skip(tctx, "not wiping out printer registry - enable dangerous tests to use\n");
3014                 return true;
3015         }
3016
3017         torture_assert_ntstatus_ok(tctx,
3018                 dcerpc_spoolss_DeletePrinterKey(p, tctx, &r),
3019                 "DeletePrinterKey failed");
3020         torture_assert_werr_ok(tctx, r.out.result,
3021                 "DeletePrinterKey failed");
3022
3023         return true;
3024 }
3025
3026 static bool test_SetPrinterData(struct torture_context *tctx,
3027                                 struct dcerpc_pipe *p,
3028                                 struct policy_handle *handle)
3029 {
3030         NTSTATUS status;
3031         struct spoolss_SetPrinterData r;
3032         const char *values[] = {
3033                 "spootyfoot",
3034                 "spooty\\foot",
3035 #if 0
3036         /* FIXME: not working with s3 atm. */
3037                 "spooty,foot",
3038                 "spooty,fo,ot",
3039 #endif
3040                 "spooty foot",
3041 #if 0
3042         /* FIXME: not working with s3 atm. */
3043                 "spooty\\fo,ot",
3044                 "spooty,fo\\ot"
3045 #endif
3046         };
3047         int i;
3048
3049         for (i=0; i < ARRAY_SIZE(values); i++) {
3050
3051                 enum winreg_Type type;
3052                 union spoolss_PrinterData data;
3053
3054                 r.in.handle = handle;
3055                 r.in.value_name = values[i];
3056                 r.in.type = REG_SZ;
3057                 r.in.data.string = "dog";
3058
3059                 torture_comment(tctx, "Testing SetPrinterData(%s)\n",
3060                         r.in.value_name);
3061
3062                 status = dcerpc_spoolss_SetPrinterData(p, tctx, &r);
3063
3064                 torture_assert_ntstatus_ok(tctx, status, "SetPrinterData failed");
3065                 torture_assert_werr_ok(tctx, r.out.result, "SetPrinterData failed");
3066
3067                 if (!test_GetPrinterData(tctx, p, handle, r.in.value_name, &type, &data)) {
3068                         return false;
3069                 }
3070
3071                 torture_assert_int_equal(tctx, r.in.type, type, "type mismatch");
3072                 torture_assert_str_equal(tctx, r.in.data.string, data.string, "data mismatch");
3073
3074                 if (!test_DeletePrinterData(tctx, p, handle, r.in.value_name)) {
3075                         return false;
3076                 }
3077         }
3078
3079         return true;
3080 }
3081
3082 static bool test_EnumPrinterKey(struct torture_context *tctx,
3083                                 struct dcerpc_pipe *p,
3084                                 struct policy_handle *handle,
3085                                 const char *key_name,
3086                                 const char ***array);
3087
3088 static bool test_SetPrinterDataEx(struct torture_context *tctx,
3089                                   struct dcerpc_pipe *p,
3090                                   struct policy_handle *handle)
3091 {
3092         NTSTATUS status;
3093         struct spoolss_SetPrinterDataEx r;
3094         const char *value_name = "dog";
3095         const char *keys[] = {
3096                 "torturedataex",
3097                 "torture data ex",
3098 #if 0
3099         /* FIXME: not working with s3 atm. */
3100                 "torturedataex_with_subkey\\subkey",
3101                 "torturedataex_with_subkey\\subkey:0",
3102                 "torturedataex_with_subkey\\subkey:1",
3103                 "torturedataex_with_subkey\\subkey\\subsubkey",
3104                 "torturedataex_with_subkey\\subkey\\subsubkey:0",
3105                 "torturedataex_with_subkey\\subkey\\subsubkey:1",
3106 #endif
3107                 "torture,data",
3108 #if 0
3109         /* FIXME: not working with s3 atm. */
3110
3111                 "torture,data,ex",
3112                 "torture,data\\ex",
3113                 "torture\\data,ex"
3114 #endif
3115         };
3116         int i;
3117         DATA_BLOB blob = data_blob_string_const("catfoobar");
3118
3119
3120         for (i=0; i < ARRAY_SIZE(keys); i++) {
3121
3122                 char *c;
3123                 const char *key;
3124                 enum winreg_Type type;
3125                 const char **subkeys;
3126                 union spoolss_PrinterData data;
3127
3128                 r.in.handle = handle;
3129                 r.in.key_name = keys[i];
3130                 r.in.value_name = value_name;
3131                 r.in.type = REG_BINARY;
3132                 r.in.data.binary = blob;
3133
3134                 torture_comment(tctx, "Testing SetPrinterDataEx(%s - %s)\n", r.in.key_name, value_name);
3135
3136                 status = dcerpc_spoolss_SetPrinterDataEx(p, tctx, &r);
3137
3138                 torture_assert_ntstatus_ok(tctx, status, "SetPrinterDataEx failed");
3139                 torture_assert_werr_ok(tctx, r.out.result, "SetPrinterDataEx failed");
3140
3141                 key = talloc_strdup(tctx, r.in.key_name);
3142
3143                 if (!test_GetPrinterDataEx(tctx, p, handle, r.in.key_name, value_name, &type, &data)) {
3144                         return false;
3145                 }
3146
3147                 torture_assert_int_equal(tctx, r.in.type, type, "type mismatch");
3148                 torture_assert_data_blob_equal(tctx, blob, data.binary, "data mismatch");
3149
3150                 if (!test_EnumPrinterDataEx(tctx, p, handle, r.in.key_name)) {
3151                         return false;
3152                 }
3153
3154                 if (!test_DeletePrinterDataEx(tctx, p, handle, r.in.key_name, value_name)) {
3155                         return false;
3156                 }
3157
3158                 c = strchr(key, '\\');
3159                 if (c) {
3160                         int i;
3161
3162                         /* we have subkeys */
3163
3164                         *c = 0;
3165
3166                         if (!test_EnumPrinterKey(tctx, p, handle, key, &subkeys)) {
3167                                 return false;
3168                         }
3169
3170                         for (i=0; subkeys && subkeys[i]; i++) {
3171
3172                                 const char *current_key = talloc_asprintf(tctx, "%s\\%s", key, subkeys[i]);
3173
3174                                 if (!test_DeletePrinterKey(tctx, p, handle, current_key)) {
3175                                         return false;
3176                                 }
3177                         }
3178
3179                         if (!test_DeletePrinterKey(tctx, p, handle, key)) {
3180                                 return false;
3181                         }
3182
3183                 } else {
3184                         if (!test_DeletePrinterKey(tctx, p, handle, key)) {
3185                                 return false;
3186                         }
3187                 }
3188         }
3189
3190         return true;
3191 }
3192
3193 static bool test_GetChangeID_PrinterData(struct torture_context *tctx,
3194                                          struct dcerpc_pipe *p,
3195                                          struct policy_handle *handle,
3196                                          uint32_t *change_id)
3197 {
3198         enum winreg_Type type;
3199         union spoolss_PrinterData data;
3200
3201         torture_assert(tctx,
3202                 test_GetPrinterData(tctx, p, handle, "ChangeID", &type, &data),
3203                 "failed to call GetPrinterData");
3204
3205         torture_assert(tctx, type == REG_DWORD, "unexpected type");
3206
3207         *change_id = data.value;
3208
3209         return true;
3210 }
3211
3212 static bool test_GetChangeID_PrinterDataEx(struct torture_context *tctx,
3213                                            struct dcerpc_pipe *p,
3214                                            struct policy_handle *handle,
3215                                            uint32_t *change_id)
3216 {
3217         enum winreg_Type type;
3218         union spoolss_PrinterData data;
3219
3220         torture_assert(tctx,
3221                 test_GetPrinterDataEx(tctx, p, handle, "PrinterDriverData", "ChangeID", &type, &data),
3222                 "failed to call GetPrinterData");
3223
3224         torture_assert(tctx, type == REG_DWORD, "unexpected type");
3225
3226         *change_id = data.value;
3227
3228         return true;
3229 }
3230
3231 static bool test_GetChangeID_PrinterInfo(struct torture_context *tctx,
3232                                          struct dcerpc_pipe *p,
3233                                          struct policy_handle *handle,
3234                                          uint32_t *change_id)
3235 {
3236         union spoolss_PrinterInfo info;
3237
3238         torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 0, &info),
3239                 "failed to query Printer level 0");
3240
3241         *change_id = info.info0.change_id;
3242
3243         return true;
3244 }
3245
3246 static bool test_ChangeID(struct torture_context *tctx,
3247                           struct dcerpc_pipe *p,
3248                           struct policy_handle *handle)
3249 {
3250         uint32_t change_id, change_id_ex, change_id_info;
3251         uint32_t change_id2, change_id_ex2, change_id_info2;
3252         union spoolss_PrinterInfo info;
3253         const char *comment;
3254
3255
3256         torture_comment(tctx, "Testing ChangeID: id change test #1\n");
3257
3258         torture_assert(tctx, test_GetChangeID_PrinterData(tctx, p, handle, &change_id),
3259                 "failed to query for ChangeID");
3260         torture_assert(tctx, test_GetChangeID_PrinterDataEx(tctx, p, handle, &change_id_ex),
3261                 "failed to query for ChangeID");
3262         torture_assert(tctx, test_GetChangeID_PrinterInfo(tctx, p, handle, &change_id_info),
3263                 "failed to query for ChangeID");
3264
3265         torture_assert_int_equal(tctx, change_id, change_id_ex,
3266                 "change_ids should all be equal");
3267         torture_assert_int_equal(tctx, change_id_ex, change_id_info,
3268                 "change_ids should all be equal");
3269
3270
3271         torture_comment(tctx, "Testing ChangeID: id change test #2\n");
3272
3273         torture_assert(tctx, test_GetChangeID_PrinterData(tctx, p, handle, &change_id),
3274                 "failed to query for ChangeID");
3275         torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 2, &info),
3276                 "failed to query Printer level 2");
3277         torture_assert(tctx, test_GetChangeID_PrinterDataEx(tctx, p, handle, &change_id_ex),
3278                 "failed to query for ChangeID");
3279         torture_assert(tctx, test_GetChangeID_PrinterInfo(tctx, p, handle, &change_id_info),
3280                 "failed to query for ChangeID");
3281         torture_assert_int_equal(tctx, change_id, change_id_ex,
3282                 "change_id should not have changed");
3283         torture_assert_int_equal(tctx, change_id_ex, change_id_info,
3284                 "change_id should not have changed");
3285
3286
3287         torture_comment(tctx, "Testing ChangeID: id change test #3\n");
3288
3289         torture_assert(tctx, test_GetChangeID_PrinterData(tctx, p, handle, &change_id),
3290                 "failed to query for ChangeID");
3291         torture_assert(tctx, test_GetChangeID_PrinterDataEx(tctx, p, handle, &change_id_ex),
3292                 "failed to query for ChangeID");
3293         torture_assert(tctx, test_GetChangeID_PrinterInfo(tctx, p, handle, &change_id_info),
3294                 "failed to query for ChangeID");
3295         torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 2, &info),
3296                 "failed to query Printer level 2");
3297         comment = talloc_strdup(tctx, info.info2.comment);
3298
3299         {
3300                 struct spoolss_SetPrinterInfoCtr info_ctr;
3301                 struct spoolss_DevmodeContainer devmode_ctr;
3302                 struct sec_desc_buf secdesc_ctr;
3303                 struct spoolss_SetPrinterInfo2 info2;
3304
3305                 ZERO_STRUCT(info_ctr);
3306                 ZERO_STRUCT(devmode_ctr);
3307                 ZERO_STRUCT(secdesc_ctr);
3308
3309                 info2.servername        = info.info2.servername;
3310                 info2.printername       = info.info2.printername;
3311                 info2.sharename         = info.info2.sharename;
3312                 info2.portname          = info.info2.portname;
3313                 info2.drivername        = info.info2.drivername;
3314                 info2.comment           = "torture_comment";
3315                 info2.location          = info.info2.location;
3316                 info2.devmode_ptr       = 0;
3317                 info2.sepfile           = info.info2.sepfile;
3318                 info2.printprocessor    = info.info2.printprocessor;
3319                 info2.datatype          = info.info2.datatype;
3320                 info2.parameters        = info.info2.parameters;
3321                 info2.secdesc_ptr       = 0;
3322                 info2.attributes        = info.info2.attributes;
3323                 info2.priority          = info.info2.priority;
3324                 info2.defaultpriority   = info.info2.defaultpriority;
3325                 info2.starttime         = info.info2.starttime;
3326                 info2.untiltime         = info.info2.untiltime;
3327                 info2.status            = info.info2.status;
3328                 info2.cjobs             = info.info2.cjobs;
3329                 info2.averageppm        = info.info2.averageppm;
3330
3331                 info_ctr.level = 2;
3332                 info_ctr.info.info2 = &info2;
3333
3334                 torture_assert(tctx, test_SetPrinter(tctx, p, handle, &info_ctr, &devmode_ctr, &secdesc_ctr, 0),
3335                         "failed to call SetPrinter");
3336
3337                 info2.comment           = comment;
3338
3339                 torture_assert(tctx, test_SetPrinter(tctx, p, handle, &info_ctr, &devmode_ctr, &secdesc_ctr, 0),
3340                         "failed to call SetPrinter");
3341
3342         }
3343
3344         torture_assert(tctx, test_GetChangeID_PrinterData(tctx, p, handle, &change_id2),
3345                 "failed to query for ChangeID");
3346         torture_assert(tctx, test_GetChangeID_PrinterDataEx(tctx, p, handle, &change_id_ex2),
3347                 "failed to query for ChangeID");
3348         torture_assert(tctx, test_GetChangeID_PrinterInfo(tctx, p, handle, &change_id_info2),
3349                 "failed to query for ChangeID");
3350
3351         torture_assert_int_equal(tctx, change_id2, change_id_ex2,
3352                 "change_ids should all be equal");
3353         torture_assert_int_equal(tctx, change_id_ex2, change_id_info2,
3354                 "change_ids should all be equal");
3355
3356         torture_assert(tctx, (change_id < change_id2),
3357                 talloc_asprintf(tctx, "change_id %d needs to be larger than change_id %d",
3358                 change_id2, change_id));
3359         torture_assert(tctx, (change_id_ex < change_id_ex2),
3360                 talloc_asprintf(tctx, "change_id %d needs to be larger than change_id %d",
3361                 change_id_ex2, change_id_ex));
3362         torture_assert(tctx, (change_id_info < change_id_info2),
3363                 talloc_asprintf(tctx, "change_id %d needs to be larger than change_id %d",
3364                 change_id_info2, change_id_info));
3365
3366         return true;
3367 }
3368
3369 static bool test_SecondaryClosePrinter(struct torture_context *tctx,
3370                                        struct dcerpc_pipe *p,
3371                                        struct policy_handle *handle)
3372 {
3373         NTSTATUS status;
3374         struct dcerpc_binding *b;
3375         struct dcerpc_pipe *p2;
3376         struct spoolss_ClosePrinter cp;
3377
3378         /* only makes sense on SMB */
3379         if (p->conn->transport.transport != NCACN_NP) {
3380                 return true;
3381         }
3382
3383         torture_comment(tctx, "testing close on secondary pipe\n");
3384
3385         status = dcerpc_parse_binding(tctx, p->conn->binding_string, &b);
3386         torture_assert_ntstatus_ok(tctx, status, "Failed to parse dcerpc binding");
3387
3388         status = dcerpc_secondary_connection(p, &p2, b);
3389         torture_assert_ntstatus_ok(tctx, status, "Failed to create secondary connection");
3390
3391         status = dcerpc_bind_auth_none(p2, &ndr_table_spoolss);
3392         torture_assert_ntstatus_ok(tctx, status, "Failed to create bind on secondary connection");
3393
3394         cp.in.handle = handle;
3395         cp.out.handle = handle;
3396
3397         status = dcerpc_spoolss_ClosePrinter(p2, tctx, &cp);
3398         torture_assert_ntstatus_equal(tctx, status, NT_STATUS_NET_WRITE_FAULT,
3399                         "ERROR: Allowed close on secondary connection");
3400
3401         torture_assert_int_equal(tctx, p2->last_fault_code, DCERPC_FAULT_CONTEXT_MISMATCH,
3402                                  "Unexpected fault code");
3403
3404         talloc_free(p2);
3405
3406         return true;
3407 }
3408
3409 static bool test_OpenPrinter_badname(struct torture_context *tctx,
3410                                      struct dcerpc_pipe *p, const char *name)
3411 {
3412         NTSTATUS status;
3413         struct spoolss_OpenPrinter op;
3414         struct spoolss_OpenPrinterEx opEx;
3415         struct policy_handle handle;
3416         bool ret = true;
3417
3418         op.in.printername       = name;
3419         op.in.datatype          = NULL;
3420         op.in.devmode_ctr.devmode= NULL;
3421         op.in.access_mask       = 0;
3422         op.out.handle           = &handle;
3423
3424         torture_comment(tctx, "\nTesting OpenPrinter(%s) with bad name\n", op.in.printername);
3425
3426         status = dcerpc_spoolss_OpenPrinter(p, tctx, &op);
3427         torture_assert_ntstatus_ok(tctx, status, "OpenPrinter failed");
3428         if (!W_ERROR_EQUAL(WERR_INVALID_PRINTER_NAME,op.out.result)) {
3429                 torture_comment(tctx, "OpenPrinter(%s) unexpected result[%s] should be WERR_INVALID_PRINTER_NAME\n",
3430                         name, win_errstr(op.out.result));
3431         }
3432
3433         if (W_ERROR_IS_OK(op.out.result)) {
3434                 ret &=test_ClosePrinter(tctx, p, &handle);
3435         }
3436
3437         opEx.in.printername             = name;
3438         opEx.in.datatype                = NULL;
3439         opEx.in.devmode_ctr.devmode     = NULL;
3440         opEx.in.access_mask             = 0;
3441         opEx.in.level                   = 1;
3442         opEx.in.userlevel.level1        = NULL;
3443         opEx.out.handle                 = &handle;
3444
3445         torture_comment(tctx, "Testing OpenPrinterEx(%s) with bad name\n", opEx.in.printername);
3446
3447         status = dcerpc_spoolss_OpenPrinterEx(p, tctx, &opEx);
3448         torture_assert_ntstatus_ok(tctx, status, "OpenPrinterEx failed");
3449         if (!W_ERROR_EQUAL(WERR_INVALID_PARAM,opEx.out.result)) {
3450                 torture_comment(tctx, "OpenPrinterEx(%s) unexpected result[%s] should be WERR_INVALID_PARAM\n",
3451                         name, win_errstr(opEx.out.result));
3452         }
3453
3454         if (W_ERROR_IS_OK(opEx.out.result)) {
3455                 ret &=test_ClosePrinter(tctx, p, &handle);
3456         }
3457
3458         return ret;
3459 }
3460
3461 static bool test_OpenPrinter(struct torture_context *tctx,
3462                              struct dcerpc_pipe *p,
3463                              const char *name)
3464 {
3465         NTSTATUS status;
3466         struct spoolss_OpenPrinter r;
3467         struct policy_handle handle;
3468         bool ret = true;
3469
3470         r.in.printername        = talloc_asprintf(tctx, "\\\\%s\\%s", dcerpc_server_name(p), name);
3471         r.in.datatype           = NULL;
3472         r.in.devmode_ctr.devmode= NULL;
3473         r.in.access_mask        = SEC_FLAG_MAXIMUM_ALLOWED;
3474         r.out.handle            = &handle;
3475
3476         torture_comment(tctx, "Testing OpenPrinter(%s)\n", r.in.printername);
3477
3478         status = dcerpc_spoolss_OpenPrinter(p, tctx, &r);
3479
3480         torture_assert_ntstatus_ok(tctx, status, "OpenPrinter failed");
3481
3482         torture_assert_werr_ok(tctx, r.out.result, "OpenPrinter failed");
3483
3484         if (!test_GetPrinter(tctx, p, &handle)) {
3485                 ret = false;
3486         }
3487
3488         if (!torture_setting_bool(tctx, "samba3", false)) {
3489                 if (!test_SecondaryClosePrinter(tctx, p, &handle)) {
3490                         ret = false;
3491                 }
3492         }
3493
3494         if (!test_ClosePrinter(tctx, p, &handle)) {
3495                 ret = false;
3496         }
3497
3498         return ret;
3499 }
3500
3501 static bool call_OpenPrinterEx(struct torture_context *tctx,
3502                                struct dcerpc_pipe *p,
3503                                const char *name,
3504                                struct spoolss_DeviceMode *devmode,
3505                                struct policy_handle *handle)
3506 {
3507         struct spoolss_OpenPrinterEx r;
3508         struct spoolss_UserLevel1 userlevel1;
3509         NTSTATUS status;
3510
3511         if (name && name[0]) {
3512                 r.in.printername = talloc_asprintf(tctx, "\\\\%s\\%s",
3513                                                    dcerpc_server_name(p), name);
3514         } else {
3515                 r.in.printername = talloc_asprintf(tctx, "\\\\%s",
3516                                                    dcerpc_server_name(p));
3517         }
3518
3519         r.in.datatype           = NULL;
3520         r.in.devmode_ctr.devmode= devmode;
3521         r.in.access_mask        = SEC_FLAG_MAXIMUM_ALLOWED;
3522         r.in.level              = 1;
3523         r.in.userlevel.level1   = &userlevel1;
3524         r.out.handle = handle;
3525
3526         userlevel1.size = 1234;
3527         userlevel1.client = "hello";
3528         userlevel1.user = "spottyfoot!";
3529         userlevel1.build = 1;
3530         userlevel1.major = 2;
3531         userlevel1.minor = 3;
3532         userlevel1.processor = 4;
3533
3534         torture_comment(tctx, "Testing OpenPrinterEx(%s)\n", r.in.printername);
3535
3536         status = dcerpc_spoolss_OpenPrinterEx(p, tctx, &r);
3537
3538         torture_assert_ntstatus_ok(tctx, status, "OpenPrinterEx failed");
3539
3540         torture_assert_werr_ok(tctx, r.out.result, "OpenPrinterEx failed");
3541
3542         return true;
3543 }
3544
3545 static bool test_OpenPrinterEx(struct torture_context *tctx,
3546                                struct dcerpc_pipe *p,
3547                                const char *name)
3548 {
3549         struct policy_handle handle;
3550         bool ret = true;
3551
3552         if (!call_OpenPrinterEx(tctx, p, name, NULL, &handle)) {
3553              &nbs