s4-smbtorture: more work on SD tests for RPC-SPOOLSS.
[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
1676         torture_assert(tctx, test_security_descriptor_equal(tctx, sd1, sd2), "");
1677
1678
1679         /* query level 2, set level 3, query level 2 */
1680
1681         torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 2, &info), "");
1682
1683         sd1 = info.info2.secdesc;
1684
1685         torture_assert(tctx, test_sd_set_level(tctx, p, handle, 3, sd1), "");
1686
1687         torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 2, &info), "");
1688
1689         sd2 = info.info2.secdesc;
1690
1691         torture_assert(tctx, test_security_descriptor_equal(tctx, sd1, sd2), "");
1692
1693
1694         /* set modified sd level 3, query level 2 */
1695
1696         for (i=0; i < 93; i++) {
1697                 struct security_ace a;
1698                 const char *sid_string = talloc_asprintf(tctx, "S-1-5-32-9999%i", i);
1699                 a.type = SEC_ACE_TYPE_ACCESS_ALLOWED;
1700                 a.flags = 0;
1701                 a.size = 0; /* autogenerated */
1702                 a.access_mask = 0;
1703                 a.trustee = *dom_sid_parse_talloc(tctx, sid_string);
1704                 torture_assert_ntstatus_ok(tctx, security_descriptor_dacl_add(sd1, &a), "");
1705         }
1706
1707         torture_assert(tctx, test_sd_set_level(tctx, p, handle, 3, sd1), "");
1708
1709         torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 2, &info), "");
1710         sd2 = info.info2.secdesc;
1711
1712         if (sd1->type & SEC_DESC_DACL_DEFAULTED) {
1713                 torture_comment(tctx, "removing SEC_DESC_DACL_DEFAULTED\n");
1714                 sd1->type &= ~SEC_DESC_DACL_DEFAULTED;
1715         }
1716
1717         torture_assert(tctx, test_security_descriptor_equal(tctx, sd1, sd2), "");
1718
1719         return true;
1720 }
1721
1722 /*
1723  * wrapper call that saves original sd, runs tests, and restores sd
1724  */
1725
1726 static bool test_PrinterInfo_SD(struct torture_context *tctx,
1727                                 struct dcerpc_pipe *p,
1728                                 struct policy_handle *handle)
1729 {
1730         union spoolss_PrinterInfo info;
1731         struct spoolss_SetPrinterInfo3 info3;
1732         struct spoolss_SetPrinterInfoCtr info_ctr;
1733         struct spoolss_DevmodeContainer devmode_ctr;
1734         struct sec_desc_buf secdesc_ctr;
1735         struct security_descriptor *sd;
1736         bool ret = true;
1737
1738         /* save original sd */
1739
1740         torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 2, &info), "");
1741
1742         sd = security_descriptor_copy(tctx, info.info2.secdesc);
1743
1744         /* run tests */
1745
1746         ret = test_PrinterInfo_SDs(tctx, p, handle);
1747
1748         /* restore original sd */
1749
1750         ZERO_STRUCT(devmode_ctr);
1751         ZERO_STRUCT(secdesc_ctr);
1752
1753         info3.sec_desc_ptr = 0;
1754
1755         info_ctr.level = 3;
1756         info_ctr.info.info3 = &info3;
1757
1758         secdesc_ctr.sd = sd;
1759
1760         torture_assert(tctx,
1761                 test_SetPrinter(tctx, p, handle, &info_ctr, &devmode_ctr, &secdesc_ctr, 0), "");
1762
1763         return ret;
1764 }
1765
1766 static bool test_devicemode_equal(struct torture_context *tctx,
1767                                   const struct spoolss_DeviceMode *d1,
1768                                   const struct spoolss_DeviceMode *d2)
1769 {
1770         if (d1 == d2) {
1771                 return true;
1772         }
1773
1774         if (!d1 || !d2) {
1775                 torture_comment(tctx, "%s\n", __location__);
1776                 return false;
1777         }
1778         torture_assert_str_equal(tctx, d1->devicename, d2->devicename, "devicename mismatch");
1779         torture_assert_int_equal(tctx, d1->specversion, d2->specversion, "specversion mismatch");
1780         torture_assert_int_equal(tctx, d1->driverversion, d2->driverversion, "driverversion mismatch");
1781         torture_assert_int_equal(tctx, d1->size, d2->size, "size mismatch");
1782         torture_assert_int_equal(tctx, d1->__driverextra_length, d2->__driverextra_length, "__driverextra_length mismatch");
1783         torture_assert_int_equal(tctx, d1->fields, d2->fields, "fields mismatch");
1784         torture_assert_int_equal(tctx, d1->orientation, d2->orientation, "orientation mismatch");
1785         torture_assert_int_equal(tctx, d1->papersize, d2->papersize, "papersize mismatch");
1786         torture_assert_int_equal(tctx, d1->paperlength, d2->paperlength, "paperlength mismatch");
1787         torture_assert_int_equal(tctx, d1->paperwidth, d2->paperwidth, "paperwidth mismatch");
1788         torture_assert_int_equal(tctx, d1->scale, d2->scale, "scale mismatch");
1789         torture_assert_int_equal(tctx, d1->copies, d2->copies, "copies mismatch");
1790         torture_assert_int_equal(tctx, d1->defaultsource, d2->defaultsource, "defaultsource mismatch");
1791         torture_assert_int_equal(tctx, d1->printquality, d2->printquality, "printquality mismatch");
1792         torture_assert_int_equal(tctx, d1->color, d2->color, "color mismatch");
1793         torture_assert_int_equal(tctx, d1->duplex, d2->duplex, "duplex mismatch");
1794         torture_assert_int_equal(tctx, d1->yresolution, d2->yresolution, "yresolution mismatch");
1795         torture_assert_int_equal(tctx, d1->ttoption, d2->ttoption, "ttoption mismatch");
1796         torture_assert_int_equal(tctx, d1->collate, d2->collate, "collate mismatch");
1797         torture_assert_str_equal(tctx, d1->formname, d2->formname, "formname mismatch");
1798         torture_assert_int_equal(tctx, d1->logpixels, d2->logpixels, "logpixels mismatch");
1799         torture_assert_int_equal(tctx, d1->bitsperpel, d2->bitsperpel, "bitsperpel mismatch");
1800         torture_assert_int_equal(tctx, d1->pelswidth, d2->pelswidth, "pelswidth mismatch");
1801         torture_assert_int_equal(tctx, d1->pelsheight, d2->pelsheight, "pelsheight mismatch");
1802         torture_assert_int_equal(tctx, d1->displayflags, d2->displayflags, "displayflags mismatch");
1803         torture_assert_int_equal(tctx, d1->displayfrequency, d2->displayfrequency, "displayfrequency mismatch");
1804         torture_assert_int_equal(tctx, d1->icmmethod, d2->icmmethod, "icmmethod mismatch");
1805         torture_assert_int_equal(tctx, d1->icmintent, d2->icmintent, "icmintent mismatch");
1806         torture_assert_int_equal(tctx, d1->mediatype, d2->mediatype, "mediatype mismatch");
1807         torture_assert_int_equal(tctx, d1->dithertype, d2->dithertype, "dithertype mismatch");
1808         torture_assert_int_equal(tctx, d1->reserved1, d2->reserved1, "reserved1 mismatch");
1809         torture_assert_int_equal(tctx, d1->reserved2, d2->reserved2, "reserved2 mismatch");
1810         torture_assert_int_equal(tctx, d1->panningwidth, d2->panningwidth, "panningwidth mismatch");
1811         torture_assert_int_equal(tctx, d1->panningheight, d2->panningheight, "panningheight mismatch");
1812         torture_assert_data_blob_equal(tctx, d1->driverextra_data, d2->driverextra_data, "driverextra_data mismatch");
1813
1814         return true;
1815 }
1816
1817 static bool test_PrinterInfo_DevModes(struct torture_context *tctx,
1818                                       struct dcerpc_pipe *p,
1819                                       struct policy_handle *handle)
1820 {
1821         union spoolss_PrinterInfo info;
1822         struct spoolss_DeviceMode *devmode;
1823         struct spoolss_DeviceMode *devmode2;
1824
1825         torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 8, &info), "");
1826
1827         devmode = info.info8.devmode;
1828
1829         torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 2, &info), "");
1830
1831         devmode2 = info.info2.devmode;
1832
1833         torture_assert(tctx, test_devicemode_equal(tctx, devmode, devmode2), "");
1834
1835         return true;
1836 }
1837
1838 /*
1839  * wrapper call that saves original devmode, runs tests, and restores devmode
1840  */
1841
1842 static bool test_PrinterInfo_DevMode(struct torture_context *tctx,
1843                                      struct dcerpc_pipe *p,
1844                                      struct policy_handle *handle)
1845 {
1846         union spoolss_PrinterInfo info;
1847         struct spoolss_SetPrinterInfo8 info8;
1848         struct spoolss_SetPrinterInfoCtr info_ctr;
1849         struct spoolss_DevmodeContainer devmode_ctr;
1850         struct sec_desc_buf secdesc_ctr;
1851         struct spoolss_DeviceMode *devmode;
1852         bool ret = true;
1853
1854         /* save original devmode */
1855
1856         torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 8, &info), "");
1857
1858         devmode = info.info8.devmode;
1859
1860         /* run tests */
1861
1862         ret = test_PrinterInfo_DevModes(tctx, p, handle);
1863
1864         /* restore original devmode */
1865
1866         ZERO_STRUCT(devmode_ctr);
1867         ZERO_STRUCT(secdesc_ctr);
1868
1869         info8.devmode_ptr = 0;
1870
1871         info_ctr.level = 8;
1872         info_ctr.info.info8 = &info8;
1873
1874         devmode_ctr.devmode = devmode;
1875
1876         torture_assert(tctx,
1877                 test_SetPrinter(tctx, p, handle, &info_ctr, &devmode_ctr, &secdesc_ctr, 0), "");
1878
1879         return ret;
1880 }
1881
1882 static bool test_ClosePrinter(struct torture_context *tctx,
1883                               struct dcerpc_pipe *p,
1884                               struct policy_handle *handle)
1885 {
1886         NTSTATUS status;
1887         struct spoolss_ClosePrinter r;
1888
1889         r.in.handle = handle;
1890         r.out.handle = handle;
1891
1892         torture_comment(tctx, "Testing ClosePrinter\n");
1893
1894         status = dcerpc_spoolss_ClosePrinter(p, tctx, &r);
1895         torture_assert_ntstatus_ok(tctx, status, "ClosePrinter failed");
1896         torture_assert_werr_ok(tctx, r.out.result, "ClosePrinter failed");
1897
1898         return true;
1899 }
1900
1901 static bool test_GetForm(struct torture_context *tctx,
1902                          struct dcerpc_pipe *p,
1903                          struct policy_handle *handle,
1904                          const char *form_name,
1905                          uint32_t level)
1906 {
1907         NTSTATUS status;
1908         struct spoolss_GetForm r;
1909         uint32_t needed;
1910
1911         r.in.handle = handle;
1912         r.in.form_name = form_name;
1913         r.in.level = level;
1914         r.in.buffer = NULL;
1915         r.in.offered = 0;
1916         r.out.needed = &needed;
1917
1918         torture_comment(tctx, "Testing GetForm level %d\n", r.in.level);
1919
1920         status = dcerpc_spoolss_GetForm(p, tctx, &r);
1921         torture_assert_ntstatus_ok(tctx, status, "GetForm failed");
1922
1923         if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
1924                 DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed);
1925                 data_blob_clear(&blob);
1926                 r.in.buffer = &blob;
1927                 r.in.offered = needed;
1928                 status = dcerpc_spoolss_GetForm(p, tctx, &r);
1929                 torture_assert_ntstatus_ok(tctx, status, "GetForm failed");
1930
1931                 torture_assert_werr_ok(tctx, r.out.result, "GetForm failed");
1932
1933                 torture_assert(tctx, r.out.info, "No form info returned");
1934         }
1935
1936         torture_assert_werr_ok(tctx, r.out.result, "GetForm failed");
1937
1938         CHECK_NEEDED_SIZE_LEVEL(spoolss_FormInfo, r.out.info, r.in.level, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
1939
1940         return true;
1941 }
1942
1943 static bool test_EnumForms(struct torture_context *tctx,
1944                            struct dcerpc_pipe *p,
1945                            struct policy_handle *handle, bool print_server)
1946 {
1947         NTSTATUS status;
1948         struct spoolss_EnumForms r;
1949         bool ret = true;
1950         uint32_t needed;
1951         uint32_t count;
1952         uint32_t levels[] = { 1, 2 };
1953         int i;
1954
1955         for (i=0; i<ARRAY_SIZE(levels); i++) {
1956
1957                 union spoolss_FormInfo *info;
1958
1959                 r.in.handle = handle;
1960                 r.in.level = levels[i];
1961                 r.in.buffer = NULL;
1962                 r.in.offered = 0;
1963                 r.out.needed = &needed;
1964                 r.out.count = &count;
1965                 r.out.info = &info;
1966
1967                 torture_comment(tctx, "Testing EnumForms level %d\n", levels[i]);
1968
1969                 status = dcerpc_spoolss_EnumForms(p, tctx, &r);
1970                 torture_assert_ntstatus_ok(tctx, status, "EnumForms failed");
1971
1972                 if ((r.in.level == 2) && (W_ERROR_EQUAL(r.out.result, WERR_UNKNOWN_LEVEL))) {
1973                         break;
1974                 }
1975
1976                 if (print_server && W_ERROR_EQUAL(r.out.result, WERR_BADFID))
1977                         torture_fail(tctx, "EnumForms on the PrintServer isn't supported by test server (NT4)");
1978
1979                 if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
1980                         int j;
1981                         DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed);
1982                         data_blob_clear(&blob);
1983                         r.in.buffer = &blob;
1984                         r.in.offered = needed;
1985
1986                         status = dcerpc_spoolss_EnumForms(p, tctx, &r);
1987
1988                         torture_assert(tctx, info, "No forms returned");
1989
1990                         for (j = 0; j < count; j++) {
1991                                 if (!print_server)
1992                                         ret &= test_GetForm(tctx, p, handle, info[j].info1.form_name, levels[i]);
1993                         }
1994                 }
1995
1996                 torture_assert_ntstatus_ok(tctx, status, "EnumForms failed");
1997
1998                 torture_assert_werr_ok(tctx, r.out.result, "EnumForms failed");
1999
2000                 CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumForms, info, r.in.level, count, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
2001         }
2002
2003         return true;
2004 }
2005
2006 static bool test_DeleteForm(struct torture_context *tctx,
2007                             struct dcerpc_pipe *p,
2008                             struct policy_handle *handle,
2009                             const char *form_name)
2010 {
2011         NTSTATUS status;
2012         struct spoolss_DeleteForm r;
2013
2014         r.in.handle = handle;
2015         r.in.form_name = form_name;
2016
2017         status = dcerpc_spoolss_DeleteForm(p, tctx, &r);
2018
2019         torture_assert_ntstatus_ok(tctx, status, "DeleteForm failed");
2020
2021         torture_assert_werr_ok(tctx, r.out.result, "DeleteForm failed");
2022
2023         return true;
2024 }
2025
2026 static bool test_AddForm(struct torture_context *tctx,
2027                          struct dcerpc_pipe *p,
2028                          struct policy_handle *handle, bool print_server)
2029 {
2030         struct spoolss_AddForm r;
2031         struct spoolss_AddFormInfo1 addform;
2032         const char *form_name = "testform3";
2033         NTSTATUS status;
2034         bool ret = true;
2035
2036         r.in.handle     = handle;
2037         r.in.level      = 1;
2038         r.in.info.info1 = &addform;
2039         addform.flags           = SPOOLSS_FORM_USER;
2040         addform.form_name       = form_name;
2041         addform.size.width      = 50;
2042         addform.size.height     = 25;
2043         addform.area.left       = 5;
2044         addform.area.top        = 10;
2045         addform.area.right      = 45;
2046         addform.area.bottom     = 15;
2047
2048         status = dcerpc_spoolss_AddForm(p, tctx, &r);
2049
2050         torture_assert_ntstatus_ok(tctx, status, "AddForm failed");
2051
2052         torture_assert_werr_ok(tctx, r.out.result, "AddForm failed");
2053
2054         if (!print_server) ret &= test_GetForm(tctx, p, handle, form_name, 1);
2055
2056         {
2057                 struct spoolss_SetForm sf;
2058                 struct spoolss_AddFormInfo1 setform;
2059
2060                 sf.in.handle    = handle;
2061                 sf.in.form_name = form_name;
2062                 sf.in.level     = 1;
2063                 sf.in.info.info1= &setform;
2064                 setform.flags           = addform.flags;
2065                 setform.form_name       = addform.form_name;
2066                 setform.size            = addform.size;
2067                 setform.area            = addform.area;
2068
2069                 setform.size.width      = 1234;
2070
2071                 status = dcerpc_spoolss_SetForm(p, tctx, &sf);
2072
2073                 torture_assert_ntstatus_ok(tctx, status, "SetForm failed");
2074
2075                 torture_assert_werr_ok(tctx, r.out.result, "SetForm failed");
2076         }
2077
2078         if (!print_server) ret &= test_GetForm(tctx, p, handle, form_name, 1);
2079
2080         {
2081                 struct spoolss_EnumForms e;
2082                 union spoolss_FormInfo *info;
2083                 uint32_t needed;
2084                 uint32_t count;
2085                 bool found = false;
2086
2087                 e.in.handle = handle;
2088                 e.in.level = 1;
2089                 e.in.buffer = NULL;
2090                 e.in.offered = 0;
2091                 e.out.needed = &needed;
2092                 e.out.count = &count;
2093                 e.out.info = &info;
2094
2095                 torture_comment(tctx, "Testing EnumForms level 1\n");
2096
2097                 status = dcerpc_spoolss_EnumForms(p, tctx, &e);
2098                 torture_assert_ntstatus_ok(tctx, status, "EnumForms failed");
2099
2100                 if (print_server && W_ERROR_EQUAL(e.out.result, WERR_BADFID))
2101                         torture_fail(tctx, "EnumForms on the PrintServer isn't supported by test server (NT4)");
2102
2103                 if (W_ERROR_EQUAL(e.out.result, WERR_INSUFFICIENT_BUFFER)) {
2104                         int j;
2105                         DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed);
2106                         data_blob_clear(&blob);
2107                         e.in.buffer = &blob;
2108                         e.in.offered = needed;
2109
2110                         status = dcerpc_spoolss_EnumForms(p, tctx, &e);
2111
2112                         torture_assert(tctx, info, "No forms returned");
2113
2114                         for (j = 0; j < count; j++) {
2115                                 if (strequal(form_name, info[j].info1.form_name)) {
2116                                         found = true;
2117                                         break;
2118                                 }
2119                         }
2120                 }
2121                 torture_assert(tctx, found, "Newly added form not found in enum call");
2122         }
2123
2124         if (!test_DeleteForm(tctx, p, handle, form_name)) {
2125                 ret = false;
2126         }
2127
2128         return ret;
2129 }
2130
2131 static bool test_EnumPorts_old(struct torture_context *tctx,
2132                                struct dcerpc_pipe *p)
2133 {
2134         NTSTATUS status;
2135         struct spoolss_EnumPorts r;
2136         uint32_t needed;
2137         uint32_t count;
2138         union spoolss_PortInfo *info;
2139
2140         r.in.servername = talloc_asprintf(tctx, "\\\\%s",
2141                                           dcerpc_server_name(p));
2142         r.in.level = 2;
2143         r.in.buffer = NULL;
2144         r.in.offered = 0;
2145         r.out.needed = &needed;
2146         r.out.count = &count;
2147         r.out.info = &info;
2148
2149         torture_comment(tctx, "Testing EnumPorts\n");
2150
2151         status = dcerpc_spoolss_EnumPorts(p, tctx, &r);
2152
2153         torture_assert_ntstatus_ok(tctx, status, "EnumPorts failed");
2154
2155         if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
2156                 DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed);
2157                 data_blob_clear(&blob);
2158                 r.in.buffer = &blob;
2159                 r.in.offered = needed;
2160
2161                 status = dcerpc_spoolss_EnumPorts(p, tctx, &r);
2162                 torture_assert_ntstatus_ok(tctx, status, "EnumPorts failed");
2163                 torture_assert_werr_ok(tctx, r.out.result, "EnumPorts failed");
2164
2165                 torture_assert(tctx, info, "No ports returned");
2166         }
2167
2168         torture_assert_werr_ok(tctx, r.out.result, "EnumPorts failed");
2169
2170         CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumPorts, info, 2, count, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
2171
2172         return true;
2173 }
2174
2175 static bool test_AddPort(struct torture_context *tctx,
2176                          struct dcerpc_pipe *p)
2177 {
2178         NTSTATUS status;
2179         struct spoolss_AddPort r;
2180
2181         r.in.server_name = talloc_asprintf(tctx, "\\\\%s",
2182                                            dcerpc_server_name(p));
2183         r.in.unknown = 0;
2184         r.in.monitor_name = "foo";
2185
2186         torture_comment(tctx, "Testing AddPort\n");
2187
2188         status = dcerpc_spoolss_AddPort(p, tctx, &r);
2189
2190         torture_assert_ntstatus_ok(tctx, status, "AddPort failed");
2191
2192         /* win2k3 returns WERR_NOT_SUPPORTED */
2193
2194 #if 0
2195
2196         if (!W_ERROR_IS_OK(r.out.result)) {
2197                 printf("AddPort failed - %s\n", win_errstr(r.out.result));
2198                 return false;
2199         }
2200
2201 #endif
2202
2203         return true;
2204 }
2205
2206 static bool test_GetJob(struct torture_context *tctx,
2207                         struct dcerpc_pipe *p,
2208                         struct policy_handle *handle, uint32_t job_id)
2209 {
2210         NTSTATUS status;
2211         struct spoolss_GetJob r;
2212         union spoolss_JobInfo info;
2213         uint32_t needed;
2214         uint32_t levels[] = {1, 2 /* 3, 4 */};
2215         uint32_t i;
2216
2217         r.in.handle = handle;
2218         r.in.job_id = job_id;
2219         r.in.level = 0;
2220         r.in.buffer = NULL;
2221         r.in.offered = 0;
2222         r.out.needed = &needed;
2223         r.out.info = &info;
2224
2225         torture_comment(tctx, "Testing GetJob level %d\n", r.in.level);
2226
2227         status = dcerpc_spoolss_GetJob(p, tctx, &r);
2228         torture_assert_werr_equal(tctx, r.out.result, WERR_UNKNOWN_LEVEL, "Unexpected return code");
2229
2230         for (i = 0; i < ARRAY_SIZE(levels); i++) {
2231
2232                 torture_comment(tctx, "Testing GetJob level %d\n", r.in.level);
2233
2234                 needed = 0;
2235
2236                 r.in.level = levels[i];
2237                 r.in.offered = 0;
2238                 r.in.buffer = NULL;
2239
2240                 status = dcerpc_spoolss_GetJob(p, tctx, &r);
2241                 torture_assert_ntstatus_ok(tctx, status, "GetJob failed");
2242
2243                 if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
2244                         DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed);
2245                         data_blob_clear(&blob);
2246                         r.in.buffer = &blob;
2247                         r.in.offered = needed;
2248
2249                         status = dcerpc_spoolss_GetJob(p, tctx, &r);
2250                         torture_assert_ntstatus_ok(tctx, status, "GetJob failed");
2251
2252                 }
2253                 torture_assert(tctx, r.out.info, "No job info returned");
2254                 torture_assert_werr_ok(tctx, r.out.result, "GetJob failed");
2255
2256                 CHECK_NEEDED_SIZE_LEVEL(spoolss_JobInfo, r.out.info, r.in.level, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
2257         }
2258
2259         return true;
2260 }
2261
2262 static bool test_SetJob(struct torture_context *tctx,
2263                         struct dcerpc_pipe *p,
2264                         struct policy_handle *handle, uint32_t job_id,
2265                         enum spoolss_JobControl command)
2266 {
2267         NTSTATUS status;
2268         struct spoolss_SetJob r;
2269
2270         r.in.handle     = handle;
2271         r.in.job_id     = job_id;
2272         r.in.ctr        = NULL;
2273         r.in.command    = command;
2274
2275         switch (command) {
2276         case SPOOLSS_JOB_CONTROL_PAUSE:
2277                 torture_comment(tctx, "Testing SetJob: SPOOLSS_JOB_CONTROL_PAUSE\n");
2278                 break;
2279         case SPOOLSS_JOB_CONTROL_RESUME:
2280                 torture_comment(tctx, "Testing SetJob: SPOOLSS_JOB_CONTROL_RESUME\n");
2281                 break;
2282         case SPOOLSS_JOB_CONTROL_CANCEL:
2283                 torture_comment(tctx, "Testing SetJob: SPOOLSS_JOB_CONTROL_CANCEL\n");
2284                 break;
2285         case SPOOLSS_JOB_CONTROL_RESTART:
2286                 torture_comment(tctx, "Testing SetJob: SPOOLSS_JOB_CONTROL_RESTART\n");
2287                 break;
2288         case SPOOLSS_JOB_CONTROL_DELETE:
2289                 torture_comment(tctx, "Testing SetJob: SPOOLSS_JOB_CONTROL_DELETE\n");
2290                 break;
2291         case SPOOLSS_JOB_CONTROL_SEND_TO_PRINTER:
2292                 torture_comment(tctx, "Testing SetJob: SPOOLSS_JOB_CONTROL_SEND_TO_PRINTER\n");
2293                 break;
2294         case SPOOLSS_JOB_CONTROL_LAST_PAGE_EJECTED:
2295                 torture_comment(tctx, "Testing SetJob: SPOOLSS_JOB_CONTROL_LAST_PAGE_EJECTED\n");
2296                 break;
2297         case SPOOLSS_JOB_CONTROL_RETAIN:
2298                 torture_comment(tctx, "Testing SetJob: SPOOLSS_JOB_CONTROL_RETAIN\n");
2299                 break;
2300         case SPOOLSS_JOB_CONTROL_RELEASE:
2301                 torture_comment(tctx, "Testing SetJob: SPOOLSS_JOB_CONTROL_RELEASE\n");
2302                 break;
2303         default:
2304                 torture_comment(tctx, "Testing SetJob\n");
2305                 break;
2306         }
2307
2308         status = dcerpc_spoolss_SetJob(p, tctx, &r);
2309         torture_assert_ntstatus_ok(tctx, status, "SetJob failed");
2310         torture_assert_werr_ok(tctx, r.out.result, "SetJob failed");
2311
2312         return true;
2313 }
2314
2315 static bool test_AddJob(struct torture_context *tctx,
2316                         struct dcerpc_pipe *p,
2317                         struct policy_handle *handle)
2318 {
2319         NTSTATUS status;
2320         struct spoolss_AddJob r;
2321         uint32_t needed;
2322
2323         r.in.level = 0;
2324         r.in.handle = handle;
2325         r.in.offered = 0;
2326         r.out.needed = &needed;
2327         r.in.buffer = r.out.buffer = NULL;
2328
2329         torture_comment(tctx, "Testing AddJob\n");
2330
2331         status = dcerpc_spoolss_AddJob(p, tctx, &r);
2332         torture_assert_werr_equal(tctx, r.out.result, WERR_UNKNOWN_LEVEL, "AddJob failed");
2333
2334         r.in.level = 1;
2335
2336         status = dcerpc_spoolss_AddJob(p, tctx, &r);
2337         torture_assert_werr_equal(tctx, r.out.result, WERR_INVALID_PARAM, "AddJob failed");
2338
2339         return true;
2340 }
2341
2342
2343 static bool test_EnumJobs(struct torture_context *tctx,
2344                           struct dcerpc_pipe *p,
2345                           struct policy_handle *handle)
2346 {
2347         NTSTATUS status;
2348         struct spoolss_EnumJobs r;
2349         uint32_t needed;
2350         uint32_t count;
2351         union spoolss_JobInfo *info;
2352
2353         r.in.handle = handle;
2354         r.in.firstjob = 0;
2355         r.in.numjobs = 0xffffffff;
2356         r.in.level = 1;
2357         r.in.buffer = NULL;
2358         r.in.offered = 0;
2359         r.out.needed = &needed;
2360         r.out.count = &count;
2361         r.out.info = &info;
2362
2363         torture_comment(tctx, "Testing EnumJobs\n");
2364
2365         status = dcerpc_spoolss_EnumJobs(p, tctx, &r);
2366
2367         torture_assert_ntstatus_ok(tctx, status, "EnumJobs failed");
2368
2369         if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
2370                 int j;
2371                 DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed);
2372                 data_blob_clear(&blob);
2373                 r.in.buffer = &blob;
2374                 r.in.offered = needed;
2375
2376                 status = dcerpc_spoolss_EnumJobs(p, tctx, &r);
2377
2378                 torture_assert_ntstatus_ok(tctx, status, "EnumJobs failed");
2379                 torture_assert_werr_ok(tctx, r.out.result, "EnumJobs failed");
2380                 torture_assert(tctx, info, "No jobs returned");
2381
2382                 CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumJobs, *r.out.info, r.in.level, count, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
2383
2384                 for (j = 0; j < count; j++) {
2385
2386                         torture_assert(tctx, test_GetJob(tctx, p, handle, info[j].info1.job_id),
2387                                 "failed to call test_GetJob");
2388
2389                         /* FIXME - gd */
2390                         if (!torture_setting_bool(tctx, "samba3", false)) {
2391                                 test_SetJob(tctx, p, handle, info[j].info1.job_id, SPOOLSS_JOB_CONTROL_PAUSE);
2392                                 test_SetJob(tctx, p, handle, info[j].info1.job_id, SPOOLSS_JOB_CONTROL_RESUME);
2393                         }
2394                 }
2395
2396         } else {
2397                 torture_assert_werr_ok(tctx, r.out.result, "EnumJobs failed");
2398         }
2399
2400         return true;
2401 }
2402
2403 static bool test_DoPrintTest(struct torture_context *tctx,
2404                              struct dcerpc_pipe *p,
2405                              struct policy_handle *handle)
2406 {
2407         bool ret = true;
2408         NTSTATUS status;
2409         struct spoolss_StartDocPrinter s;
2410         struct spoolss_DocumentInfo1 info1;
2411         struct spoolss_StartPagePrinter sp;
2412         struct spoolss_WritePrinter w;
2413         struct spoolss_EndPagePrinter ep;
2414         struct spoolss_EndDocPrinter e;
2415         int i;
2416         uint32_t job_id;
2417         uint32_t num_written;
2418
2419         torture_comment(tctx, "Testing StartDocPrinter\n");
2420
2421         s.in.handle             = handle;
2422         s.in.level              = 1;
2423         s.in.info.info1         = &info1;
2424         s.out.job_id            = &job_id;
2425         info1.document_name     = "TorturePrintJob";
2426         info1.output_file       = NULL;
2427         info1.datatype          = "RAW";
2428
2429         status = dcerpc_spoolss_StartDocPrinter(p, tctx, &s);
2430         torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_StartDocPrinter failed");
2431         torture_assert_werr_ok(tctx, s.out.result, "StartDocPrinter failed");
2432
2433         for (i=1; i < 4; i++) {
2434                 torture_comment(tctx, "Testing StartPagePrinter: Page[%d]\n", i);
2435
2436                 sp.in.handle            = handle;
2437
2438                 status = dcerpc_spoolss_StartPagePrinter(p, tctx, &sp);
2439                 torture_assert_ntstatus_ok(tctx, status,
2440                                            "dcerpc_spoolss_StartPagePrinter failed");
2441                 torture_assert_werr_ok(tctx, sp.out.result, "StartPagePrinter failed");
2442
2443                 torture_comment(tctx, "Testing WritePrinter: Page[%d]\n", i);
2444
2445                 w.in.handle             = handle;
2446                 w.in.data               = data_blob_string_const(talloc_asprintf(tctx,"TortureTestPage: %d\nData\n",i));
2447                 w.out.num_written       = &num_written;
2448
2449                 status = dcerpc_spoolss_WritePrinter(p, tctx, &w);
2450                 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_WritePrinter failed");
2451                 torture_assert_werr_ok(tctx, w.out.result, "WritePrinter failed");
2452
2453                 torture_comment(tctx, "Testing EndPagePrinter: Page[%d]\n", i);
2454
2455                 ep.in.handle            = handle;
2456
2457                 status = dcerpc_spoolss_EndPagePrinter(p, tctx, &ep);
2458                 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EndPagePrinter failed");
2459                 torture_assert_werr_ok(tctx, ep.out.result, "EndPagePrinter failed");
2460         }
2461
2462         torture_comment(tctx, "Testing EndDocPrinter\n");
2463
2464         e.in.handle = handle;
2465
2466         status = dcerpc_spoolss_EndDocPrinter(p, tctx, &e);
2467         torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EndDocPrinter failed");
2468         torture_assert_werr_ok(tctx, e.out.result, "EndDocPrinter failed");
2469
2470         ret &= test_AddJob(tctx, p, handle);
2471         ret &= test_EnumJobs(tctx, p, handle);
2472
2473         ret &= test_SetJob(tctx, p, handle, job_id, SPOOLSS_JOB_CONTROL_DELETE);
2474
2475         return ret;
2476 }
2477
2478 static bool test_PausePrinter(struct torture_context *tctx,
2479                               struct dcerpc_pipe *p,
2480                               struct policy_handle *handle)
2481 {
2482         NTSTATUS status;
2483         struct spoolss_SetPrinter r;
2484         struct spoolss_SetPrinterInfoCtr info_ctr;
2485         struct spoolss_DevmodeContainer devmode_ctr;
2486         struct sec_desc_buf secdesc_ctr;
2487
2488         info_ctr.level = 0;
2489         info_ctr.info.info0 = NULL;
2490
2491         ZERO_STRUCT(devmode_ctr);
2492         ZERO_STRUCT(secdesc_ctr);
2493
2494         r.in.handle             = handle;
2495         r.in.info_ctr           = &info_ctr;
2496         r.in.devmode_ctr        = &devmode_ctr;
2497         r.in.secdesc_ctr        = &secdesc_ctr;
2498         r.in.command            = SPOOLSS_PRINTER_CONTROL_PAUSE;
2499
2500         torture_comment(tctx, "Testing SetPrinter: SPOOLSS_PRINTER_CONTROL_PAUSE\n");
2501
2502         status = dcerpc_spoolss_SetPrinter(p, tctx, &r);
2503
2504         torture_assert_ntstatus_ok(tctx, status, "SetPrinter failed");
2505
2506         torture_assert_werr_ok(tctx, r.out.result, "SetPrinter failed");
2507
2508         return true;
2509 }
2510
2511 static bool test_ResumePrinter(struct torture_context *tctx,
2512                                struct dcerpc_pipe *p,
2513                                struct policy_handle *handle)
2514 {
2515         NTSTATUS status;
2516         struct spoolss_SetPrinter r;
2517         struct spoolss_SetPrinterInfoCtr info_ctr;
2518         struct spoolss_DevmodeContainer devmode_ctr;
2519         struct sec_desc_buf secdesc_ctr;
2520
2521         info_ctr.level = 0;
2522         info_ctr.info.info0 = NULL;
2523
2524         ZERO_STRUCT(devmode_ctr);
2525         ZERO_STRUCT(secdesc_ctr);
2526
2527         r.in.handle             = handle;
2528         r.in.info_ctr           = &info_ctr;
2529         r.in.devmode_ctr        = &devmode_ctr;
2530         r.in.secdesc_ctr        = &secdesc_ctr;
2531         r.in.command            = SPOOLSS_PRINTER_CONTROL_RESUME;
2532
2533         torture_comment(tctx, "Testing SetPrinter: SPOOLSS_PRINTER_CONTROL_RESUME\n");
2534
2535         status = dcerpc_spoolss_SetPrinter(p, tctx, &r);
2536
2537         torture_assert_ntstatus_ok(tctx, status, "SetPrinter failed");
2538
2539         torture_assert_werr_ok(tctx, r.out.result, "SetPrinter failed");
2540
2541         return true;
2542 }
2543
2544 static bool test_GetPrinterData(struct torture_context *tctx,
2545                                 struct dcerpc_pipe *p,
2546                                 struct policy_handle *handle,
2547                                 const char *value_name,
2548                                 enum winreg_Type *type_p,
2549                                 union spoolss_PrinterData *data_p)
2550 {
2551         NTSTATUS status;
2552         struct spoolss_GetPrinterData r;
2553         uint32_t needed;
2554         enum winreg_Type type;
2555         union spoolss_PrinterData data;
2556
2557         r.in.handle = handle;
2558         r.in.value_name = value_name;
2559         r.in.offered = 0;
2560         r.out.needed = &needed;
2561         r.out.type = &type;
2562         r.out.data = &data;
2563
2564         torture_comment(tctx, "Testing GetPrinterData(%s)\n", r.in.value_name);
2565
2566         status = dcerpc_spoolss_GetPrinterData(p, tctx, &r);
2567         torture_assert_ntstatus_ok(tctx, status, "GetPrinterData failed");
2568
2569         if (W_ERROR_EQUAL(r.out.result, WERR_MORE_DATA)) {
2570                 r.in.offered = needed;
2571
2572                 status = dcerpc_spoolss_GetPrinterData(p, tctx, &r);
2573                 torture_assert_ntstatus_ok(tctx, status, "GetPrinterData failed");
2574         }
2575
2576         torture_assert_werr_ok(tctx, r.out.result,
2577                 talloc_asprintf(tctx, "GetPrinterData(%s) failed", r.in.value_name));
2578
2579         CHECK_NEEDED_SIZE_LEVEL(spoolss_PrinterData, &data, type, lp_iconv_convenience(tctx->lp_ctx), needed, 1);
2580
2581         if (type_p) {
2582                 *type_p = type;
2583         }
2584
2585         if (data_p) {
2586                 *data_p = data;
2587         }
2588
2589         return true;
2590 }
2591
2592 static bool test_GetPrinterDataEx(struct torture_context *tctx,
2593                                   struct dcerpc_pipe *p,
2594                                   struct policy_handle *handle,
2595                                   const char *key_name,
2596                                   const char *value_name,
2597                                   enum winreg_Type *type_p,
2598                                   union spoolss_PrinterData *data_p)
2599 {
2600         NTSTATUS status;
2601         struct spoolss_GetPrinterDataEx r;
2602         enum winreg_Type type;
2603         uint32_t needed;
2604         union spoolss_PrinterData data;
2605
2606         r.in.handle = handle;
2607         r.in.key_name = key_name;
2608         r.in.value_name = value_name;
2609         r.in.offered = 0;
2610         r.out.type = &type;
2611         r.out.needed = &needed;
2612         r.out.data = &data;
2613
2614         torture_comment(tctx, "Testing GetPrinterDataEx(%s - %s)\n",
2615                 r.in.key_name, r.in.value_name);
2616
2617         status = dcerpc_spoolss_GetPrinterDataEx(p, tctx, &r);
2618         if (!NT_STATUS_IS_OK(status)) {
2619                 if (NT_STATUS_EQUAL(status,NT_STATUS_NET_WRITE_FAULT) &&
2620                     p->last_fault_code == DCERPC_FAULT_OP_RNG_ERROR) {
2621                         torture_skip(tctx, "GetPrinterDataEx not supported by server\n");
2622                 }
2623                 torture_assert_ntstatus_ok(tctx, status, "GetPrinterDataEx failed");
2624         }
2625
2626         if (W_ERROR_EQUAL(r.out.result, WERR_MORE_DATA)) {
2627                 r.in.offered = needed;
2628                 status = dcerpc_spoolss_GetPrinterDataEx(p, tctx, &r);
2629                 torture_assert_ntstatus_ok(tctx, status, "GetPrinterDataEx failed");
2630         }
2631
2632         torture_assert_werr_ok(tctx, r.out.result,
2633                 talloc_asprintf(tctx, "GetPrinterDataEx(%s - %s) failed", r.in.key_name, r.in.value_name));
2634
2635         CHECK_NEEDED_SIZE_LEVEL(spoolss_PrinterData, &data, type, lp_iconv_convenience(tctx->lp_ctx), needed, 1);
2636
2637         if (type_p) {
2638                 *type_p = type;
2639         }
2640
2641         if (data_p) {
2642                 *data_p = data;
2643         }
2644
2645         return true;
2646 }
2647
2648 static bool test_GetPrinterData_list(struct torture_context *tctx,
2649                                      struct dcerpc_pipe *p,
2650                                      struct policy_handle *handle)
2651 {
2652         const char *list[] = {
2653                 "W3SvcInstalled",
2654                 "BeepEnabled",
2655                 "EventLog",
2656                 /* "NetPopup", not on w2k8 */
2657                 /* "NetPopupToComputer", not on w2k8 */
2658                 "MajorVersion",
2659                 "MinorVersion",
2660                 "DefaultSpoolDirectory",
2661                 "Architecture",
2662                 "DsPresent",
2663                 "OSVersion",
2664                 /* "OSVersionEx", not on s3 */
2665                 "DNSMachineName"
2666         };
2667         int i;
2668
2669         for (i=0; i < ARRAY_SIZE(list); i++) {
2670                 enum winreg_Type type, type_ex;
2671                 union spoolss_PrinterData data, data_ex;
2672
2673                 torture_assert(tctx, test_GetPrinterData(tctx, p, handle, list[i], &type, &data),
2674                         talloc_asprintf(tctx, "GetPrinterData failed on %s\n", list[i]));
2675                 torture_assert(tctx, test_GetPrinterDataEx(tctx, p, handle, "random_string", list[i], &type_ex, &data_ex),
2676                         talloc_asprintf(tctx, "GetPrinterDataEx failed on %s\n", list[i]));
2677                 torture_assert_int_equal(tctx, type, type_ex, "type mismatch");
2678                 switch (type) {
2679                 case REG_SZ:
2680                         torture_assert_str_equal(tctx, data.string, data_ex.string, "REG_SZ mismatch");
2681                         break;
2682                 case REG_DWORD:
2683                         torture_assert_int_equal(tctx, data.value, data_ex.value, "REG_DWORD mismatch");
2684                         break;
2685                 case REG_BINARY:
2686                         torture_assert_data_blob_equal(tctx, data.binary, data_ex.binary, "REG_BINARY mismatch");
2687                         break;
2688                 default:
2689                         break;
2690                 }
2691         }
2692
2693         return true;
2694 }
2695
2696 static bool test_EnumPrinterData(struct torture_context *tctx, struct dcerpc_pipe *p,
2697                                  struct policy_handle *handle)
2698 {
2699         NTSTATUS status;
2700         struct spoolss_EnumPrinterData r;
2701
2702         ZERO_STRUCT(r);
2703         r.in.handle = handle;
2704         r.in.enum_index = 0;
2705
2706         do {
2707                 uint32_t value_size = 0;
2708                 uint32_t data_size = 0;
2709                 enum winreg_Type type = 0;
2710
2711                 r.in.value_offered = value_size;
2712                 r.out.value_needed = &value_size;
2713                 r.in.data_offered = data_size;
2714                 r.out.data_needed = &data_size;
2715
2716                 r.out.type = &type;
2717                 r.out.data = talloc_zero_array(tctx, uint8_t, 0);
2718
2719                 torture_comment(tctx, "Testing EnumPrinterData\n");
2720
2721                 status = dcerpc_spoolss_EnumPrinterData(p, tctx, &r);
2722
2723                 torture_assert_ntstatus_ok(tctx, status, "EnumPrinterData failed");
2724                 if (W_ERROR_EQUAL(r.out.result, WERR_NO_MORE_ITEMS)) {
2725                         break;
2726                 }
2727                 torture_assert_werr_ok(tctx, r.out.result, "EnumPrinterData");
2728
2729                 r.in.value_offered = value_size;
2730                 r.out.value_name = talloc_zero_array(tctx, const char, value_size);
2731                 r.in.data_offered = data_size;
2732                 r.out.data = talloc_zero_array(tctx, uint8_t, data_size);
2733
2734                 status = dcerpc_spoolss_EnumPrinterData(p, tctx, &r);
2735
2736                 torture_assert_ntstatus_ok(tctx, status, "EnumPrinterData failed");
2737                 if (W_ERROR_EQUAL(r.out.result, WERR_NO_MORE_ITEMS)) {
2738                         break;
2739                 }
2740
2741                 torture_assert_werr_ok(tctx, r.out.result, "EnumPrinterData failed");
2742
2743                 torture_assert(tctx, test_GetPrinterData(tctx, p, handle, r.out.value_name, NULL, NULL),
2744                         talloc_asprintf(tctx, "failed to call GetPrinterData for %s\n", r.out.value_name));
2745
2746                 torture_assert(tctx, test_GetPrinterDataEx(tctx, p, handle, "PrinterDriverData", r.out.value_name, NULL, NULL),
2747                         talloc_asprintf(tctx, "failed to call GetPrinterDataEx on PrinterDriverData for %s\n", r.out.value_name));
2748
2749                 r.in.enum_index++;
2750
2751         } while (W_ERROR_IS_OK(r.out.result));
2752
2753         return true;
2754 }
2755
2756 static bool test_EnumPrinterDataEx(struct torture_context *tctx,
2757                                    struct dcerpc_pipe *p,
2758                                    struct policy_handle *handle,
2759                                    const char *key_name)
2760 {
2761         struct spoolss_EnumPrinterDataEx r;
2762         struct spoolss_PrinterEnumValues *info;
2763         uint32_t needed;
2764         uint32_t count;
2765
2766         r.in.handle = handle;
2767         r.in.key_name = key_name;
2768         r.in.offered = 0;
2769         r.out.needed = &needed;
2770         r.out.count = &count;
2771         r.out.info = &info;
2772
2773         torture_comment(tctx, "Testing EnumPrinterDataEx(%s)\n", key_name);
2774
2775         torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_EnumPrinterDataEx(p, tctx, &r),
2776                 "EnumPrinterDataEx failed");
2777         if (W_ERROR_EQUAL(r.out.result, WERR_MORE_DATA)) {
2778                 r.in.offered = needed;
2779                 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_EnumPrinterDataEx(p, tctx, &r),
2780                         "EnumPrinterDataEx failed");
2781         }
2782
2783         torture_assert_werr_ok(tctx, r.out.result, "EnumPrinterDataEx failed");
2784
2785         CHECK_NEEDED_SIZE_ENUM(spoolss_EnumPrinterDataEx, info, count, lp_iconv_convenience(tctx->lp_ctx), needed, 1);
2786
2787         return true;
2788 }
2789
2790
2791 static bool test_DeletePrinterData(struct torture_context *tctx,
2792                                    struct dcerpc_pipe *p,
2793                                    struct policy_handle *handle,
2794                                    const char *value_name)
2795 {
2796         NTSTATUS status;
2797         struct spoolss_DeletePrinterData r;
2798
2799         r.in.handle = handle;
2800         r.in.value_name = value_name;
2801
2802         torture_comment(tctx, "Testing DeletePrinterData(%s)\n",
2803                 r.in.value_name);
2804
2805         status = dcerpc_spoolss_DeletePrinterData(p, tctx, &r);
2806
2807         torture_assert_ntstatus_ok(tctx, status, "DeletePrinterData failed");
2808         torture_assert_werr_ok(tctx, r.out.result, "DeletePrinterData failed");
2809
2810         return true;
2811 }
2812
2813 static bool test_DeletePrinterDataEx(struct torture_context *tctx,
2814                                      struct dcerpc_pipe *p,
2815                                      struct policy_handle *handle,
2816                                      const char *key_name,
2817                                      const char *value_name)
2818 {
2819         struct spoolss_DeletePrinterDataEx r;
2820
2821         r.in.handle = handle;
2822         r.in.key_name = key_name;
2823         r.in.value_name = value_name;
2824
2825         torture_comment(tctx, "Testing DeletePrinterDataEx(%s - %s)\n",
2826                 r.in.key_name, r.in.value_name);
2827
2828         torture_assert_ntstatus_ok(tctx,
2829                 dcerpc_spoolss_DeletePrinterDataEx(p, tctx, &r),
2830                 "DeletePrinterDataEx failed");
2831         torture_assert_werr_ok(tctx, r.out.result,
2832                 "DeletePrinterDataEx failed");
2833
2834         return true;
2835 }
2836
2837 static bool test_DeletePrinterKey(struct torture_context *tctx,
2838                                   struct dcerpc_pipe *p,
2839                                   struct policy_handle *handle,
2840                                   const char *key_name)
2841 {
2842         struct spoolss_DeletePrinterKey r;
2843
2844         r.in.handle = handle;
2845         r.in.key_name = key_name;
2846
2847         torture_comment(tctx, "Testing DeletePrinterKey(%s)\n", r.in.key_name);
2848
2849         if (strequal(key_name, "") && !torture_setting_bool(tctx, "dangerous", false)) {
2850                 torture_skip(tctx, "not wiping out printer registry - enable dangerous tests to use\n");
2851                 return true;
2852         }
2853
2854         torture_assert_ntstatus_ok(tctx,
2855                 dcerpc_spoolss_DeletePrinterKey(p, tctx, &r),
2856                 "DeletePrinterKey failed");
2857         torture_assert_werr_ok(tctx, r.out.result,
2858                 "DeletePrinterKey failed");
2859
2860         return true;
2861 }
2862
2863 static bool test_SetPrinterData(struct torture_context *tctx,
2864                                 struct dcerpc_pipe *p,
2865                                 struct policy_handle *handle)
2866 {
2867         NTSTATUS status;
2868         struct spoolss_SetPrinterData r;
2869         const char *values[] = {
2870                 "spootyfoot",
2871                 "spooty\\foot",
2872 #if 0
2873         /* FIXME: not working with s3 atm. */
2874                 "spooty,foot",
2875                 "spooty,fo,ot",
2876 #endif
2877                 "spooty foot",
2878 #if 0
2879         /* FIXME: not working with s3 atm. */
2880                 "spooty\\fo,ot",
2881                 "spooty,fo\\ot"
2882 #endif
2883         };
2884         int i;
2885
2886         for (i=0; i < ARRAY_SIZE(values); i++) {
2887
2888                 enum winreg_Type type;
2889                 union spoolss_PrinterData data;
2890
2891                 r.in.handle = handle;
2892                 r.in.value_name = values[i];
2893                 r.in.type = REG_SZ;
2894                 r.in.data.string = "dog";
2895
2896                 torture_comment(tctx, "Testing SetPrinterData(%s)\n",
2897                         r.in.value_name);
2898
2899                 status = dcerpc_spoolss_SetPrinterData(p, tctx, &r);
2900
2901                 torture_assert_ntstatus_ok(tctx, status, "SetPrinterData failed");
2902                 torture_assert_werr_ok(tctx, r.out.result, "SetPrinterData failed");
2903
2904                 if (!test_GetPrinterData(tctx, p, handle, r.in.value_name, &type, &data)) {
2905                         return false;
2906                 }
2907
2908                 torture_assert_int_equal(tctx, r.in.type, type, "type mismatch");
2909                 torture_assert_str_equal(tctx, r.in.data.string, data.string, "data mismatch");
2910
2911                 if (!test_DeletePrinterData(tctx, p, handle, r.in.value_name)) {
2912                         return false;
2913                 }
2914         }
2915
2916         return true;
2917 }
2918
2919 static bool test_EnumPrinterKey(struct torture_context *tctx,
2920                                 struct dcerpc_pipe *p,
2921                                 struct policy_handle *handle,
2922                                 const char *key_name,
2923                                 const char ***array);
2924
2925 static bool test_SetPrinterDataEx(struct torture_context *tctx,
2926                                   struct dcerpc_pipe *p,
2927                                   struct policy_handle *handle)
2928 {
2929         NTSTATUS status;
2930         struct spoolss_SetPrinterDataEx r;
2931         const char *value_name = "dog";
2932         const char *keys[] = {
2933                 "torturedataex",
2934                 "torture data ex",
2935 #if 0
2936         /* FIXME: not working with s3 atm. */
2937                 "torturedataex_with_subkey\\subkey",
2938                 "torturedataex_with_subkey\\subkey:0",
2939                 "torturedataex_with_subkey\\subkey:1",
2940                 "torturedataex_with_subkey\\subkey\\subsubkey",
2941                 "torturedataex_with_subkey\\subkey\\subsubkey:0",
2942                 "torturedataex_with_subkey\\subkey\\subsubkey:1",
2943 #endif
2944                 "torture,data",
2945 #if 0
2946         /* FIXME: not working with s3 atm. */
2947
2948                 "torture,data,ex",
2949                 "torture,data\\ex",
2950                 "torture\\data,ex"
2951 #endif
2952         };
2953         int i;
2954         DATA_BLOB blob = data_blob_string_const("catfoobar");
2955
2956
2957         for (i=0; i < ARRAY_SIZE(keys); i++) {
2958
2959                 char *c;
2960                 const char *key;
2961                 enum winreg_Type type;
2962                 const char **subkeys;
2963                 union spoolss_PrinterData data;
2964
2965                 r.in.handle = handle;
2966                 r.in.key_name = keys[i];
2967                 r.in.value_name = value_name;
2968                 r.in.type = REG_BINARY;
2969                 r.in.data.binary = blob;
2970
2971                 torture_comment(tctx, "Testing SetPrinterDataEx(%s - %s)\n", r.in.key_name, value_name);
2972
2973                 status = dcerpc_spoolss_SetPrinterDataEx(p, tctx, &r);
2974
2975                 torture_assert_ntstatus_ok(tctx, status, "SetPrinterDataEx failed");
2976                 torture_assert_werr_ok(tctx, r.out.result, "SetPrinterDataEx failed");
2977
2978                 key = talloc_strdup(tctx, r.in.key_name);
2979
2980                 if (!test_GetPrinterDataEx(tctx, p, handle, r.in.key_name, value_name, &type, &data)) {
2981                         return false;
2982                 }
2983
2984                 torture_assert_int_equal(tctx, r.in.type, type, "type mismatch");
2985                 torture_assert_data_blob_equal(tctx, blob, data.binary, "data mismatch");
2986
2987                 if (!test_EnumPrinterDataEx(tctx, p, handle, r.in.key_name)) {
2988                         return false;
2989                 }
2990
2991                 if (!test_DeletePrinterDataEx(tctx, p, handle, r.in.key_name, value_name)) {
2992                         return false;
2993                 }
2994
2995                 c = strchr(key, '\\');
2996                 if (c) {
2997                         int i;
2998
2999                         /* we have subkeys */
3000
3001                         *c = 0;
3002
3003                         if (!test_EnumPrinterKey(tctx, p, handle, key, &subkeys)) {
3004                                 return false;
3005                         }
3006
3007                         for (i=0; subkeys && subkeys[i]; i++) {
3008
3009                                 const char *current_key = talloc_asprintf(tctx, "%s\\%s", key, subkeys[i]);
3010
3011                                 if (!test_DeletePrinterKey(tctx, p, handle, current_key)) {
3012                                         return false;
3013                                 }
3014                         }
3015
3016                         if (!test_DeletePrinterKey(tctx, p, handle, key)) {
3017                                 return false;
3018                         }
3019
3020                 } else {
3021                         if (!test_DeletePrinterKey(tctx, p, handle, key)) {
3022                                 return false;
3023                         }
3024                 }
3025         }
3026
3027         return true;
3028 }
3029
3030 static bool test_GetChangeID_PrinterData(struct torture_context *tctx,
3031                                          struct dcerpc_pipe *p,
3032                                          struct policy_handle *handle,
3033                                          uint32_t *change_id)
3034 {
3035         enum winreg_Type type;
3036         union spoolss_PrinterData data;
3037
3038         torture_assert(tctx,
3039                 test_GetPrinterData(tctx, p, handle, "ChangeID", &type, &data),
3040                 "failed to call GetPrinterData");
3041
3042         torture_assert(tctx, type == REG_DWORD, "unexpected type");
3043
3044         *change_id = data.value;
3045
3046         return true;
3047 }
3048
3049 static bool test_GetChangeID_PrinterDataEx(struct torture_context *tctx,
3050                                            struct dcerpc_pipe *p,
3051                                            struct policy_handle *handle,
3052                                            uint32_t *change_id)
3053 {
3054         enum winreg_Type type;
3055         union spoolss_PrinterData data;
3056
3057         torture_assert(tctx,
3058                 test_GetPrinterDataEx(tctx, p, handle, "PrinterDriverData", "ChangeID", &type, &data),
3059                 "failed to call GetPrinterData");
3060
3061         torture_assert(tctx, type == REG_DWORD, "unexpected type");
3062
3063         *change_id = data.value;
3064
3065         return true;
3066 }
3067
3068 static bool test_GetChangeID_PrinterInfo(struct torture_context *tctx,
3069                                          struct dcerpc_pipe *p,
3070                                          struct policy_handle *handle,
3071                                          uint32_t *change_id)
3072 {
3073         union spoolss_PrinterInfo info;
3074
3075         torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 0, &info),
3076                 "failed to query Printer level 0");
3077
3078         *change_id = info.info0.change_id;
3079
3080         return true;
3081 }
3082
3083 static bool test_ChangeID(struct torture_context *tctx,
3084                           struct dcerpc_pipe *p,
3085                           struct policy_handle *handle)
3086 {
3087         uint32_t change_id, change_id_ex, change_id_info;
3088         uint32_t change_id2, change_id_ex2, change_id_info2;
3089         union spoolss_PrinterInfo info;
3090         const char *comment;
3091
3092
3093         torture_comment(tctx, "Testing ChangeID: id change test #1\n");
3094
3095         torture_assert(tctx, test_GetChangeID_PrinterData(tctx, p, handle, &change_id),
3096                 "failed to query for ChangeID");
3097         torture_assert(tctx, test_GetChangeID_PrinterDataEx(tctx, p, handle, &change_id_ex),
3098                 "failed to query for ChangeID");
3099         torture_assert(tctx, test_GetChangeID_PrinterInfo(tctx, p, handle, &change_id_info),
3100                 "failed to query for ChangeID");
3101
3102         torture_assert_int_equal(tctx, change_id, change_id_ex,
3103                 "change_ids should all be equal");
3104         torture_assert_int_equal(tctx, change_id_ex, change_id_info,
3105                 "change_ids should all be equal");
3106
3107
3108         torture_comment(tctx, "Testing ChangeID: id change test #2\n");
3109
3110         torture_assert(tctx, test_GetChangeID_PrinterData(tctx, p, handle, &change_id),
3111                 "failed to query for ChangeID");
3112         torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 2, &info),
3113                 "failed to query Printer level 2");
3114         torture_assert(tctx, test_GetChangeID_PrinterDataEx(tctx, p, handle, &change_id_ex),
3115                 "failed to query for ChangeID");
3116         torture_assert(tctx, test_GetChangeID_PrinterInfo(tctx, p, handle, &change_id_info),
3117                 "failed to query for ChangeID");
3118         torture_assert_int_equal(tctx, change_id, change_id_ex,
3119                 "change_id should not have changed");
3120         torture_assert_int_equal(tctx, change_id_ex, change_id_info,
3121                 "change_id should not have changed");
3122
3123
3124         torture_comment(tctx, "Testing ChangeID: id change test #3\n");
3125
3126         torture_assert(tctx, test_GetChangeID_PrinterData(tctx, p, handle, &change_id),
3127                 "failed to query for ChangeID");
3128         torture_assert(tctx, test_GetChangeID_PrinterDataEx(tctx, p, handle, &change_id_ex),
3129                 "failed to query for ChangeID");
3130         torture_assert(tctx, test_GetChangeID_PrinterInfo(tctx, p, handle, &change_id_info),
3131                 "failed to query for ChangeID");
3132         torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 2, &info),
3133                 "failed to query Printer level 2");
3134         comment = talloc_strdup(tctx, info.info2.comment);
3135
3136         {
3137                 struct spoolss_SetPrinterInfoCtr info_ctr;
3138                 struct spoolss_DevmodeContainer devmode_ctr;
3139                 struct sec_desc_buf secdesc_ctr;
3140                 struct spoolss_SetPrinterInfo2 info2;
3141
3142                 ZERO_STRUCT(info_ctr);
3143                 ZERO_STRUCT(devmode_ctr);
3144                 ZERO_STRUCT(secdesc_ctr);
3145
3146                 info2.servername        = info.info2.servername;
3147                 info2.printername       = info.info2.printername;
3148                 info2.sharename         = info.info2.sharename;
3149                 info2.portname          = info.info2.portname;
3150                 info2.drivername        = info.info2.drivername;
3151                 info2.comment           = "torture_comment";
3152                 info2.location          = info.info2.location;
3153                 info2.devmode_ptr       = 0;
3154                 info2.sepfile           = info.info2.sepfile;
3155                 info2.printprocessor    = info.info2.printprocessor;
3156                 info2.datatype          = info.info2.datatype;
3157                 info2.parameters        = info.info2.parameters;
3158                 info2.secdesc_ptr       = 0;
3159                 info2.attributes        = info.info2.attributes;
3160                 info2.priority          = info.info2.priority;
3161                 info2.defaultpriority   = info.info2.defaultpriority;
3162                 info2.starttime         = info.info2.starttime;
3163                 info2.untiltime         = info.info2.untiltime;
3164                 info2.status            = info.info2.status;
3165                 info2.cjobs             = info.info2.cjobs;
3166                 info2.averageppm        = info.info2.averageppm;
3167
3168                 info_ctr.level = 2;
3169                 info_ctr.info.info2 = &info2;
3170
3171                 torture_assert(tctx, test_SetPrinter(tctx, p, handle, &info_ctr, &devmode_ctr, &secdesc_ctr, 0),
3172                         "failed to call SetPrinter");
3173
3174                 info2.comment           = comment;
3175
3176                 torture_assert(tctx, test_SetPrinter(tctx, p, handle, &info_ctr, &devmode_ctr, &secdesc_ctr, 0),
3177                         "failed to call SetPrinter");
3178
3179         }
3180
3181         torture_assert(tctx, test_GetChangeID_PrinterData(tctx, p, handle, &change_id2),
3182                 "failed to query for ChangeID");
3183         torture_assert(tctx, test_GetChangeID_PrinterDataEx(tctx, p, handle, &change_id_ex2),
3184                 "failed to query for ChangeID");
3185         torture_assert(tctx, test_GetChangeID_PrinterInfo(tctx, p, handle, &change_id_info2),
3186                 "failed to query for ChangeID");
3187
3188         torture_assert_int_equal(tctx, change_id2, change_id_ex2,
3189                 "change_ids should all be equal");
3190         torture_assert_int_equal(tctx, change_id_ex2, change_id_info2,
3191                 "change_ids should all be equal");
3192
3193         torture_assert(tctx, (change_id < change_id2),
3194                 talloc_asprintf(tctx, "change_id %d needs to be larger than change_id %d",
3195                 change_id2, change_id));
3196         torture_assert(tctx, (change_id_ex < change_id_ex2),
3197                 talloc_asprintf(tctx, "change_id %d needs to be larger than change_id %d",
3198                 change_id_ex2, change_id_ex));
3199         torture_assert(tctx, (change_id_info < change_id_info2),
3200                 talloc_asprintf(tctx, "change_id %d needs to be larger than change_id %d",
3201                 change_id_info2, change_id_info));
3202
3203         return true;
3204 }
3205
3206 static bool test_SecondaryClosePrinter(struct torture_context *tctx,
3207                                        struct dcerpc_pipe *p,
3208                                        struct policy_handle *handle)
3209 {
3210         NTSTATUS status;
3211         struct dcerpc_binding *b;
3212         struct dcerpc_pipe *p2;
3213         struct spoolss_ClosePrinter cp;
3214
3215         /* only makes sense on SMB */
3216         if (p->conn->transport.transport != NCACN_NP) {
3217                 return true;
3218         }
3219
3220         torture_comment(tctx, "testing close on secondary pipe\n");
3221
3222         status = dcerpc_parse_binding(tctx, p->conn->binding_string, &b);
3223         torture_assert_ntstatus_ok(tctx, status, "Failed to parse dcerpc binding");
3224
3225         status = dcerpc_secondary_connection(p, &p2, b);
3226         torture_assert_ntstatus_ok(tctx, status, "Failed to create secondary connection");
3227
3228         status = dcerpc_bind_auth_none(p2, &ndr_table_spoolss);
3229         torture_assert_ntstatus_ok(tctx, status, "Failed to create bind on secondary connection");
3230
3231         cp.in.handle = handle;
3232         cp.out.handle = handle;
3233
3234         status = dcerpc_spoolss_ClosePrinter(p2, tctx, &cp);
3235         torture_assert_ntstatus_equal(tctx, status, NT_STATUS_NET_WRITE_FAULT,
3236                         "ERROR: Allowed close on secondary connection");
3237
3238         torture_assert_int_equal(tctx, p2->last_fault_code, DCERPC_FAULT_CONTEXT_MISMATCH,
3239                                  "Unexpected fault code");
3240
3241         talloc_free(p2);
3242
3243         return true;
3244 }
3245
3246 static bool test_OpenPrinter_badname(struct torture_context *tctx,
3247                                      struct dcerpc_pipe *p, const char *name)
3248 {
3249         NTSTATUS status;
3250         struct spoolss_OpenPrinter op;
3251         struct spoolss_OpenPrinterEx opEx;
3252         struct policy_handle handle;
3253         bool ret = true;
3254
3255         op.in.printername       = name;
3256         op.in.datatype          = NULL;
3257         op.in.devmode_ctr.devmode= NULL;
3258         op.in.access_mask       = 0;
3259         op.out.handle           = &handle;
3260
3261         torture_comment(tctx, "\nTesting OpenPrinter(%s) with bad name\n", op.in.printername);
3262
3263         status = dcerpc_spoolss_OpenPrinter(p, tctx, &op);
3264         torture_assert_ntstatus_ok(tctx, status, "OpenPrinter failed");
3265         if (!W_ERROR_EQUAL(WERR_INVALID_PRINTER_NAME,op.out.result)) {
3266                 torture_comment(tctx, "OpenPrinter(%s) unexpected result[%s] should be WERR_INVALID_PRINTER_NAME\n",
3267                         name, win_errstr(op.out.result));
3268         }
3269
3270         if (W_ERROR_IS_OK(op.out.result)) {
3271                 ret &=test_ClosePrinter(tctx, p, &handle);
3272         }
3273
3274         opEx.in.printername             = name;
3275         opEx.in.datatype                = NULL;
3276         opEx.in.devmode_ctr.devmode     = NULL;
3277         opEx.in.access_mask             = 0;
3278         opEx.in.level                   = 1;
3279         opEx.in.userlevel.level1        = NULL;
3280         opEx.out.handle                 = &handle;
3281
3282         torture_comment(tctx, "Testing OpenPrinterEx(%s) with bad name\n", opEx.in.printername);
3283
3284         status = dcerpc_spoolss_OpenPrinterEx(p, tctx, &opEx);
3285         torture_assert_ntstatus_ok(tctx, status, "OpenPrinterEx failed");
3286         if (!W_ERROR_EQUAL(WERR_INVALID_PARAM,opEx.out.result)) {
3287                 torture_comment(tctx, "OpenPrinterEx(%s) unexpected result[%s] should be WERR_INVALID_PARAM\n",
3288                         name, win_errstr(opEx.out.result));
3289         }
3290
3291         if (W_ERROR_IS_OK(opEx.out.result)) {
3292                 ret &=test_ClosePrinter(tctx, p, &handle);
3293         }
3294
3295         return ret;
3296 }
3297
3298 static bool test_OpenPrinter(struct torture_context *tctx,
3299                              struct dcerpc_pipe *p,
3300                              const char *name)
3301 {
3302         NTSTATUS status;
3303         struct spoolss_OpenPrinter r;
3304         struct policy_handle handle;
3305         bool ret = true;
3306
3307         r.in.printername        = talloc_asprintf(tctx, "\\\\%s\\%s", dcerpc_server_name(p), name);
3308         r.in.datatype           = NULL;
3309         r.in.devmode_ctr.devmode= NULL;
3310         r.in.access_mask        = SEC_FLAG_MAXIMUM_ALLOWED;
3311         r.out.handle            = &handle;
3312
3313         torture_comment(tctx, "Testing OpenPrinter(%s)\n", r.in.printername);
3314
3315         status = dcerpc_spoolss_OpenPrinter(p, tctx, &r);
3316
3317         torture_assert_ntstatus_ok(tctx, status, "OpenPrinter failed");
3318
3319         torture_assert_werr_ok(tctx, r.out.result, "OpenPrinter failed");
3320
3321         if (!test_GetPrinter(tctx, p, &handle)) {
3322                 ret = false;
3323         }
3324
3325         if (!torture_setting_bool(tctx, "samba3", false)) {
3326                 if (!test_SecondaryClosePrinter(tctx, p, &handle)) {
3327                         ret = false;
3328                 }
3329         }
3330
3331         if (!test_ClosePrinter(tctx, p, &handle)) {
3332                 ret = false;
3333         }
3334
3335         return ret;
3336 }
3337
3338 static bool call_OpenPrinterEx(struct torture_context *tctx,
3339                                struct dcerpc_pipe *p,
3340                                const char *name, struct policy_handle *handle)
3341 {
3342         struct spoolss_OpenPrinterEx r;
3343         struct spoolss_UserLevel1 userlevel1;
3344         NTSTATUS status;
3345
3346         if (name && name[0]) {
3347                 r.in.printername = talloc_asprintf(tctx, "\\\\%s\\%s",
3348                                                    dcerpc_server_name(p), name);
3349         } else {
3350                 r.in.printername = talloc_asprintf(tctx, "\\\\%s",
3351                                                    dcerpc_server_name(p));
3352         }
3353
3354         r.in.datatype           = NULL;
3355         r.in.devmode_ctr.devmode= NULL;
3356         r.in.access_mask        = SEC_FLAG_MAXIMUM_ALLOWED;
3357         r.in.level              = 1;
3358         r.in.userlevel.level1   = &userlevel1;
3359         r.out.handle = handle;
3360
3361         userlevel1.size = 1234;
3362         userlevel1.client = "hello";
3363         userlevel1.user = "spottyfoot!";
3364         userlevel1.build = 1;
3365         userlevel1.major = 2;
3366         userlevel1.minor = 3;
3367         userlevel1.processor = 4;
3368
3369         torture_comment(tctx, "Testing OpenPrinterEx(%s)\n", r.in.printername);
3370
3371         status = dcerpc_spoolss_OpenPrinterEx(p, tctx, &r);
3372
3373         torture_assert_ntstatus_ok(tctx, status, "OpenPrinterEx failed");
3374
3375         torture_assert_werr_ok(tctx, r.out.result, "OpenPrinterEx failed");
3376
3377         return true;
3378 }
3379
3380 static bool test_OpenPrinterEx(struct torture_context *tctx,
3381                                struct dcerpc_pipe *p,
3382                                const char *name)
3383 {
3384         struct policy_handle handle;
3385         bool ret = true;
3386
3387         if (!call_OpenPrinterEx(tctx, p, name, &handle)) {
3388                 return false;
3389         }
3390
3391         if (!test_PrinterInfo_SD(tctx, p, &handle)) {
3392                 ret = false;
3393         }
3394
3395         if (!test_GetPrinter(tctx, p, &handle)) {
3396                 ret = false;
3397         }
3398
3399         if (!test_EnumForms(tctx, p, &handle, false)) {
3400                 ret = false;
3401         }
3402
3403         if (!test_AddForm(tctx, p, &handle, false)) {
3404                 ret = false;
3405         }
3406
3407         if (!test_EnumPrinterData(tctx, p, &handle)) {
3408                 ret = false;
3409         }
3410
3411         if (!test_EnumPrinterDataEx(tctx, p, &handle, "PrinterDriverData")) {
3412                 ret = false;
3413         }
3414
3415         if (!test_printer_keys(tctx, p, &handle)) {
3416                 ret = false;
3417         }
3418
3419         if (!test_PausePrinter(tctx, p, &handle)) {
3420                 ret = false;
3421         }
3422
3423         if (!test_DoPrintTest(tctx, p, &handle)) {
3424                 ret = false;
3425         }
3426
3427         if (!test_ResumePrinter(tctx, p, &handle)) {
3428                 ret = false;
3429         }
3430
3431         if (!test_SetPrinterData(tctx, p, &handle)) {
3432                 ret = false;
3433         }
3434
3435         if (!test_SetPrinterDataEx(tctx, p, &handle)) {
3436                 ret = false;
3437         }
3438
3439         if (!test_ChangeID(tctx, p, &handle)) {
3440                 ret = false;
3441         }
3442
3443         if (!torture_setting_bool(tctx, "samba3", false)) {
3444                 if (!test_SecondaryClosePrinter(tctx, p, &handle)) {
3445                         ret = false;
3446                 }
3447         }
3448
3449         if (!test_ClosePrinter(tctx, p, &handle)) {
3450                 ret = false;
3451         }
3452
3453         return ret;
3454 }
3455
3456 static bool test_EnumPrinters_old(struct torture_context *tctx, struct dcerpc_pipe *p)
3457 {
3458         struct spoolss_EnumPrinters r;
3459         NTSTATUS status;
3460         uint16_t levels[] = {1, 2, 4, 5};
3461         int i;
3462         bool ret = true;
3463
3464         for (i=0;i<ARRAY_SIZE(levels);i++) {
3465                 union spoolss_PrinterInfo *info;
3466                 int j;
3467                 uint32_t needed;
3468                 uint32_t count;
3469
3470                 r.in.flags      = PRINTER_ENUM_LOCAL;
3471                 r.in.server     = "";
3472                 r.in.level      = levels[i];
3473                 r.in.buffer     = NULL;
3474                 r.in.offered    = 0;
3475                 r.out.needed    = &needed;
3476                 r.out.count     = &count;
3477                 r.out.info      = &info;
3478
3479                 torture_comment(tctx, "Testing EnumPrinters level %u\n", r.in.level);
3480
3481                 status = dcerpc_spoolss_EnumPrinters(p, tctx, &r);
3482                 torture_assert_ntstatus_ok(tctx, status, "EnumPrinters failed");
3483
3484                 if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
3485                         DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed);
3486                         data_blob_clear(&blob);
3487                         r.in.buffer = &blob;
3488                         r.in.offered = needed;
3489                         status = dcerpc_spoolss_EnumPrinters(p, tctx, &r);
3490                 }
3491
3492                 torture_assert_ntstatus_ok(tctx, status, "EnumPrinters failed");
3493
3494                 torture_assert_werr_ok(tctx, r.out.result, "EnumPrinters failed");
3495
3496                 CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumPrinters, info, r.in.level, count, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
3497
3498                 if (!info) {
3499                         torture_comment(tctx, "No printers returned\n");
3500                         return true;
3501                 }
3502
3503                 for (j=0;j<count;j++) {
3504                         if (r.in.level == 1) {
3505                                 char *unc = talloc_strdup(tctx, info[j].info1.name);
3506                                 char *slash, *name;
3507                                 name = unc;
3508                                 if (unc[0] == '\\' && unc[1] == '\\') {
3509                                         unc +=2;
3510                                 }
3511                                 slash = strchr(unc, '\\');
3512                                 if (slash) {
3513                                         slash++;
3514                                         name = slash;
3515                                 }
3516                                 if (!test_OpenPrinter(tctx, p, name)) {
3517                                         ret = false;
3518                                 }
3519                                 if (!test_OpenPrinterEx(tctx, p, name)) {
3520                                         ret = false;
3521                                 }
3522                         }
3523                 }
3524         }
3525
3526         return ret;
3527 }
3528
3529 static bool test_GetPrinterDriver(struct torture_context *tctx,
3530                                   struct dcerpc_pipe *p,
3531                                   struct policy_handle *handle,
3532                                   const char *driver_name)
3533 {
3534         struct spoolss_GetPrinterDriver r;
3535         uint32_t needed;
3536
3537         r.in.handle = handle;
3538         r.in.architecture = "W32X86";
3539         r.in.level = 1;
3540         r.in.buffer = NULL;
3541         r.in.offered = 0;
3542         r.out.needed = &needed;
3543
3544         torture_comment(tctx, "Testing GetPrinterDriver level %d\n", r.in.level);
3545
3546         torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_GetPrinterDriver(p, tctx, &r),
3547                 "failed to call GetPrinterDriver");
3548         if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
3549                 DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed);
3550                 data_blob_clear(&blob);
3551                 r.in.buffer = &blob;
3552                 r.in.offered = needed;
3553                 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_GetPrinterDriver(p, tctx, &r),
3554                         "failed to call GetPrinterDriver");
3555         }
3556
3557         torture_assert_werr_ok(tctx, r.out.result,
3558                 "failed to call GetPrinterDriver");
3559
3560         CHECK_NEEDED_SIZE_LEVEL(spoolss_DriverInfo, r.out.info, r.in.level, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
3561
3562         return true;
3563 }
3564
3565 static bool test_GetPrinterDriver2(struct torture_context *tctx,
3566                                    struct dcerpc_pipe *p,
3567                                    struct policy_handle *handle,
3568                                    const char *driver_name)
3569 {
3570         struct spoolss_GetPrinterDriver2 r;
3571         uint16_t levels[] = {1, 2, 3, 4, 5, 6, 8, 101 };
3572         uint32_t needed;
3573         uint32_t server_major_version;
3574         uint32_t server_minor_version;
3575         int i;
3576
3577         r.in.handle = handle;
3578         r.in.architecture = SPOOLSS_ARCHITECTURE_NT_X86;
3579         r.in.client_major_version = 3;
3580         r.in.client_minor_version = 0;
3581         r.out.needed = &needed;
3582         r.out.server_major_version = &server_major_version;
3583         r.out.server_minor_version = &server_minor_version;
3584
3585         for (i=0;i<ARRAY_SIZE(levels);i++) {
3586
3587                 r.in.buffer = NULL;
3588                 r.in.offered = 0;
3589                 r.in.level = levels[i];
3590
3591                 torture_comment(tctx, "Testing GetPrinterDriver2(%s) level %d\n",
3592                         driver_name, r.in.level);
3593
3594                 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_GetPrinterDriver2(p, tctx, &r),
3595                         "failed to call GetPrinterDriver2");
3596                 if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
3597                         DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed);
3598                         data_blob_clear(&blob);
3599                         r.in.buffer = &blob;
3600                         r.in.offered = needed;
3601                         torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_GetPrinterDriver2(p, tctx, &r),
3602                                 "failed to call GetPrinterDriver2");
3603                 }
3604
3605                 if (W_ERROR_EQUAL(r.out.result, WERR_INVALID_LEVEL)) {
3606                         switch (r.in.level) {
3607                         case 101:
3608                         case 8:
3609                                 continue;
3610                         default:
3611                                 break;
3612                         }
3613                 }
3614
3615                 torture_assert_werr_ok(tctx, r.out.result,
3616                         "failed to call GetPrinterDriver2");
3617
3618                 CHECK_NEEDED_SIZE_LEVEL(spoolss_DriverInfo, r.out.info, r.in.level, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
3619         }
3620
3621         return true;
3622 }
3623
3624 static bool test_EnumPrinterDrivers_old(struct torture_context *tctx,
3625                                         struct dcerpc_pipe *p)
3626 {
3627         struct spoolss_EnumPrinterDrivers r;
3628         NTSTATUS status;
3629         uint16_t levels[] = {1, 2, 3, 4, 5, 6};
3630         int i;
3631
3632         for (i=0;i<ARRAY_SIZE(levels);i++) {
3633
3634                 uint32_t needed;
3635                 uint32_t count;
3636                 union spoolss_DriverInfo *info;
3637
3638                 r.in.server = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
3639                 r.in.environment = SPOOLSS_ARCHITECTURE_NT_X86;
3640                 r.in.level = levels[i];
3641                 r.in.buffer = NULL;
3642                 r.in.offered = 0;
3643                 r.out.needed = &needed;
3644                 r.out.count = &count;
3645                 r.out.info = &info;
3646
3647                 torture_comment(tctx, "Testing EnumPrinterDrivers level %u\n", r.in.level);
3648
3649                 status = dcerpc_spoolss_EnumPrinterDrivers(p, tctx, &r);
3650
3651                 torture_assert_ntstatus_ok(tctx, status, "EnumPrinterDrivers failed");
3652
3653                 if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
3654                         DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed);
3655                         data_blob_clear(&blob);
3656                         r.in.buffer = &blob;
3657                         r.in.offered = needed;
3658                         status = dcerpc_spoolss_EnumPrinterDrivers(p, tctx, &r);
3659                 }
3660
3661                 torture_assert_ntstatus_ok(tctx, status, "EnumPrinterDrivers failed");
3662
3663                 torture_assert_werr_ok(tctx, r.out.result, "EnumPrinterDrivers failed");
3664
3665                 if (!info) {
3666                         torture_comment(tctx, "No printer drivers returned\n");
3667                         break;
3668                 }
3669
3670                 CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumPrinterDrivers, info, r.in.level, count, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
3671         }
3672
3673         return true;
3674 }
3675
3676 static bool test_DeletePrinter(struct torture_context *tctx,
3677                                struct dcerpc_pipe *p,
3678                                struct policy_handle *handle)
3679 {
3680         struct spoolss_DeletePrinter r;
3681
3682         torture_comment(tctx, "Testing DeletePrinter\n");
3683
3684         r.in.handle = handle;
3685
3686         torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_DeletePrinter(p, tctx, &r),
3687                 "failed to delete printer");
3688         torture_assert_werr_ok(tctx, r.out.result,
3689                 "failed to delete printer");
3690
3691         return true;
3692 }
3693
3694 static bool test_EnumPrinters_findname(struct torture_context *tctx,
3695                                        struct dcerpc_pipe *p,
3696                                        uint32_t flags,
3697                                        uint32_t level,
3698                                        const char *name,
3699                                        bool *found)
3700 {
3701         struct spoolss_EnumPrinters e;
3702         uint32_t count;
3703         union spoolss_PrinterInfo *info;
3704         uint32_t needed;
3705         int i;
3706
3707         *found = false;
3708
3709         e.in.flags = flags;
3710         e.in.server = NULL;
3711         e.in.level = level;
3712         e.in.buffer = NULL;
3713         e.in.offered = 0;
3714         e.out.count = &count;
3715         e.out.info = &info;
3716         e.out.needed = &needed;
3717
3718         torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_EnumPrinters(p, tctx, &e),
3719                 "failed to enum printers");
3720
3721         if (W_ERROR_EQUAL(e.out.result, WERR_INSUFFICIENT_BUFFER)) {
3722                 DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed);
3723                 data_blob_clear(&blob);
3724                 e.in.buffer = &blob;
3725                 e.in.offered = needed;
3726
3727                 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_EnumPrinters(p, tctx, &e),
3728                         "failed to enum printers");
3729         }
3730
3731         torture_assert_werr_ok(tctx, e.out.result,
3732                 "failed to enum printers");
3733
3734         for (i=0; i < count; i++) {
3735
3736                 const char *current = NULL;
3737
3738                 switch (level) {
3739                 case 1:
3740                         current = info[i].info1.name;
3741                         break;
3742                 }
3743
3744                 if (strequal(current, name)) {
3745                         *found = true;
3746                         break;
3747                 }
3748         }
3749
3750         return true;
3751 }
3752
3753 static bool test_AddPrinter_wellknown(struct torture_context *tctx,
3754                                       struct dcerpc_pipe *p,
3755                                       const char *printername,
3756                                       bool ex)
3757 {
3758         WERROR result;
3759         struct spoolss_AddPrinter r;
3760         struct spoolss_AddPrinterEx rex;
3761         struct spoolss_SetPrinterInfoCtr info_ctr;
3762         struct spoolss_SetPrinterInfo1 info1;
3763         struct spoolss_DevmodeContainer devmode_ctr;
3764         struct sec_desc_buf secdesc_ctr;
3765         struct spoolss_UserLevelCtr userlevel_ctr;
3766         struct policy_handle handle;
3767         bool found = false;
3768
3769         ZERO_STRUCT(devmode_ctr);
3770         ZERO_STRUCT(secdesc_ctr);
3771         ZERO_STRUCT(userlevel_ctr);
3772         ZERO_STRUCT(info1);
3773
3774         torture_comment(tctx, "Testing AddPrinter%s level 1\n", ex ? "Ex":"");
3775
3776         /* try to add printer to wellknown printer list (level 1) */
3777
3778         userlevel_ctr.level = 1;
3779
3780         info_ctr.info.info1 = &info1;
3781         info_ctr.level = 1;
3782
3783         rex.in.server = NULL;
3784         rex.in.info_ctr = &info_ctr;
3785         rex.in.devmode_ctr = &devmode_ctr;
3786         rex.in.secdesc_ctr = &secdesc_ctr;
3787         rex.in.userlevel_ctr = &userlevel_ctr;
3788         rex.out.handle = &handle;
3789
3790         r.in.server = NULL;
3791         r.in.info_ctr = &info_ctr;
3792         r.in.devmode_ctr = &devmode_ctr;
3793         r.in.secdesc_ctr = &secdesc_ctr;
3794         r.out.handle = &handle;
3795
3796         torture_assert_ntstatus_ok(tctx, ex ? dcerpc_spoolss_AddPrinterEx(p, tctx, &rex) :
3797                                               dcerpc_spoolss_AddPrinter(p, tctx, &r),
3798                 "failed to add printer");
3799         result = ex ? rex.out.result : r.out.result;
3800         torture_assert_werr_equal(tctx, result, WERR_INVALID_PRINTER_NAME,
3801                 "unexpected result code");
3802
3803         info1.name = printername;
3804         info1.flags = PRINTER_ATTRIBUTE_SHARED;
3805
3806         torture_assert_ntstatus_ok(tctx, ex ? dcerpc_spoolss_AddPrinterEx(p, tctx, &rex) :
3807                                               dcerpc_spoolss_AddPrinter(p, tctx, &r),
3808                 "failed to add printer");
3809         result = ex ? rex.out.result : r.out.result;
3810         torture_assert_werr_equal(tctx, result, WERR_PRINTER_ALREADY_EXISTS,
3811                 "unexpected result code");
3812
3813         /* bizarre protocol, WERR_PRINTER_ALREADY_EXISTS means success here,
3814            better do a real check to see the printer is really there */
3815
3816         torture_assert(tctx, test_EnumPrinters_findname(tctx, p,
3817                                                         PRINTER_ENUM_NETWORK, 1,
3818                                                         printername,
3819                                                         &found),
3820                         "failed to enum printers");
3821
3822         torture_assert(tctx, found, "failed to find newly added printer");
3823
3824         info1.flags = 0;
3825
3826         torture_assert_ntstatus_ok(tctx, ex ? dcerpc_spoolss_AddPrinterEx(p, tctx, &rex) :
3827                                               dcerpc_spoolss_AddPrinter(p, tctx, &r),
3828                 "failed to add printer");
3829         result = ex ? rex.out.result : r.out.result;
3830         torture_assert_werr_equal(tctx, result, WERR_PRINTER_ALREADY_EXISTS,
3831                 "unexpected result code");
3832
3833         /* bizarre protocol, WERR_PRINTER_ALREADY_EXISTS means success here,
3834            better do a real check to see the printer has really been removed
3835            from the well known printer list */
3836
3837         found = false;
3838
3839         torture_assert(tctx, test_EnumPrinters_findname(tctx, p,
3840                                                         PRINTER_ENUM_NETWORK, 1,
3841                                                         printername,
3842                                                         &found),
3843                         "failed to enum printers");
3844 #if 0
3845         torture_assert(tctx, !found, "printer still in well known printer list");
3846 #endif
3847         return true;
3848 }
3849
3850 static bool test_AddPrinter_normal(struct torture_context *tctx,
3851                                    struct dcerpc_pipe *p,
3852                                    struct policy_handle *handle_p,
3853                                    const char *printername,
3854                                    const char *drivername,
3855                                    const char *portname,
3856                                    bool ex)
3857 {
3858         WERROR result;
3859         struct spoolss_AddPrinter r;
3860         struct spoolss_AddPrinterEx rex;
3861         struct spoolss_SetPrinterInfoCtr info_ctr;
3862         struct spoolss_SetPrinterInfo2 info2;
3863         struct spoolss_DevmodeContainer devmode_ctr;
3864         struct sec_desc_buf secdesc_ctr;
3865         struct spoolss_UserLevelCtr userlevel_ctr;
3866         struct policy_handle handle;
3867         bool found = false;
3868
3869         ZERO_STRUCT(devmode_ctr);
3870         ZERO_STRUCT(secdesc_ctr);
3871         ZERO_STRUCT(userlevel_ctr);
3872
3873         torture_comment(tctx, "Testing AddPrinter%s level 2\n", ex ? "Ex":"");
3874
3875         userlevel_ctr.level = 1;
3876
3877         rex.in.server = NULL;
3878         rex.in.info_ctr = &info_ctr;
3879         rex.in.devmode_ctr = &devmode_ctr;
3880         rex.in.secdesc_ctr = &secdesc_ctr;
3881         rex.in.userlevel_ctr = &userlevel_ctr;
3882         rex.out.handle = &handle;
3883
3884         r.in.server = NULL;
3885         r.in.info_ctr = &info_ctr;
3886         r.in.devmode_ctr = &devmode_ctr;
3887         r.in.secdesc_ctr = &secdesc_ctr;
3888         r.out.handle = &handle;
3889
3890  again:
3891
3892         /* try to add printer to printer list (level 2) */
3893
3894         ZERO_STRUCT(info2);
3895
3896         info_ctr.info.info2 = &info2;
3897         info_ctr.level = 2;
3898
3899         torture_assert_ntstatus_ok(tctx, ex ? dcerpc_spoolss_AddPrinterEx(p, tctx, &rex) :
3900                                               dcerpc_spoolss_AddPrinter(p, tctx, &r),
3901                 "failed to add printer");
3902         result = ex ? rex.out.result : r.out.result;
3903         torture_assert_werr_equal(tctx, result, WERR_INVALID_PRINTER_NAME,
3904                 "unexpected result code");
3905
3906         info2.printername = printername;
3907
3908         torture_assert_ntstatus_ok(tctx, ex ? dcerpc_spoolss_AddPrinterEx(p, tctx, &rex) :
3909                                               dcerpc_spoolss_AddPrinter(p, tctx, &r),
3910                 "failed to add printer");
3911         result = ex ? rex.out.result : r.out.result;
3912
3913         if (W_ERROR_EQUAL(result, WERR_PRINTER_ALREADY_EXISTS)) {
3914                 struct policy_handle printer_handle;
3915
3916                 torture_assert(tctx, call_OpenPrinterEx(tctx, p, printername, &printer_handle),
3917                         "failed to open printer handle");
3918
3919                 torture_assert(tctx, test_DeletePrinter(tctx, p, &printer_handle),
3920                         "failed to delete printer");
3921
3922                 torture_assert(tctx, test_ClosePrinter(tctx, p, &printer_handle),
3923                         "failed to close server handle");
3924
3925                 goto again;
3926         }
3927
3928         torture_assert_werr_equal(tctx, result, WERR_UNKNOWN_PORT,
3929                 "unexpected result code");
3930
3931         info2.portname = portname;
3932
3933         torture_assert_ntstatus_ok(tctx, ex ? dcerpc_spoolss_AddPrinterEx(p, tctx, &rex) :
3934                                               dcerpc_spoolss_AddPrinter(p, tctx, &r),
3935                 "failed to add printer");
3936         result = ex ? rex.out.result : r.out.result;
3937         torture_assert_werr_equal(tctx, result, WERR_UNKNOWN_PRINTER_DRIVER,
3938                 "unexpected result code");
3939
3940         info2.drivername = drivername;
3941
3942         torture_assert_ntstatus_ok(tctx, ex ? dcerpc_spoolss_AddPrinterEx(p, tctx, &rex) :
3943                                               dcerpc_spoolss_AddPrinter(p, tctx, &r),
3944                 "failed to add printer");
3945         result = ex ? rex.out.result : r.out.result;
3946
3947         /* w2k8r2 allows to add printer w/o defining printprocessor */
3948
3949         if (!W_ERROR_IS_OK(result)) {
3950                 torture_assert_werr_equal(tctx, result, WERR_UNKNOWN_PRINTPROCESSOR,
3951                         "unexpected result code");
3952
3953                 info2.printprocessor = "winprint";
3954
3955                 torture_assert_ntstatus_ok(tctx, ex ? dcerpc_spoolss_AddPrinterEx(p, tctx, &rex) :
3956                                                       dcerpc_spoolss_AddPrinter(p, tctx, &r),
3957                         "failed to add printer");
3958                 result = ex ? rex.out.result : r.out.result;
3959                 torture_assert_werr_ok(tctx, result,
3960                         "failed to add printer");
3961         }
3962
3963         *handle_p = handle;
3964
3965         /* we are paranoid, really check if the printer is there now */
3966
3967         torture_assert(tctx, test_EnumPrinters_findname(tctx, p,
3968                                                         PRINTER_ENUM_LOCAL, 1,
3969                                                         printername,
3970                                                         &found),
3971                         "failed to enum printers");
3972         torture_assert(tctx, found, "failed to find newly added printer");
3973
3974         torture_assert_ntstatus_ok(tctx, ex ? dcerpc_spoolss_AddPrinterEx(p, tctx, &rex) :
3975                                               dcerpc_spoolss_AddPrinter(p, tctx, &r),
3976                 "failed to add printer");
3977         result = ex ? rex.out.result : r.out.result;
3978         torture_assert_werr_equal(tctx, result, WERR_PRINTER_ALREADY_EXISTS,
3979                 "unexpected result code");
3980
3981         return true;
3982 }
3983
3984 static bool test_AddPrinterEx(struct torture_context *tctx,
3985                               struct dcerpc_pipe *p,
3986                               struct policy_handle *handle_p,
3987                               const char *printername,
3988                               const char *drivername,
3989                               const char *portname)
3990 {
3991         bool ret = true;
3992
3993         if (!torture_setting_bool(tctx, "samba3", false)) {
3994                 if (!test_AddPrinter_wellknown(tctx, p, TORTURE_WELLKNOWN_PRINTER_EX, true)) {
3995                         torture_comment(tctx, "failed to add printer to well known list\n");
3996                         ret = false;
3997                 }
3998         }
3999
4000         if (!test_AddPrinter_normal(tctx, p, handle_p,
4001                                     printername, drivername, portname,
4002                                     true)) {
4003                 torture_comment(tctx, "failed to add printer to printer list\n");
4004                 ret = false;
4005         }
4006
4007         return ret;
4008 }
4009
4010 static bool test_AddPrinter(struct torture_context *tctx,
4011                             struct dcerpc_pipe *p,
4012                             struct policy_handle *handle_p,
4013                             const char *printername,
4014                             const char *drivername,
4015                             const char *portname)
4016 {
4017         bool ret = true;
4018
4019         if (!torture_setting_bool(tctx, "samba3", false)) {
4020                 if (!test_AddPrinter_wellknown(tctx, p, TORTURE_WELLKNOWN_PRINTER, false)) {
4021                         torture_comment(tctx, "failed to add printer to well known list\n");
4022                         ret = false;
4023                 }
4024         }
4025
4026         if (!test_AddPrinter_normal(tctx, p, handle_p,
4027                                     printername, drivername, portname,
4028                                     false)) {
4029                 torture_comment(tctx, "failed to add printer to printer list\n");
4030                 ret = false;
4031         }
4032
4033         return ret;
4034 }
4035
4036 static bool test_printer_info(struct torture_context *tctx,
4037                               struct dcerpc_pipe *p,
4038                               struct policy_handle *handle)
4039 {
4040         bool ret = true;
4041
4042         if (!test_PrinterInfo(tctx, p, handle)) {
4043                 ret = false;
4044         }
4045
4046         if (!test_SetPrinter_errors(tctx, p, handle)) {
4047                 ret = false;
4048         }
4049
4050         return ret;
4051 }
4052
4053 static bool test_EnumPrinterKey(struct torture_context *tctx,
4054                                 struct dcerpc_pipe *p,
4055                                 struct policy_handle *handle,
4056                                 const char *key_name,
4057                                 const char ***array)
4058 {
4059         struct spoolss_EnumPrinterKey r;
4060         uint32_t needed = 0;
4061         union spoolss_KeyNames key_buffer;
4062         int32_t offered[] = { 0, 1, 2, 3, 4, 5, -1, -2, -3, -4, -5, 256, 512, 1024, 2048 };
4063         uint32_t _ndr_size;
4064         int i;
4065
4066         r.in.handle = handle;
4067         r.in.key_name = key_name;
4068         r.out.key_buffer = &key_buffer;
4069         r.out.needed = &needed;
4070         r.out._ndr_size = &_ndr_size;
4071
4072         for (i=0; i < ARRAY_SIZE(offered); i++) {
4073
4074                 if (offered[i] < 0 && needed) {
4075                         if (needed <= 4) {
4076                                 continue;
4077                         }
4078                         r.in.offered = needed + offered[i];
4079                 } else {
4080                         r.in.offered = offered[i];
4081                 }
4082
4083                 ZERO_STRUCT(key_buffer);
4084
4085                 torture_comment(tctx, "Testing EnumPrinterKey(%s) with %d offered\n", r.in.key_name, r.in.offered);
4086
4087                 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_EnumPrinterKey(p, tctx, &r),
4088                         "failed to call EnumPrinterKey");
4089                 if (W_ERROR_EQUAL(r.out.result, WERR_MORE_DATA)) {
4090
4091                         torture_assert(tctx, (_ndr_size == r.in.offered/2),
4092                                 talloc_asprintf(tctx, "EnumPrinterKey size mismatch, _ndr_size %d (expected %d)",
4093                                         _ndr_size, r.in.offered/2));
4094
4095                         r.in.offered = needed;
4096                         torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_EnumPrinterKey(p, tctx, &r),
4097                                 "failed to call EnumPrinterKey");
4098                 }
4099
4100                 if (offered[i] > 0) {
4101                         torture_assert_werr_ok(tctx, r.out.result,
4102                                 "failed to call EnumPrinterKey");
4103                 }
4104
4105                 torture_assert(tctx, (_ndr_size == r.in.offered/2),
4106                         talloc_asprintf(tctx, "EnumPrinterKey size mismatch, _ndr_size %d (expected %d)",
4107                                 _ndr_size, r.in.offered/2));
4108
4109                 torture_assert(tctx, (*r.out.needed <= r.in.offered),
4110                         talloc_asprintf(tctx, "EnumPrinterKey size mismatch: needed %d is not <= offered %d", *r.out.needed, r.in.offered));
4111
4112                 torture_assert(tctx, (*r.out.needed <= _ndr_size * 2),
4113                         talloc_asprintf(tctx, "EnumPrinterKey size mismatch: needed %d is not <= _ndr_size %d * 2", *r.out.needed, _ndr_size));
4114
4115                 if (key_buffer.string_array) {
4116                         uint32_t calc_needed = 0;
4117                         int s;
4118                         for (s=0; key_buffer.string_array[s]; s++) {
4119                                 calc_needed += strlen_m_term(key_buffer.string_array[s])*2;
4120                         }
4121                         if (!key_buffer.string_array[0]) {
4122                                 calc_needed += 2;
4123                         }
4124                         calc_needed += 2;
4125
4126                         torture_assert_int_equal(tctx, *r.out.needed, calc_needed,
4127                                 "EnumPrinterKey unexpected size");
4128                 }
4129         }
4130
4131         if (array) {
4132                 *array = key_buffer.string_array;
4133         }
4134
4135         return true;
4136 }
4137
4138 bool test_printer_keys(struct torture_context *tctx,
4139                        struct dcerpc_pipe *p,
4140                        struct policy_handle *handle)
4141 {
4142         const char **key_array = NULL;
4143         int i;
4144
4145         torture_assert(tctx, test_EnumPrinterKey(tctx, p, handle, "", &key_array),
4146                 "failed to call test_EnumPrinterKey");
4147
4148         for (i=0; key_array && key_array[i]; i++) {
4149                 torture_assert(tctx, test_EnumPrinterKey(tctx, p, handle, key_array[i], NULL),
4150                         "failed to call test_EnumPrinterKey");
4151         }
4152         for (i=0; key_array && key_array[i]; i++) {
4153                 torture_assert(tctx, test_EnumPrinterDataEx(tctx, p, handle, key_array[i]),
4154                         "failed to call test_EnumPrinterDataEx");
4155         }
4156
4157         return true;
4158 }
4159
4160 static bool test_printer(struct torture_context *tctx,
4161                          struct dcerpc_pipe *p)
4162 {
4163         bool ret = true;
4164         struct policy_handle handle[2];
4165         bool found = false;
4166         const char *drivername = "Microsoft XPS Document Writer";
4167         const char *portname = "LPT1:";
4168
4169         /* test printer created via AddPrinter */
4170
4171         if (!test_AddPrinter(tctx, p, &handle[0], TORTURE_PRINTER, drivername, portname)) {
4172                 return false;
4173         }
4174
4175         if (!test_printer_info(tctx, p, &handle[0])) {
4176                 ret = false;
4177         }
4178
4179         if (!test_PrinterInfo_SD(tctx, p, &handle[0])) {
4180                 ret = false;
4181         }
4182
4183         if (!test_PrinterInfo_DevMode(tctx, p, &handle[0])) {
4184                 ret = false;
4185         }
4186
4187         if (!test_printer_keys(tctx, p, &handle[0])) {
4188                 ret = false;
4189         }
4190
4191         if (!test_DeletePrinter(tctx, p, &handle[0])) {
4192                 ret = false;
4193         }
4194
4195         if (!test_EnumPrinters_findname(tctx, p, PRINTER_ENUM_LOCAL, 1,
4196                                         TORTURE_PRINTER, &found)) {
4197                 ret = false;
4198         }
4199
4200         torture_assert(tctx, !found, "deleted printer still there");
4201
4202         /* test printer created via AddPrinterEx */
4203
4204         if (!test_AddPrinterEx(tctx, p, &handle[1], TORTURE_PRINTER_EX, drivername, portname)) {
4205                 return false;
4206         }
4207
4208         if (!test_printer_info(tctx, p, &handle[1])) {
4209                 ret = false;
4210         }
4211
4212         if (!test_printer_keys(tctx, p, &handle[1])) {
4213                 ret = false;
4214         }
4215
4216         if (!test_DeletePrinter(tctx, p, &handle[1])) {
4217                 ret = false;
4218         }
4219
4220         if (!test_EnumPrinters_findname(tctx, p, PRINTER_ENUM_LOCAL, 1,
4221                                         TORTURE_PRINTER_EX, &found)) {
4222                 ret = false;
4223         }
4224
4225         torture_assert(tctx, !found, "deleted printer still there");
4226
4227         return ret;
4228 }
4229
4230 bool torture_rpc_spoolss(struct torture_context *torture)
4231 {
4232         NTSTATUS status;
4233         struct dcerpc_pipe *p;
4234         bool ret = true;
4235         struct test_spoolss_context *ctx;
4236
4237         status = torture_rpc_connection(torture, &p, &ndr_table_spoolss);
4238         if (!NT_STATUS_IS_OK(status)) {
4239                 return false;
4240         }
4241
4242         ctx = talloc_zero(torture, struct test_spoolss_context);
4243
4244         ret &= test_OpenPrinter_server(torture, p, &ctx->server_handle);
4245         ret &= test_GetPrinterData_list(torture, p, &ctx->server_handle);
4246         ret &= test_EnumForms(torture, p, &ctx->server_handle, true);
4247         ret &= test_AddForm(torture, p, &ctx->server_handle, true);
4248         ret &= test_EnumPorts(torture, p, ctx);
4249         ret &= test_GetPrinterDriverDirectory(torture, p, ctx);
4250         ret &= test_GetPrintProcessorDirectory(torture, p, ctx);
4251         ret &= test_EnumPrinterDrivers(torture, p, ctx, SPOOLSS_ARCHITECTURE_NT_X86);
4252         ret &= test_EnumPrinterDrivers(torture, p, ctx, SPOOLSS_ARCHITECTURE_ALL);
4253         ret &= test_EnumMonitors(torture, p, ctx);
4254         ret &= test_EnumPrintProcessors(torture, p, ctx);
4255         ret &= test_EnumPrintProcDataTypes(torture, p, ctx);
4256         ret &= test_EnumPrinters(torture, p, ctx);
4257         ret &= test_OpenPrinter_badname(torture, p, "__INVALID_PRINTER__");
4258         ret &= test_OpenPrinter_badname(torture, p, "\\\\__INVALID_HOST__");
4259         ret &= test_OpenPrinter_badname(torture, p, "");
4260         ret &= test_OpenPrinter_badname(torture, p, "\\\\\\");
4261         ret &= test_OpenPrinter_badname(torture, p, "\\\\\\__INVALID_PRINTER__");
4262         ret &= test_OpenPrinter_badname(torture, p, talloc_asprintf(torture, "\\\\%s\\", dcerpc_server_name(p)));
4263         ret &= test_OpenPrinter_badname(torture, p,
4264                                         talloc_asprintf(torture, "\\\\%s\\__INVALID_PRINTER__", dcerpc_server_name(p)));
4265
4266
4267         ret &= test_AddPort(torture, p);
4268         ret &= test_EnumPorts_old(torture, p);
4269         ret &= test_EnumPrinters_old(torture, p);
4270         ret &= test_EnumPrinterDrivers_old(torture, p);
4271
4272         return ret;
4273 }
4274
4275 struct torture_suite *torture_rpc_spoolss_printer(TALLOC_CTX *mem_ctx)
4276 {
4277         struct torture_suite *suite = torture_suite_create(mem_ctx, "SPOOLSS-PRINTER");
4278
4279         struct torture_rpc_tcase *tcase = torture_suite_add_rpc_iface_tcase(suite,
4280                                                         "printer", &ndr_table_spoolss);
4281
4282         torture_rpc_tcase_add_test(tcase, "printer", test_printer);
4283
4284         return suite;
4285 }