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