s4-smbtorture: hand down printername to test_SetPrinterDataEx_matrix.
[metze/samba/wip.git] / source4 / torture / rpc / spoolss.c
1 /*
2    Unix SMB/CIFS implementation.
3    test suite for spoolss rpc operations
4
5    Copyright (C) Tim Potter 2003
6    Copyright (C) Stefan Metzmacher 2005
7    Copyright (C) Jelmer Vernooij 2007
8    Copyright (C) Guenther Deschner 2009-2010
9
10    This program is free software; you can redistribute it and/or modify
11    it under the terms of the GNU General Public License as published by
12    the Free Software Foundation; either version 3 of the License, or
13    (at your option) any later version.
14
15    This program is distributed in the hope that it will be useful,
16    but WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18    GNU General Public License for more details.
19
20    You should have received a copy of the GNU General Public License
21    along with this program.  If not, see <http://www.gnu.org/licenses/>.
22 */
23
24 #include "includes.h"
25 #include "torture/torture.h"
26 #include "librpc/gen_ndr/ndr_misc.h"
27 #include "librpc/gen_ndr/ndr_spoolss.h"
28 #include "librpc/gen_ndr/ndr_spoolss_c.h"
29 #include "librpc/gen_ndr/ndr_security.h"
30 #include "libcli/security/security.h"
31 #include "torture/rpc/rpc.h"
32 #include "param/param.h"
33 #include "lib/registry/registry.h"
34
35 #define TORTURE_WELLKNOWN_PRINTER       "torture_wkn_printer"
36 #define TORTURE_PRINTER                 "torture_printer"
37 #define TORTURE_WELLKNOWN_PRINTER_EX    "torture_wkn_printer_ex"
38 #define TORTURE_PRINTER_EX              "torture_printer_ex"
39
40 struct test_spoolss_context {
41         /* print server handle */
42         struct policy_handle server_handle;
43
44         /* for EnumPorts */
45         uint32_t port_count[3];
46         union spoolss_PortInfo *ports[3];
47
48         /* for EnumPrinterDrivers */
49         uint32_t driver_count[8];
50         union spoolss_DriverInfo *drivers[8];
51
52         /* for EnumMonitors */
53         uint32_t monitor_count[3];
54         union spoolss_MonitorInfo *monitors[3];
55
56         /* for EnumPrintProcessors */
57         uint32_t print_processor_count[2];
58         union spoolss_PrintProcessorInfo *print_processors[2];
59
60         /* for EnumPrinters */
61         uint32_t printer_count[6];
62         union spoolss_PrinterInfo *printers[6];
63 };
64
65 #define COMPARE_STRING(tctx, c,r,e) \
66         torture_assert_str_equal(tctx, c.e, r.e, "invalid value")
67
68 /* not every compiler supports __typeof__() */
69 #if (__GNUC__ >= 3)
70 #define _CHECK_FIELD_SIZE(c,r,e,type) do {\
71         if (sizeof(__typeof__(c.e)) != sizeof(type)) { \
72                 torture_fail(tctx, #c "." #e "field is not " #type "\n"); \
73         }\
74         if (sizeof(__typeof__(r.e)) != sizeof(type)) { \
75                 torture_fail(tctx, #r "." #e "field is not " #type "\n"); \
76         }\
77 } while(0)
78 #else
79 #define _CHECK_FIELD_SIZE(c,r,e,type) do {} while(0)
80 #endif
81
82 #define COMPARE_UINT32(tctx, c, r, e) do {\
83         _CHECK_FIELD_SIZE(c, r, e, uint32_t); \
84         torture_assert_int_equal(tctx, c.e, r.e, "invalid value"); \
85 } while(0)
86
87 #define COMPARE_UINT64(tctx, c, r, e) do {\
88         _CHECK_FIELD_SIZE(c, r, e, uint64_t); \
89         torture_assert_int_equal(tctx, c.e, r.e, "invalid value"); \
90 } while(0)
91
92
93 #define COMPARE_NTTIME(tctx, c, r, e) do {\
94         _CHECK_FIELD_SIZE(c, r, e, NTTIME); \
95         torture_assert_int_equal(tctx, c.e, r.e, "invalid value"); \
96 } while(0)
97
98 #define COMPARE_STRING_ARRAY(tctx, c,r,e) do {\
99         int __i; \
100         if (!c.e && !r.e) { \
101                 break; \
102         } \
103         if (c.e && !r.e) { \
104                 torture_fail(tctx, #r "." #e " field is NULL and " #c "." #e " is not\n"); \
105         } \
106         if (!c.e && r.e) { \
107                 torture_fail(tctx, #c "." #e " field is NULL and " #r "." #e " is not\n"); \
108         } \
109         for (__i=0;c.e[__i] != NULL; __i++) { \
110                 torture_assert_str_equal(tctx, c.e[__i], r.e[__i], "invalid value"); \
111         } \
112 } while(0)
113
114 #define CHECK_ALIGN(size, n) do {\
115         if (size % n) {\
116                 torture_warning(tctx, "%d is *NOT* %d byte aligned, should be %d",\
117                         size, n, size + n - (size % n));\
118         }\
119 } while(0)
120
121 #define DO_ROUND(size, n) (((size)+((n)-1)) & ~((n)-1))
122
123 #define CHECK_NEEDED_SIZE_ENUM_LEVEL(fn, info, level, count, ic, needed, align) do { \
124         if (torture_setting_bool(tctx, "spoolss_check_size", false)) {\
125         uint32_t size = ndr_size_##fn##_info(tctx, ic, level, count, info);\
126         uint32_t round_size = DO_ROUND(size, align);\
127         if (round_size != needed) {\
128                 torture_warning(tctx, __location__": "#fn" level %d (count: %d) got unexpected needed size: %d, we calculated: %d", level, count, needed, round_size);\
129                 CHECK_ALIGN(size, align);\
130         }\
131         }\
132 } while(0)
133
134 #define CHECK_NEEDED_SIZE_ENUM(fn, info, count, ic, needed, align) do { \
135         if (torture_setting_bool(tctx, "spoolss_check_size", false)) {\
136         uint32_t size = ndr_size_##fn##_info(tctx, ic, count, info);\
137         uint32_t round_size = DO_ROUND(size, align);\
138         if (round_size != needed) {\
139                 torture_warning(tctx, __location__": "#fn" (count: %d) got unexpected needed size: %d, we calculated: %d", count, needed, round_size);\
140                 CHECK_ALIGN(size, align);\
141         }\
142         }\
143 } while(0)
144
145 #define CHECK_NEEDED_SIZE_LEVEL(fn, info, level, ic, needed, align) do { \
146         if (torture_setting_bool(tctx, "spoolss_check_size", false)) {\
147         uint32_t size = ndr_size_##fn(info, level, ic, 0);\
148         uint32_t round_size = DO_ROUND(size, align);\
149         if (round_size != needed) {\
150                 torture_warning(tctx, __location__": "#fn" level %d got unexpected needed size: %d, we calculated: %d", level, needed, round_size);\
151                 CHECK_ALIGN(size, align);\
152         }\
153         }\
154 } while(0)
155
156 static bool test_OpenPrinter_server(struct torture_context *tctx,
157                                     struct dcerpc_pipe *p,
158                                     struct policy_handle *server_handle)
159 {
160         NTSTATUS status;
161         struct spoolss_OpenPrinter op;
162
163         op.in.printername       = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
164         op.in.datatype          = NULL;
165         op.in.devmode_ctr.devmode= NULL;
166         op.in.access_mask       = 0;
167         op.out.handle           = server_handle;
168
169         torture_comment(tctx, "Testing OpenPrinter(%s)\n", op.in.printername);
170
171         status = dcerpc_spoolss_OpenPrinter(p, tctx, &op);
172         torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_OpenPrinter failed");
173         torture_assert_werr_ok(tctx, op.out.result, "dcerpc_spoolss_OpenPrinter failed");
174
175         return true;
176 }
177
178 static bool test_EnumPorts(struct torture_context *tctx,
179                            struct dcerpc_pipe *p,
180                            struct test_spoolss_context *ctx)
181 {
182         NTSTATUS status;
183         struct spoolss_EnumPorts r;
184         uint16_t levels[] = { 1, 2 };
185         int i, j;
186
187         for (i=0;i<ARRAY_SIZE(levels);i++) {
188                 int level = levels[i];
189                 DATA_BLOB blob;
190                 uint32_t needed;
191                 uint32_t count;
192                 union spoolss_PortInfo *info;
193
194                 r.in.servername = "";
195                 r.in.level = level;
196                 r.in.buffer = NULL;
197                 r.in.offered = 0;
198                 r.out.needed = &needed;
199                 r.out.count = &count;
200                 r.out.info = &info;
201
202                 torture_comment(tctx, "Testing EnumPorts level %u\n", r.in.level);
203
204                 status = dcerpc_spoolss_EnumPorts(p, ctx, &r);
205                 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EnumPorts failed");
206                 if (W_ERROR_IS_OK(r.out.result)) {
207                         /* TODO: do some more checks here */
208                         continue;
209                 }
210                 torture_assert_werr_equal(tctx, r.out.result, WERR_INSUFFICIENT_BUFFER,
211                         "EnumPorts unexpected return code");
212
213                 blob = data_blob_talloc(ctx, NULL, needed);
214                 data_blob_clear(&blob);
215                 r.in.buffer = &blob;
216                 r.in.offered = needed;
217
218                 status = dcerpc_spoolss_EnumPorts(p, ctx, &r);
219                 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EnumPorts failed");
220
221                 torture_assert_werr_ok(tctx, r.out.result, "EnumPorts failed");
222
223                 torture_assert(tctx, info, "EnumPorts returned no info");
224
225                 CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumPorts, info, r.in.level, count, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
226
227                 ctx->port_count[level]  = count;
228                 ctx->ports[level]       = info;
229         }
230
231         for (i=1;i<ARRAY_SIZE(levels);i++) {
232                 int level = levels[i];
233                 int old_level = levels[i-1];
234                 torture_assert_int_equal(tctx, ctx->port_count[level], ctx->port_count[old_level],
235                         "EnumPorts invalid value");
236         }
237         /* if the array sizes are not the same we would maybe segfault in the following code */
238
239         for (i=0;i<ARRAY_SIZE(levels);i++) {
240                 int level = levels[i];
241                 for (j=0;j<ctx->port_count[level];j++) {
242                         union spoolss_PortInfo *cur = &ctx->ports[level][j];
243                         union spoolss_PortInfo *ref = &ctx->ports[2][j];
244                         switch (level) {
245                         case 1:
246                                 COMPARE_STRING(tctx, cur->info1, ref->info2, port_name);
247                                 break;
248                         case 2:
249                                 /* level 2 is our reference, and it makes no sense to compare it to itself */
250                                 break;
251                         }
252                 }
253         }
254
255         return true;
256 }
257
258 static bool test_GetPrintProcessorDirectory(struct torture_context *tctx,
259                                             struct dcerpc_pipe *p,
260                                             struct test_spoolss_context *ctx,
261                                             const char *environment)
262 {
263         NTSTATUS status;
264         struct spoolss_GetPrintProcessorDirectory r;
265         struct {
266                 uint16_t level;
267                 const char *server;
268         } levels[] = {{
269                         .level  = 1,
270                         .server = NULL
271                 },{
272                         .level  = 1,
273                         .server = ""
274                 },{
275                         .level  = 78,
276                         .server = ""
277                 },{
278                         .level  = 1,
279                         .server = talloc_asprintf(ctx, "\\\\%s", dcerpc_server_name(p))
280                 },{
281                         .level  = 1024,
282                         .server = talloc_asprintf(ctx, "\\\\%s", dcerpc_server_name(p))
283                 }
284         };
285         int i;
286         uint32_t needed;
287
288         for (i=0;i<ARRAY_SIZE(levels);i++) {
289                 int level = levels[i].level;
290                 DATA_BLOB blob;
291
292                 r.in.server             = levels[i].server;
293                 r.in.environment        = environment;
294                 r.in.level              = level;
295                 r.in.buffer             = NULL;
296                 r.in.offered            = 0;
297                 r.out.needed            = &needed;
298
299                 torture_comment(tctx, "Testing GetPrintProcessorDirectory level %u\n", r.in.level);
300
301                 status = dcerpc_spoolss_GetPrintProcessorDirectory(p, ctx, &r);
302                 torture_assert_ntstatus_ok(tctx, status,
303                         "dcerpc_spoolss_GetPrintProcessorDirectory failed");
304                 torture_assert_werr_equal(tctx, r.out.result, WERR_INSUFFICIENT_BUFFER,
305                         "GetPrintProcessorDirectory unexpected return code");
306
307                 blob = data_blob_talloc(ctx, NULL, needed);
308                 data_blob_clear(&blob);
309                 r.in.buffer = &blob;
310                 r.in.offered = needed;
311
312                 status = dcerpc_spoolss_GetPrintProcessorDirectory(p, ctx, &r);
313                 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_GetPrintProcessorDirectory failed");
314
315                 torture_assert_werr_ok(tctx, r.out.result, "GetPrintProcessorDirectory failed");
316
317                 CHECK_NEEDED_SIZE_LEVEL(spoolss_PrintProcessorDirectoryInfo, r.out.info, r.in.level, lp_iconv_convenience(tctx->lp_ctx), needed, 2);
318         }
319
320         return true;
321 }
322
323
324 static bool test_GetPrinterDriverDirectory(struct torture_context *tctx,
325                                            struct dcerpc_pipe *p,
326                                            struct test_spoolss_context *ctx,
327                                            const char *environment)
328 {
329         NTSTATUS status;
330         struct spoolss_GetPrinterDriverDirectory r;
331         struct {
332                 uint16_t level;
333                 const char *server;
334         } levels[] = {{
335                         .level  = 1,
336                         .server = NULL
337                 },{
338                         .level  = 1,
339                         .server = ""
340                 },{
341                         .level  = 78,
342                         .server = ""
343                 },{
344                         .level  = 1,
345                         .server = talloc_asprintf(ctx, "\\\\%s", dcerpc_server_name(p))
346                 },{
347                         .level  = 1024,
348                         .server = talloc_asprintf(ctx, "\\\\%s", dcerpc_server_name(p))
349                 }
350         };
351         int i;
352         uint32_t needed;
353
354         for (i=0;i<ARRAY_SIZE(levels);i++) {
355                 int level = levels[i].level;
356                 DATA_BLOB blob;
357
358                 r.in.server             = levels[i].server;
359                 r.in.environment        = environment;
360                 r.in.level              = level;
361                 r.in.buffer             = NULL;
362                 r.in.offered            = 0;
363                 r.out.needed            = &needed;
364
365                 torture_comment(tctx, "Testing GetPrinterDriverDirectory level %u\n", r.in.level);
366
367                 status = dcerpc_spoolss_GetPrinterDriverDirectory(p, ctx, &r);
368                 torture_assert_ntstatus_ok(tctx, status,
369                         "dcerpc_spoolss_GetPrinterDriverDirectory failed");
370                 torture_assert_werr_equal(tctx, r.out.result, WERR_INSUFFICIENT_BUFFER,
371                         "GetPrinterDriverDirectory unexpected return code");
372
373                 blob = data_blob_talloc(ctx, NULL, needed);
374                 data_blob_clear(&blob);
375                 r.in.buffer = &blob;
376                 r.in.offered = needed;
377
378                 status = dcerpc_spoolss_GetPrinterDriverDirectory(p, ctx, &r);
379                 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_GetPrinterDriverDirectory failed");
380
381                 torture_assert_werr_ok(tctx, r.out.result, "GetPrinterDriverDirectory failed");
382
383                 CHECK_NEEDED_SIZE_LEVEL(spoolss_DriverDirectoryInfo, r.out.info, r.in.level, lp_iconv_convenience(tctx->lp_ctx), needed, 2);
384         }
385
386         return true;
387 }
388
389 static bool test_EnumPrinterDrivers(struct torture_context *tctx,
390                                     struct dcerpc_pipe *p,
391                                     struct test_spoolss_context *ctx,
392                                     const char *architecture)
393 {
394         NTSTATUS status;
395         struct spoolss_EnumPrinterDrivers r;
396         uint16_t levels[] = { 1, 2, 3, 4, 5, 6, 8 };
397         int i, j;
398
399         for (i=0;i<ARRAY_SIZE(levels);i++) {
400                 int level = levels[i];
401                 DATA_BLOB blob;
402                 uint32_t needed;
403                 uint32_t count;
404                 union spoolss_DriverInfo *info;
405
406                 /* FIXME: gd, come back and fix "" as server, and handle
407                  * priority of returned error codes in torture test and samba 3
408                  * server */
409
410                 r.in.server             = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
411                 r.in.environment        = architecture;
412                 r.in.level              = level;
413                 r.in.buffer             = NULL;
414                 r.in.offered            = 0;
415                 r.out.needed            = &needed;
416                 r.out.count             = &count;
417                 r.out.info              = &info;
418
419                 torture_comment(tctx, "Testing EnumPrinterDrivers level %u (%s)\n", r.in.level, r.in.environment);
420
421                 status = dcerpc_spoolss_EnumPrinterDrivers(p, ctx, &r);
422                 torture_assert_ntstatus_ok(tctx, status,
423                                            "dcerpc_spoolss_EnumPrinterDrivers failed");
424                 if (W_ERROR_IS_OK(r.out.result)) {
425                         /* TODO: do some more checks here */
426                         continue;
427                 }
428                 if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
429                         blob = data_blob_talloc(ctx, NULL, needed);
430                         data_blob_clear(&blob);
431                         r.in.buffer = &blob;
432                         r.in.offered = needed;
433
434                         status = dcerpc_spoolss_EnumPrinterDrivers(p, ctx, &r);
435                         torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EnumPrinterDrivers failed");
436                 }
437
438                 torture_assert_werr_ok(tctx, r.out.result, "EnumPrinterDrivers failed");
439
440                 CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumPrinterDrivers, info, r.in.level, count, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
441
442                 ctx->driver_count[level]        = count;
443                 ctx->drivers[level]             = info;
444         }
445
446         for (i=1;i<ARRAY_SIZE(levels);i++) {
447                 int level = levels[i];
448                 int old_level = levels[i-1];
449
450                 torture_assert_int_equal(tctx, ctx->driver_count[level], ctx->driver_count[old_level],
451                         "EnumPrinterDrivers invalid value");
452         }
453
454         for (i=0;i<ARRAY_SIZE(levels);i++) {
455                 int level = levels[i];
456
457                 for (j=0;j<ctx->driver_count[level];j++) {
458                         union spoolss_DriverInfo *cur = &ctx->drivers[level][j];
459                         union spoolss_DriverInfo *ref = &ctx->drivers[8][j];
460
461                         switch (level) {
462                         case 1:
463                                 COMPARE_STRING(tctx, cur->info1, ref->info8, driver_name);
464                                 break;
465                         case 2:
466                                 COMPARE_UINT32(tctx, cur->info2, ref->info8, version);
467                                 COMPARE_STRING(tctx, cur->info2, ref->info8, driver_name);
468                                 COMPARE_STRING(tctx, cur->info2, ref->info8, architecture);
469                                 COMPARE_STRING(tctx, cur->info2, ref->info8, driver_path);
470                                 COMPARE_STRING(tctx, cur->info2, ref->info8, data_file);
471                                 COMPARE_STRING(tctx, cur->info2, ref->info8, config_file);
472                                 break;
473                         case 3:
474                                 COMPARE_UINT32(tctx, cur->info3, ref->info8, version);
475                                 COMPARE_STRING(tctx, cur->info3, ref->info8, driver_name);
476                                 COMPARE_STRING(tctx, cur->info3, ref->info8, architecture);
477                                 COMPARE_STRING(tctx, cur->info3, ref->info8, driver_path);
478                                 COMPARE_STRING(tctx, cur->info3, ref->info8, data_file);
479                                 COMPARE_STRING(tctx, cur->info3, ref->info8, config_file);
480                                 COMPARE_STRING(tctx, cur->info3, ref->info8, help_file);
481                                 COMPARE_STRING_ARRAY(tctx, cur->info3, ref->info8, dependent_files);
482                                 COMPARE_STRING(tctx, cur->info3, ref->info8, monitor_name);
483                                 COMPARE_STRING(tctx, cur->info3, ref->info8, default_datatype);
484                                 break;
485                         case 4:
486                                 COMPARE_UINT32(tctx, cur->info4, ref->info8, version);
487                                 COMPARE_STRING(tctx, cur->info4, ref->info8, driver_name);
488                                 COMPARE_STRING(tctx, cur->info4, ref->info8, architecture);
489                                 COMPARE_STRING(tctx, cur->info4, ref->info8, driver_path);
490                                 COMPARE_STRING(tctx, cur->info4, ref->info8, data_file);
491                                 COMPARE_STRING(tctx, cur->info4, ref->info8, config_file);
492                                 COMPARE_STRING(tctx, cur->info4, ref->info8, help_file);
493                                 COMPARE_STRING_ARRAY(tctx, cur->info4, ref->info8, dependent_files);
494                                 COMPARE_STRING(tctx, cur->info4, ref->info8, monitor_name);
495                                 COMPARE_STRING(tctx, cur->info4, ref->info8, default_datatype);
496                                 COMPARE_STRING_ARRAY(tctx, cur->info4, ref->info8, previous_names);
497                                 break;
498                         case 5:
499                                 COMPARE_UINT32(tctx, cur->info5, ref->info8, version);
500                                 COMPARE_STRING(tctx, cur->info5, ref->info8, driver_name);
501                                 COMPARE_STRING(tctx, cur->info5, ref->info8, architecture);
502                                 COMPARE_STRING(tctx, cur->info5, ref->info8, driver_path);
503                                 COMPARE_STRING(tctx, cur->info5, ref->info8, data_file);
504                                 COMPARE_STRING(tctx, cur->info5, ref->info8, config_file);
505                                 /*COMPARE_UINT32(tctx, cur->info5, ref->info8, driver_attributes);*/
506                                 /*COMPARE_UINT32(tctx, cur->info5, ref->info8, config_version);*/
507                                 /*TODO: ! COMPARE_UINT32(tctx, cur->info5, ref->info8, driver_version); */
508                                 break;
509                         case 6:
510                                 COMPARE_UINT32(tctx, cur->info6, ref->info8, version);
511                                 COMPARE_STRING(tctx, cur->info6, ref->info8, driver_name);
512                                 COMPARE_STRING(tctx, cur->info6, ref->info8, architecture);
513                                 COMPARE_STRING(tctx, cur->info6, ref->info8, driver_path);
514                                 COMPARE_STRING(tctx, cur->info6, ref->info8, data_file);
515                                 COMPARE_STRING(tctx, cur->info6, ref->info8, config_file);
516                                 COMPARE_STRING(tctx, cur->info6, ref->info8, help_file);
517                                 COMPARE_STRING_ARRAY(tctx, cur->info6, ref->info8, dependent_files);
518                                 COMPARE_STRING(tctx, cur->info6, ref->info8, monitor_name);
519                                 COMPARE_STRING(tctx, cur->info6, ref->info8, default_datatype);
520                                 COMPARE_STRING_ARRAY(tctx, cur->info6, ref->info8, previous_names);
521                                 COMPARE_NTTIME(tctx, cur->info6, ref->info8, driver_date);
522                                 COMPARE_UINT64(tctx, cur->info6, ref->info8, driver_version);
523                                 COMPARE_STRING(tctx, cur->info6, ref->info8, manufacturer_name);
524                                 COMPARE_STRING(tctx, cur->info6, ref->info8, manufacturer_url);
525                                 COMPARE_STRING(tctx, cur->info6, ref->info8, hardware_id);
526                                 COMPARE_STRING(tctx, cur->info6, ref->info8, provider);
527                                 break;
528                         case 8:
529                                 /* level 8 is our reference, and it makes no sense to compare it to itself */
530                                 break;
531                         }
532                 }
533         }
534
535         return true;
536 }
537
538 static bool test_EnumMonitors(struct torture_context *tctx,
539                               struct dcerpc_pipe *p,
540                               struct test_spoolss_context *ctx)
541 {
542         NTSTATUS status;
543         struct spoolss_EnumMonitors r;
544         uint16_t levels[] = { 1, 2 };
545         int i, j;
546
547         for (i=0;i<ARRAY_SIZE(levels);i++) {
548                 int level = levels[i];
549                 DATA_BLOB blob;
550                 uint32_t needed;
551                 uint32_t count;
552                 union spoolss_MonitorInfo *info;
553
554                 r.in.servername = "";
555                 r.in.level = level;
556                 r.in.buffer = NULL;
557                 r.in.offered = 0;
558                 r.out.needed = &needed;
559                 r.out.count = &count;
560                 r.out.info = &info;
561
562                 torture_comment(tctx, "Testing EnumMonitors level %u\n", r.in.level);
563
564                 status = dcerpc_spoolss_EnumMonitors(p, ctx, &r);
565                 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EnumMonitors failed");
566                 if (W_ERROR_IS_OK(r.out.result)) {
567                         /* TODO: do some more checks here */
568                         continue;
569                 }
570                 torture_assert_werr_equal(tctx, r.out.result, WERR_INSUFFICIENT_BUFFER,
571                         "EnumMonitors failed");
572
573                 blob = data_blob_talloc(ctx, NULL, needed);
574                 data_blob_clear(&blob);
575                 r.in.buffer = &blob;
576                 r.in.offered = needed;
577
578                 status = dcerpc_spoolss_EnumMonitors(p, ctx, &r);
579                 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EnumMonitors failed");
580
581                 torture_assert_werr_ok(tctx, r.out.result, "EnumMonitors failed");
582
583                 CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumMonitors, info, r.in.level, count, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
584
585                 ctx->monitor_count[level]       = count;
586                 ctx->monitors[level]            = info;
587         }
588
589         for (i=1;i<ARRAY_SIZE(levels);i++) {
590                 int level = levels[i];
591                 int old_level = levels[i-1];
592                 torture_assert_int_equal(tctx, ctx->monitor_count[level], ctx->monitor_count[old_level],
593                                          "EnumMonitors invalid value");
594         }
595
596         for (i=0;i<ARRAY_SIZE(levels);i++) {
597                 int level = levels[i];
598                 for (j=0;j<ctx->monitor_count[level];j++) {
599                         union spoolss_MonitorInfo *cur = &ctx->monitors[level][j];
600                         union spoolss_MonitorInfo *ref = &ctx->monitors[2][j];
601                         switch (level) {
602                         case 1:
603                                 COMPARE_STRING(tctx, cur->info1, ref->info2, monitor_name);
604                                 break;
605                         case 2:
606                                 /* level 2 is our reference, and it makes no sense to compare it to itself */
607                                 break;
608                         }
609                 }
610         }
611
612         return true;
613 }
614
615 static bool test_EnumPrintProcessors(struct torture_context *tctx,
616                                      struct dcerpc_pipe *p,
617                                      struct test_spoolss_context *ctx,
618                                      const char *environment)
619 {
620         NTSTATUS status;
621         struct spoolss_EnumPrintProcessors r;
622         uint16_t levels[] = { 1 };
623         int i, j;
624
625         for (i=0;i<ARRAY_SIZE(levels);i++) {
626                 int level = levels[i];
627                 DATA_BLOB blob;
628                 uint32_t needed;
629                 uint32_t count;
630                 union spoolss_PrintProcessorInfo *info;
631
632                 r.in.servername = "";
633                 r.in.environment = environment;
634                 r.in.level = level;
635                 r.in.buffer = NULL;
636                 r.in.offered = 0;
637                 r.out.needed = &needed;
638                 r.out.count = &count;
639                 r.out.info = &info;
640
641                 torture_comment(tctx, "Testing EnumPrintProcessors level %u\n", r.in.level);
642
643                 status = dcerpc_spoolss_EnumPrintProcessors(p, ctx, &r);
644                 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EnumPrintProcessors failed");
645                 if (W_ERROR_IS_OK(r.out.result)) {
646                         /* TODO: do some more checks here */
647                         continue;
648                 }
649                 torture_assert_werr_equal(tctx, r.out.result, WERR_INSUFFICIENT_BUFFER,
650                         "EnumPrintProcessors unexpected return code");
651
652                 blob = data_blob_talloc(ctx, NULL, needed);
653                 data_blob_clear(&blob);
654                 r.in.buffer = &blob;
655                 r.in.offered = needed;
656
657                 status = dcerpc_spoolss_EnumPrintProcessors(p, ctx, &r);
658                 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EnumPrintProcessors failed");
659
660                 torture_assert_werr_ok(tctx, r.out.result, "EnumPrintProcessors failed");
661
662                 CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumPrintProcessors, info, r.in.level, count, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
663
664                 ctx->print_processor_count[level]       = count;
665                 ctx->print_processors[level]            = info;
666         }
667
668         for (i=1;i<ARRAY_SIZE(levels);i++) {
669                 int level = levels[i];
670                 int old_level = levels[i-1];
671                 torture_assert_int_equal(tctx, ctx->print_processor_count[level], ctx->print_processor_count[old_level],
672                         "EnumPrintProcessors failed");
673         }
674
675         for (i=0;i<ARRAY_SIZE(levels);i++) {
676                 int level = levels[i];
677                 for (j=0;j<ctx->print_processor_count[level];j++) {
678 #if 0
679                         union spoolss_PrintProcessorInfo *cur = &ctx->print_processors[level][j];
680                         union spoolss_PrintProcessorInfo *ref = &ctx->print_processors[1][j];
681 #endif
682                         switch (level) {
683                         case 1:
684                                 /* level 1 is our reference, and it makes no sense to compare it to itself */
685                                 break;
686                         }
687                 }
688         }
689
690         return true;
691 }
692
693 static bool test_EnumPrintProcDataTypes(struct torture_context *tctx,
694                                         struct dcerpc_pipe *p,
695                                         struct test_spoolss_context *ctx)
696 {
697         NTSTATUS status;
698         struct spoolss_EnumPrintProcDataTypes r;
699         uint16_t levels[] = { 1 };
700         int i;
701
702         for (i=0;i<ARRAY_SIZE(levels);i++) {
703                 int level = levels[i];
704                 DATA_BLOB blob;
705                 uint32_t needed;
706                 uint32_t count;
707                 union spoolss_PrintProcDataTypesInfo *info;
708
709                 r.in.servername = "";
710                 r.in.print_processor_name = "winprint";
711                 r.in.level = level;
712                 r.in.buffer = NULL;
713                 r.in.offered = 0;
714                 r.out.needed = &needed;
715                 r.out.count = &count;
716                 r.out.info = &info;
717
718                 torture_comment(tctx, "Testing EnumPrintProcDataTypes level %u\n", r.in.level);
719
720                 status = dcerpc_spoolss_EnumPrintProcDataTypes(p, ctx, &r);
721                 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EnumPrintProcDataType failed");
722                 if (W_ERROR_IS_OK(r.out.result)) {
723                         /* TODO: do some more checks here */
724                         continue;
725                 }
726                 torture_assert_werr_equal(tctx, r.out.result, WERR_INSUFFICIENT_BUFFER,
727                         "EnumPrintProcDataTypes unexpected return code");
728
729                 blob = data_blob_talloc(ctx, NULL, needed);
730                 data_blob_clear(&blob);
731                 r.in.buffer = &blob;
732                 r.in.offered = needed;
733
734                 status = dcerpc_spoolss_EnumPrintProcDataTypes(p, ctx, &r);
735                 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EnumPrintProcDataTypes failed");
736
737                 torture_assert_werr_ok(tctx, r.out.result, "EnumPrintProcDataTypes failed");
738
739                 CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumPrintProcDataTypes, info, r.in.level, count, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
740
741         }
742
743         return true;
744 }
745
746
747 static bool test_EnumPrinters(struct torture_context *tctx,
748                               struct dcerpc_pipe *p,
749                               struct test_spoolss_context *ctx)
750 {
751         struct spoolss_EnumPrinters r;
752         NTSTATUS status;
753         uint16_t levels[] = { 0, 1, 2, 4, 5 };
754         int i, j;
755
756         for (i=0;i<ARRAY_SIZE(levels);i++) {
757                 int level = levels[i];
758                 DATA_BLOB blob;
759                 uint32_t needed;
760                 uint32_t count;
761                 union spoolss_PrinterInfo *info;
762
763                 r.in.flags      = PRINTER_ENUM_LOCAL;
764                 r.in.server     = "";
765                 r.in.level      = level;
766                 r.in.buffer     = NULL;
767                 r.in.offered    = 0;
768                 r.out.needed    = &needed;
769                 r.out.count     = &count;
770                 r.out.info      = &info;
771
772                 torture_comment(tctx, "Testing EnumPrinters level %u\n", r.in.level);
773
774                 status = dcerpc_spoolss_EnumPrinters(p, ctx, &r);
775                 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EnumPrinters failed");
776                 if (W_ERROR_IS_OK(r.out.result)) {
777                         /* TODO: do some more checks here */
778                         continue;
779                 }
780                 torture_assert_werr_equal(tctx, r.out.result, WERR_INSUFFICIENT_BUFFER,
781                         "EnumPrinters unexpected return code");
782
783                 blob = data_blob_talloc(ctx, NULL, needed);
784                 data_blob_clear(&blob);
785                 r.in.buffer = &blob;
786                 r.in.offered = needed;
787
788                 status = dcerpc_spoolss_EnumPrinters(p, ctx, &r);
789                 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EnumPrinters failed");
790
791                 torture_assert_werr_ok(tctx, r.out.result, "EnumPrinters failed");
792
793                 CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumPrinters, info, r.in.level, count, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
794
795                 ctx->printer_count[level]       = count;
796                 ctx->printers[level]            = info;
797         }
798
799         for (i=1;i<ARRAY_SIZE(levels);i++) {
800                 int level = levels[i];
801                 int old_level = levels[i-1];
802                 torture_assert_int_equal(tctx, ctx->printer_count[level], ctx->printer_count[old_level],
803                                          "EnumPrinters invalid value");
804         }
805
806         for (i=0;i<ARRAY_SIZE(levels);i++) {
807                 int level = levels[i];
808                 for (j=0;j<ctx->printer_count[level];j++) {
809                         union spoolss_PrinterInfo *cur = &ctx->printers[level][j];
810                         union spoolss_PrinterInfo *ref = &ctx->printers[2][j];
811                         switch (level) {
812                         case 0:
813                                 COMPARE_STRING(tctx, cur->info0, ref->info2, printername);
814                                 COMPARE_STRING(tctx, cur->info0, ref->info2, servername);
815                                 COMPARE_UINT32(tctx, cur->info0, ref->info2, cjobs);
816                                 /*COMPARE_UINT32(tctx, cur->info0, ref->info2, total_jobs);
817                                 COMPARE_UINT32(tctx, cur->info0, ref->info2, total_bytes);
818                                 COMPARE_SPOOLSS_TIME(cur->info0, ref->info2, spoolss_Time time);
819                                 COMPARE_UINT32(tctx, cur->info0, ref->info2, global_counter);
820                                 COMPARE_UINT32(tctx, cur->info0, ref->info2, total_pages);
821                                 COMPARE_UINT32(tctx, cur->info0, ref->info2, version);
822                                 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown10);
823                                 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown11);
824                                 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown12);
825                                 COMPARE_UINT32(tctx, cur->info0, ref->info2, session_counter);
826                                 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown14);
827                                 COMPARE_UINT32(tctx, cur->info0, ref->info2, printer_errors);
828                                 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown16);
829                                 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown17);
830                                 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown18);
831                                 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown19);
832                                 COMPARE_UINT32(tctx, cur->info0, ref->info2, change_id);
833                                 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown21);*/
834                                 COMPARE_UINT32(tctx, cur->info0, ref->info2, status);
835                                 /*COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown23);
836                                 COMPARE_UINT32(tctx, cur->info0, ref->info2, c_setprinter);
837                                 COMPARE_UINT16(cur->info0, ref->info2, unknown25);
838                                 COMPARE_UINT16(cur->info0, ref->info2, unknown26);
839                                 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown27);
840                                 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown28);
841                                 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown29);*/
842                                 break;
843                         case 1:
844                                 /*COMPARE_UINT32(tctx, cur->info1, ref->info2, flags);*/
845                                 /*COMPARE_STRING(tctx, cur->info1, ref->info2, name);*/
846                                 /*COMPARE_STRING(tctx, cur->info1, ref->info2, description);*/
847                                 COMPARE_STRING(tctx, cur->info1, ref->info2, comment);
848                                 break;
849                         case 2:
850                                 /* level 2 is our reference, and it makes no sense to compare it to itself */
851                                 break;
852                         case 4:
853                                 COMPARE_STRING(tctx, cur->info4, ref->info2, printername);
854                                 COMPARE_STRING(tctx, cur->info4, ref->info2, servername);
855                                 COMPARE_UINT32(tctx, cur->info4, ref->info2, attributes);
856                                 break;
857                         case 5:
858                                 COMPARE_STRING(tctx, cur->info5, ref->info2, printername);
859                                 COMPARE_STRING(tctx, cur->info5, ref->info2, portname);
860                                 COMPARE_UINT32(tctx, cur->info5, ref->info2, attributes);
861                                 /*COMPARE_UINT32(tctx, cur->info5, ref->info2, device_not_selected_timeout);
862                                 COMPARE_UINT32(tctx, cur->info5, ref->info2, transmission_retry_timeout);*/
863                                 break;
864                         }
865                 }
866         }
867
868         /* TODO:
869          *      - verify that the port of a printer was in the list returned by EnumPorts
870          */
871
872         return true;
873 }
874
875 static bool test_GetPrinterDriver2(struct torture_context *tctx,
876                                    struct dcerpc_pipe *p,
877                                    struct policy_handle *handle,
878                                    const char *driver_name,
879                                    const char *environment);
880
881 bool test_GetPrinter_level(struct torture_context *tctx,
882                            struct dcerpc_pipe *p,
883                            struct policy_handle *handle,
884                            uint32_t level,
885                            union spoolss_PrinterInfo *info)
886 {
887         struct spoolss_GetPrinter r;
888         uint32_t needed;
889
890         r.in.handle = handle;
891         r.in.level = level;
892         r.in.buffer = NULL;
893         r.in.offered = 0;
894         r.out.needed = &needed;
895
896         torture_comment(tctx, "Testing GetPrinter level %u\n", r.in.level);
897
898         torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_GetPrinter(p, tctx, &r),
899                 "GetPrinter failed");
900
901         if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
902                 DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed);
903                 data_blob_clear(&blob);
904                 r.in.buffer = &blob;
905                 r.in.offered = needed;
906
907                 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_GetPrinter(p, tctx, &r),
908                         "GetPrinter failed");
909         }
910
911         torture_assert_werr_ok(tctx, r.out.result, "GetPrinter failed");
912
913         CHECK_NEEDED_SIZE_LEVEL(spoolss_PrinterInfo, r.out.info, r.in.level, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
914
915         if (info && r.out.info) {
916                 *info = *r.out.info;
917         }
918
919         return true;
920 }
921
922
923 static bool test_GetPrinter(struct torture_context *tctx,
924                             struct dcerpc_pipe *p,
925                             struct policy_handle *handle,
926                             const char *environment)
927 {
928         uint32_t levels[] = {0, 1, 2, 3, 4, 5, 6, 7, 8};
929         int i;
930
931         for (i=0;i<ARRAY_SIZE(levels);i++) {
932
933                 union spoolss_PrinterInfo info;
934
935                 ZERO_STRUCT(info);
936
937                 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, levels[i], &info),
938                         "failed to call GetPrinter");
939
940                 if ((levels[i] == 2) && info.info2.drivername && strlen(info.info2.drivername)) {
941                         torture_assert(tctx,
942                                 test_GetPrinterDriver2(tctx, p, handle, info.info2.drivername, environment),
943                                 "failed to call test_GetPrinterDriver2");
944                 }
945         }
946
947         return true;
948 }
949
950 static bool test_SetPrinter(struct torture_context *tctx,
951                             struct dcerpc_pipe *p,
952                             struct policy_handle *handle,
953                             struct spoolss_SetPrinterInfoCtr *info_ctr,
954                             struct spoolss_DevmodeContainer *devmode_ctr,
955                             struct sec_desc_buf *secdesc_ctr,
956                             enum spoolss_PrinterControl command)
957 {
958         struct spoolss_SetPrinter r;
959
960         r.in.handle = handle;
961         r.in.info_ctr = info_ctr;
962         r.in.devmode_ctr = devmode_ctr;
963         r.in.secdesc_ctr = secdesc_ctr;
964         r.in.command = command;
965
966         torture_comment(tctx, "Testing SetPrinter level %d\n", r.in.info_ctr->level);
967
968         torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_SetPrinter(p, tctx, &r),
969                 "failed to call SetPrinter");
970         torture_assert_werr_ok(tctx, r.out.result,
971                 "failed to call SetPrinter");
972
973         return true;
974 }
975
976 static bool test_SetPrinter_errors(struct torture_context *tctx,
977                                    struct dcerpc_pipe *p,
978                                    struct policy_handle *handle)
979 {
980         struct spoolss_SetPrinter r;
981         uint16_t levels[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
982         int i;
983
984         struct spoolss_SetPrinterInfoCtr info_ctr;
985         struct spoolss_DevmodeContainer devmode_ctr;
986         struct sec_desc_buf secdesc_ctr;
987
988         info_ctr.level = 0;
989         info_ctr.info.info0 = NULL;
990
991         ZERO_STRUCT(devmode_ctr);
992         ZERO_STRUCT(secdesc_ctr);
993
994         r.in.handle = handle;
995         r.in.info_ctr = &info_ctr;
996         r.in.devmode_ctr = &devmode_ctr;
997         r.in.secdesc_ctr = &secdesc_ctr;
998         r.in.command = 0;
999
1000         torture_comment(tctx, "Testing SetPrinter all zero\n");
1001
1002         torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_SetPrinter(p, tctx, &r),
1003                 "failed to call SetPrinter");
1004         torture_assert_werr_equal(tctx, r.out.result, WERR_INVALID_PARAM,
1005                 "failed to call SetPrinter");
1006
1007  again:
1008         for (i=0; i < ARRAY_SIZE(levels); i++) {
1009
1010                 struct spoolss_SetPrinterInfo0 info0;
1011                 struct spoolss_SetPrinterInfo1 info1;
1012                 struct spoolss_SetPrinterInfo2 info2;
1013                 struct spoolss_SetPrinterInfo3 info3;
1014                 struct spoolss_SetPrinterInfo4 info4;
1015                 struct spoolss_SetPrinterInfo5 info5;
1016                 struct spoolss_SetPrinterInfo6 info6;
1017                 struct spoolss_SetPrinterInfo7 info7;
1018                 struct spoolss_SetPrinterInfo8 info8;
1019                 struct spoolss_SetPrinterInfo9 info9;
1020
1021
1022                 info_ctr.level = levels[i];
1023                 switch (levels[i]) {
1024                 case 0:
1025                         ZERO_STRUCT(info0);
1026                         info_ctr.info.info0 = &info0;
1027                         break;
1028                 case 1:
1029                         ZERO_STRUCT(info1);
1030                         info_ctr.info.info1 = &info1;
1031                         break;
1032                 case 2:
1033                         ZERO_STRUCT(info2);
1034                         info_ctr.info.info2 = &info2;
1035                         break;
1036                 case 3:
1037                         ZERO_STRUCT(info3);
1038                         info_ctr.info.info3 = &info3;
1039                         break;
1040                 case 4:
1041                         ZERO_STRUCT(info4);
1042                         info_ctr.info.info4 = &info4;
1043                         break;
1044                 case 5:
1045                         ZERO_STRUCT(info5);
1046                         info_ctr.info.info5 = &info5;
1047                         break;
1048                 case 6:
1049                         ZERO_STRUCT(info6);
1050                         info_ctr.info.info6 = &info6;
1051                         break;
1052                 case 7:
1053                         ZERO_STRUCT(info7);
1054                         info_ctr.info.info7 = &info7;
1055                         break;
1056                 case 8:
1057                         ZERO_STRUCT(info8);
1058                         info_ctr.info.info8 = &info8;
1059                         break;
1060                 case 9:
1061                         ZERO_STRUCT(info9);
1062                         info_ctr.info.info9 = &info9;
1063                         break;
1064                 }
1065
1066                 torture_comment(tctx, "Testing SetPrinter level %d, command %d\n",
1067                         info_ctr.level, r.in.command);
1068
1069                 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_SetPrinter(p, tctx, &r),
1070                         "failed to call SetPrinter");
1071
1072                 switch (r.in.command) {
1073                 case SPOOLSS_PRINTER_CONTROL_UNPAUSE: /* 0 */
1074                         /* is ignored for all levels other then 0 */
1075                         if (info_ctr.level > 0) {
1076                                 /* ignored then */
1077                                 break;
1078                         }
1079                 case SPOOLSS_PRINTER_CONTROL_PAUSE: /* 1 */
1080                 case SPOOLSS_PRINTER_CONTROL_RESUME: /* 2 */
1081                 case SPOOLSS_PRINTER_CONTROL_PURGE: /* 3 */
1082                         if (info_ctr.level > 0) {
1083                                 /* is invalid for all levels other then 0 */
1084                                 torture_assert_werr_equal(tctx, r.out.result, WERR_INVALID_PRINTER_COMMAND,
1085                                         "unexpected error code returned");
1086                                 continue;
1087                         } else {
1088                                 torture_assert_werr_ok(tctx, r.out.result,
1089                                         "failed to call SetPrinter with non 0 command");
1090                                 continue;
1091                         }
1092                         break;
1093
1094                 case SPOOLSS_PRINTER_CONTROL_SET_STATUS: /* 4 */
1095                         /* FIXME: gd needs further investigation */
1096                 default:
1097                         torture_assert_werr_equal(tctx, r.out.result, WERR_INVALID_PRINTER_COMMAND,
1098                                 "unexpected error code returned");
1099                         continue;
1100                 }
1101
1102                 switch (info_ctr.level) {
1103                 case 1:
1104                         torture_assert_werr_equal(tctx, r.out.result, WERR_UNKNOWN_LEVEL,
1105                                 "unexpected error code returned");
1106                         break;
1107                 case 2:
1108                         torture_assert_werr_equal(tctx, r.out.result, WERR_UNKNOWN_PRINTER_DRIVER,
1109                                 "unexpected error code returned");
1110                         break;
1111                 case 3:
1112                 case 4:
1113                 case 5:
1114                 case 7:
1115                         torture_assert_werr_equal(tctx, r.out.result, WERR_INVALID_PARAM,
1116                                 "unexpected error code returned");
1117                         break;
1118                 case 9:
1119                         torture_assert_werr_equal(tctx, r.out.result, WERR_NOT_SUPPORTED,
1120                                 "unexpected error code returned");
1121                         break;
1122                 default:
1123                         torture_assert_werr_ok(tctx, r.out.result,
1124                                 "failed to call SetPrinter");
1125                         break;
1126                 }
1127         }
1128
1129         if (r.in.command < 5) {
1130                 r.in.command++;
1131                 goto again;
1132         }
1133
1134         return true;
1135 }
1136
1137 static void clear_info2(struct spoolss_SetPrinterInfoCtr *r)
1138 {
1139         if ((r->level == 2) && (r->info.info2)) {
1140                 r->info.info2->secdesc_ptr = 0;
1141                 r->info.info2->devmode_ptr = 0;
1142         }
1143 }
1144
1145 static bool test_PrinterInfo(struct torture_context *tctx,
1146                              struct dcerpc_pipe *p,
1147                              struct policy_handle *handle)
1148 {
1149         NTSTATUS status;
1150         struct spoolss_SetPrinter s;
1151         struct spoolss_GetPrinter q;
1152         struct spoolss_GetPrinter q0;
1153         struct spoolss_SetPrinterInfoCtr info_ctr;
1154         union spoolss_PrinterInfo info;
1155         struct spoolss_DevmodeContainer devmode_ctr;
1156         struct sec_desc_buf secdesc_ctr;
1157         uint32_t needed;
1158         bool ret = true;
1159         int i;
1160
1161         uint32_t status_list[] = {
1162                 /* these do not stick
1163                 PRINTER_STATUS_PAUSED,
1164                 PRINTER_STATUS_ERROR,
1165                 PRINTER_STATUS_PENDING_DELETION, */
1166                 PRINTER_STATUS_PAPER_JAM,
1167                 PRINTER_STATUS_PAPER_OUT,
1168                 PRINTER_STATUS_MANUAL_FEED,
1169                 PRINTER_STATUS_PAPER_PROBLEM,
1170                 PRINTER_STATUS_OFFLINE,
1171                 PRINTER_STATUS_IO_ACTIVE,
1172                 PRINTER_STATUS_BUSY,
1173                 PRINTER_STATUS_PRINTING,
1174                 PRINTER_STATUS_OUTPUT_BIN_FULL,
1175                 PRINTER_STATUS_NOT_AVAILABLE,
1176                 PRINTER_STATUS_WAITING,
1177                 PRINTER_STATUS_PROCESSING,
1178                 PRINTER_STATUS_INITIALIZING,
1179                 PRINTER_STATUS_WARMING_UP,
1180                 PRINTER_STATUS_TONER_LOW,
1181                 PRINTER_STATUS_NO_TONER,
1182                 PRINTER_STATUS_PAGE_PUNT,
1183                 PRINTER_STATUS_USER_INTERVENTION,
1184                 PRINTER_STATUS_OUT_OF_MEMORY,
1185                 PRINTER_STATUS_DOOR_OPEN,
1186                 PRINTER_STATUS_SERVER_UNKNOWN,
1187                 PRINTER_STATUS_POWER_SAVE,
1188                 /* these do not stick
1189                 0x02000000,
1190                 0x04000000,
1191                 0x08000000,
1192                 0x10000000,
1193                 0x20000000,
1194                 0x40000000,
1195                 0x80000000 */
1196         };
1197         uint32_t default_attribute = PRINTER_ATTRIBUTE_LOCAL;
1198         uint32_t attribute_list[] = {
1199                 PRINTER_ATTRIBUTE_QUEUED,
1200                 /* fails with WERR_INVALID_DATATYPE:
1201                 PRINTER_ATTRIBUTE_DIRECT, */
1202                 /* does not stick
1203                 PRINTER_ATTRIBUTE_DEFAULT, */
1204                 PRINTER_ATTRIBUTE_SHARED,
1205                 /* does not stick
1206                 PRINTER_ATTRIBUTE_NETWORK, */
1207                 PRINTER_ATTRIBUTE_HIDDEN,
1208                 PRINTER_ATTRIBUTE_LOCAL,
1209                 PRINTER_ATTRIBUTE_ENABLE_DEVQ,
1210                 PRINTER_ATTRIBUTE_KEEPPRINTEDJOBS,
1211                 PRINTER_ATTRIBUTE_DO_COMPLETE_FIRST,
1212                 PRINTER_ATTRIBUTE_WORK_OFFLINE,
1213                 /* does not stick
1214                 PRINTER_ATTRIBUTE_ENABLE_BIDI, */
1215                 /* fails with WERR_INVALID_DATATYPE:
1216                 PRINTER_ATTRIBUTE_RAW_ONLY, */
1217                 /* these do not stick
1218                 PRINTER_ATTRIBUTE_PUBLISHED,
1219                 PRINTER_ATTRIBUTE_FAX,
1220                 PRINTER_ATTRIBUTE_TS,
1221                 0x00010000,
1222                 0x00020000,
1223                 0x00040000,
1224                 0x00080000,
1225                 0x00100000,
1226                 0x00200000,
1227                 0x00400000,
1228                 0x00800000,
1229                 0x01000000,
1230                 0x02000000,
1231                 0x04000000,
1232                 0x08000000,
1233                 0x10000000,
1234                 0x20000000,
1235                 0x40000000,
1236                 0x80000000 */
1237         };
1238
1239         ZERO_STRUCT(devmode_ctr);
1240         ZERO_STRUCT(secdesc_ctr);
1241
1242         s.in.handle = handle;
1243         s.in.command = 0;
1244         s.in.info_ctr = &info_ctr;
1245         s.in.devmode_ctr = &devmode_ctr;
1246         s.in.secdesc_ctr = &secdesc_ctr;
1247
1248         q.in.handle = handle;
1249         q.out.info = &info;
1250         q0 = q;
1251
1252 #define TESTGETCALL(call, r) \
1253                 r.in.buffer = NULL; \
1254                 r.in.offered = 0;\
1255                 r.out.needed = &needed; \
1256                 status = dcerpc_spoolss_ ##call(p, tctx, &r); \
1257                 if (!NT_STATUS_IS_OK(status)) { \
1258                         torture_comment(tctx, #call " level %u failed - %s (%s)\n", \
1259                                r.in.level, nt_errstr(status), __location__); \
1260                         ret = false; \
1261                         break; \
1262                 }\
1263                 if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {\
1264                         DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed); \
1265                         data_blob_clear(&blob); \
1266                         r.in.buffer = &blob; \
1267                         r.in.offered = needed; \
1268                 }\
1269                 status = dcerpc_spoolss_ ##call(p, tctx, &r); \
1270                 if (!NT_STATUS_IS_OK(status)) { \
1271                         torture_comment(tctx, #call " level %u failed - %s (%s)\n", \
1272                                r.in.level, nt_errstr(status), __location__); \
1273                         ret = false; \
1274                         break; \
1275                 } \
1276                 if (!W_ERROR_IS_OK(r.out.result)) { \
1277                         torture_comment(tctx, #call " level %u failed - %s (%s)\n", \
1278                                r.in.level, win_errstr(r.out.result), __location__); \
1279                         ret = false; \
1280                         break; \
1281                 }
1282
1283
1284 #define TESTSETCALL_EXP(call, r, err) \
1285                 clear_info2(&info_ctr);\
1286                 status = dcerpc_spoolss_ ##call(p, tctx, &r); \
1287                 if (!NT_STATUS_IS_OK(status)) { \
1288                         torture_comment(tctx, #call " level %u failed - %s (%s)\n", \
1289                                r.in.info_ctr->level, nt_errstr(status), __location__); \
1290                         ret = false; \
1291                         break; \
1292                 } \
1293                 if (!W_ERROR_IS_OK(err)) { \
1294                         if (!W_ERROR_EQUAL(err, r.out.result)) { \
1295                                 torture_comment(tctx, #call " level %u failed - %s, expected %s (%s)\n", \
1296                                        r.in.info_ctr->level, win_errstr(r.out.result), win_errstr(err), __location__); \
1297                                 ret = false; \
1298                         } \
1299                         break; \
1300                 } \
1301                 if (!W_ERROR_IS_OK(r.out.result)) { \
1302                         torture_comment(tctx, #call " level %u failed - %s (%s)\n", \
1303                                r.in.info_ctr->level, win_errstr(r.out.result), __location__); \
1304                         ret = false; \
1305                         break; \
1306                 }
1307
1308 #define TESTSETCALL(call, r) \
1309         TESTSETCALL_EXP(call, r, WERR_OK)
1310
1311 #define STRING_EQUAL(s1, s2, field) \
1312                 if ((s1 && !s2) || (s2 && !s1) || strcmp(s1, s2)) { \
1313                         torture_comment(tctx, "Failed to set %s to '%s' (%s)\n", \
1314                                #field, s2, __location__); \
1315                         ret = false; \
1316                         break; \
1317                 }
1318
1319 #define MEM_EQUAL(s1, s2, length, field) \
1320                 if ((s1 && !s2) || (s2 && !s1) || memcmp(s1, s2, length)) { \
1321                         torture_comment(tctx, "Failed to set %s to '%s' (%s)\n", \
1322                                #field, (const char *)s2, __location__); \
1323                         ret = false; \
1324                         break; \
1325                 }
1326
1327 #define INT_EQUAL(i1, i2, field) \
1328                 if (i1 != i2) { \
1329                         torture_comment(tctx, "Failed to set %s to 0x%llx - got 0x%llx (%s)\n", \
1330                                #field, (unsigned long long)i2, (unsigned long long)i1, __location__); \
1331                         ret = false; \
1332                         break; \
1333                 }
1334
1335 #define SD_EQUAL(sd1, sd2, field) \
1336                 if (!security_descriptor_equal(sd1, sd2)) { \
1337                         torture_comment(tctx, "Failed to set %s (%s)\n", \
1338                                #field, __location__); \
1339                         ret = false; \
1340                         break; \
1341                 }
1342
1343 #define TEST_PRINTERINFO_STRING_EXP_ERR(lvl1, field1, lvl2, field2, value, err) do { \
1344                 torture_comment(tctx, "field test %d/%s vs %d/%s\n", lvl1, #field1, lvl2, #field2); \
1345                 q.in.level = lvl1; \
1346                 TESTGETCALL(GetPrinter, q) \
1347                 info_ctr.level = lvl1; \
1348                 info_ctr.info.info ## lvl1 = (struct spoolss_SetPrinterInfo ## lvl1 *)&q.out.info->info ## lvl1; \
1349                 info_ctr.info.info ## lvl1->field1 = value;\
1350                 TESTSETCALL_EXP(SetPrinter, s, err) \
1351                 info_ctr.info.info ## lvl1->field1 = ""; \
1352                 TESTGETCALL(GetPrinter, q) \
1353                 info_ctr.info.info ## lvl1->field1 = value; \
1354                 STRING_EQUAL(info_ctr.info.info ## lvl1->field1, value, field1); \
1355                 q.in.level = lvl2; \
1356                 TESTGETCALL(GetPrinter, q) \
1357                 info_ctr.info.info ## lvl2 = (struct spoolss_SetPrinterInfo ## lvl2 *)&q.out.info->info ## lvl2; \
1358                 STRING_EQUAL(info_ctr.info.info ## lvl2->field2, value, field2); \
1359         } while (0)
1360
1361 #define TEST_PRINTERINFO_STRING(lvl1, field1, lvl2, field2, value) do { \
1362         TEST_PRINTERINFO_STRING_EXP_ERR(lvl1, field1, lvl2, field2, value, WERR_OK); \
1363         } while (0);
1364
1365 #define TEST_PRINTERINFO_INT_EXP(lvl1, field1, lvl2, field2, value, exp_value) do { \
1366                 torture_comment(tctx, "field test %d/%s vs %d/%s\n", lvl1, #field1, lvl2, #field2); \
1367                 q.in.level = lvl1; \
1368                 TESTGETCALL(GetPrinter, q) \
1369                 info_ctr.level = lvl1; \
1370                 info_ctr.info.info ## lvl1 = (struct spoolss_SetPrinterInfo ## lvl1 *)&q.out.info->info ## lvl1; \
1371                 info_ctr.info.info ## lvl1->field1 = value; \
1372                 TESTSETCALL(SetPrinter, s) \
1373                 info_ctr.info.info ## lvl1->field1 = 0; \
1374                 TESTGETCALL(GetPrinter, q) \
1375                 info_ctr.info.info ## lvl1 = (struct spoolss_SetPrinterInfo ## lvl1 *)&q.out.info->info ## lvl1; \
1376                 INT_EQUAL(info_ctr.info.info ## lvl1->field1, exp_value, field1); \
1377                 q.in.level = lvl2; \
1378                 TESTGETCALL(GetPrinter, q) \
1379                 info_ctr.info.info ## lvl2 = (struct spoolss_SetPrinterInfo ## lvl2 *)&q.out.info->info ## lvl2; \
1380                 INT_EQUAL(info_ctr.info.info ## lvl2->field2, exp_value, field1); \
1381         } while (0)
1382
1383 #define TEST_PRINTERINFO_INT(lvl1, field1, lvl2, field2, value) do { \
1384         TEST_PRINTERINFO_INT_EXP(lvl1, field1, lvl2, field2, value, value); \
1385         } while (0)
1386
1387         q0.in.level = 0;
1388         do { TESTGETCALL(GetPrinter, q0) } while (0);
1389
1390         TEST_PRINTERINFO_STRING(2, comment,  1, comment, "xx2-1 comment");
1391         TEST_PRINTERINFO_STRING(2, comment,  2, comment, "xx2-2 comment");
1392
1393         /* level 0 printername does not stick */
1394 /*      TEST_PRINTERINFO_STRING(2, printername,  0, printername, "xx2-0 printer"); */
1395         TEST_PRINTERINFO_STRING(2, printername,  1, name,        "xx2-1 printer");
1396         TEST_PRINTERINFO_STRING(2, printername,  2, printername, "xx2-2 printer");
1397         TEST_PRINTERINFO_STRING(2, printername,  4, printername, "xx2-4 printer");
1398         TEST_PRINTERINFO_STRING(2, printername,  5, printername, "xx2-5 printer");
1399 /*      TEST_PRINTERINFO_STRING(4, printername,  0, printername, "xx4-0 printer"); */
1400         TEST_PRINTERINFO_STRING(4, printername,  1, name,        "xx4-1 printer");
1401         TEST_PRINTERINFO_STRING(4, printername,  2, printername, "xx4-2 printer");
1402         TEST_PRINTERINFO_STRING(4, printername,  4, printername, "xx4-4 printer");
1403         TEST_PRINTERINFO_STRING(4, printername,  5, printername, "xx4-5 printer");
1404 /*      TEST_PRINTERINFO_STRING(5, printername,  0, printername, "xx5-0 printer"); */
1405         TEST_PRINTERINFO_STRING(5, printername,  1, name,        "xx5-1 printer");
1406         TEST_PRINTERINFO_STRING(5, printername,  2, printername, "xx5-2 printer");
1407         TEST_PRINTERINFO_STRING(5, printername,  4, printername, "xx5-4 printer");
1408         TEST_PRINTERINFO_STRING(5, printername,  5, printername, "xx5-5 printer");
1409
1410         /* servername can be set but does not stick
1411         TEST_PRINTERINFO_STRING(2, servername,  0, servername, "xx2-0 servername");
1412         TEST_PRINTERINFO_STRING(2, servername,  2, servername, "xx2-2 servername");
1413         TEST_PRINTERINFO_STRING(2, servername,  4, servername, "xx2-4 servername");
1414         */
1415
1416         /* passing an invalid port will result in WERR_UNKNOWN_PORT */
1417         TEST_PRINTERINFO_STRING_EXP_ERR(2, portname,  2, portname, "xx2-2 portname", WERR_UNKNOWN_PORT);
1418         TEST_PRINTERINFO_STRING_EXP_ERR(2, portname,  5, portname, "xx2-5 portname", WERR_UNKNOWN_PORT);
1419         TEST_PRINTERINFO_STRING_EXP_ERR(5, portname,  2, portname, "xx5-2 portname", WERR_UNKNOWN_PORT);
1420         TEST_PRINTERINFO_STRING_EXP_ERR(5, portname,  5, portname, "xx5-5 portname", WERR_UNKNOWN_PORT);
1421
1422         TEST_PRINTERINFO_STRING(2, sharename,   2, sharename,   "xx2-2 sharename");
1423         /* passing an invalid driver will result in WERR_UNKNOWN_PRINTER_DRIVER */
1424         TEST_PRINTERINFO_STRING_EXP_ERR(2, drivername,  2, drivername,  "xx2-2 drivername", WERR_UNKNOWN_PRINTER_DRIVER);
1425         TEST_PRINTERINFO_STRING(2, location,    2, location,    "xx2-2 location");
1426         /* passing an invalid sepfile will result in WERR_INVALID_SEPARATOR_FILE */
1427         TEST_PRINTERINFO_STRING_EXP_ERR(2, sepfile,     2, sepfile,     "xx2-2 sepfile", WERR_INVALID_SEPARATOR_FILE);
1428         /* passing an invalid printprocessor will result in WERR_UNKNOWN_PRINTPROCESSOR */
1429         TEST_PRINTERINFO_STRING_EXP_ERR(2, printprocessor, 2, printprocessor, "xx2-2 printprocessor", WERR_UNKNOWN_PRINTPROCESSOR);
1430         TEST_PRINTERINFO_STRING(2, datatype,    2, datatype,    "xx2-2 datatype");
1431         TEST_PRINTERINFO_STRING(2, parameters,  2, parameters,  "xx2-2 parameters");
1432
1433         for (i=0; i < ARRAY_SIZE(attribute_list); i++) {
1434 /*              TEST_PRINTERINFO_INT_EXP(2, attributes, 1, flags,
1435                         attribute_list[i],
1436                         (attribute_list[i] | default_attribute)
1437                         ); */
1438                 TEST_PRINTERINFO_INT_EXP(2, attributes, 2, attributes,
1439                         attribute_list[i],
1440                         (attribute_list[i] | default_attribute)
1441                         );
1442                 TEST_PRINTERINFO_INT_EXP(2, attributes, 4, attributes,
1443                         attribute_list[i],
1444                         (attribute_list[i] | default_attribute)
1445                         );
1446                 TEST_PRINTERINFO_INT_EXP(2, attributes, 5, attributes,
1447                         attribute_list[i],
1448                         (attribute_list[i] | default_attribute)
1449                         );
1450 /*              TEST_PRINTERINFO_INT_EXP(4, attributes, 1, flags,
1451                         attribute_list[i],
1452                         (attribute_list[i] | default_attribute)
1453                         ); */
1454                 TEST_PRINTERINFO_INT_EXP(4, attributes, 2, attributes,
1455                         attribute_list[i],
1456                         (attribute_list[i] | default_attribute)
1457                         );
1458                 TEST_PRINTERINFO_INT_EXP(4, attributes, 4, attributes,
1459                         attribute_list[i],
1460                         (attribute_list[i] | default_attribute)
1461                         );
1462                 TEST_PRINTERINFO_INT_EXP(4, attributes, 5, attributes,
1463                         attribute_list[i],
1464                         (attribute_list[i] | default_attribute)
1465                         );
1466 /*              TEST_PRINTERINFO_INT_EXP(5, attributes, 1, flags,
1467                         attribute_list[i],
1468                         (attribute_list[i] | default_attribute)
1469                         ); */
1470                 TEST_PRINTERINFO_INT_EXP(5, attributes, 2, attributes,
1471                         attribute_list[i],
1472                         (attribute_list[i] | default_attribute)
1473                         );
1474                 TEST_PRINTERINFO_INT_EXP(5, attributes, 4, attributes,
1475                         attribute_list[i],
1476                         (attribute_list[i] | default_attribute)
1477                         );
1478                 TEST_PRINTERINFO_INT_EXP(5, attributes, 5, attributes,
1479                         attribute_list[i],
1480                         (attribute_list[i] | default_attribute)
1481                         );
1482         }
1483
1484         for (i=0; i < ARRAY_SIZE(status_list); i++) {
1485                 /* level 2 sets do not stick
1486                 TEST_PRINTERINFO_INT(2, status, 0, status, status_list[i]);
1487                 TEST_PRINTERINFO_INT(2, status, 2, status, status_list[i]);
1488                 TEST_PRINTERINFO_INT(2, status, 6, status, status_list[i]); */
1489                 TEST_PRINTERINFO_INT(6, status, 0, status, status_list[i]);
1490                 TEST_PRINTERINFO_INT(6, status, 2, status, status_list[i]);
1491                 TEST_PRINTERINFO_INT(6, status, 6, status, status_list[i]);
1492         }
1493
1494         /* priorities need to be between 0 and 99
1495            passing an invalid priority will result in WERR_INVALID_PRIORITY */
1496         TEST_PRINTERINFO_INT(2, priority,       2, priority, 0);
1497         TEST_PRINTERINFO_INT(2, priority,       2, priority, 1);
1498         TEST_PRINTERINFO_INT(2, priority,       2, priority, 99);
1499         /* TEST_PRINTERINFO_INT(2, priority,    2, priority, 100); */
1500         TEST_PRINTERINFO_INT(2, defaultpriority,2, defaultpriority, 0);
1501         TEST_PRINTERINFO_INT(2, defaultpriority,2, defaultpriority, 1);
1502         TEST_PRINTERINFO_INT(2, defaultpriority,2, defaultpriority, 99);
1503         /* TEST_PRINTERINFO_INT(2, defaultpriority,2, defaultpriority, 100); */
1504
1505         TEST_PRINTERINFO_INT(2, starttime,      2, starttime, __LINE__);
1506         TEST_PRINTERINFO_INT(2, untiltime,      2, untiltime, __LINE__);
1507
1508         /* does not stick
1509         TEST_PRINTERINFO_INT(2, cjobs,          2, cjobs, __LINE__);
1510         TEST_PRINTERINFO_INT(2, averageppm,     2, averageppm, __LINE__); */
1511
1512         /* does not stick
1513         TEST_PRINTERINFO_INT(5, device_not_selected_timeout, 5, device_not_selected_timeout, __LINE__);
1514         TEST_PRINTERINFO_INT(5, transmission_retry_timeout, 5, transmission_retry_timeout, __LINE__); */
1515
1516         /* FIXME: gd also test devmode and secdesc behavior */
1517
1518         {
1519                 /* verify composition of level 1 description field */
1520                 const char *description;
1521                 const char *tmp;
1522
1523                 q0.in.level = 1;
1524                 do { TESTGETCALL(GetPrinter, q0) } while (0);
1525
1526                 description = talloc_strdup(tctx, q0.out.info->info1.description);
1527
1528                 q0.in.level = 2;
1529                 do { TESTGETCALL(GetPrinter, q0) } while (0);
1530
1531                 tmp = talloc_asprintf(tctx, "%s,%s,%s",
1532                         q0.out.info->info2.printername,
1533                         q0.out.info->info2.drivername,
1534                         q0.out.info->info2.location);
1535
1536                 do { STRING_EQUAL(description, tmp, "description")} while (0);
1537         }
1538
1539         return ret;
1540 }
1541
1542 #define torture_assert_sid_equal(torture_ctx,got,expected,cmt)\
1543         do { struct dom_sid *__got = (got), *__expected = (expected); \
1544         if (!dom_sid_equal(__got, __expected)) { \
1545                 torture_result(torture_ctx, TORTURE_FAIL, \
1546                                            __location__": "#got" was %s, expected %s: %s", \
1547                                            dom_sid_string(torture_ctx, __got), dom_sid_string(torture_ctx, __expected), cmt); \
1548                 return false; \
1549         } \
1550         } while(0)
1551
1552 static bool test_security_descriptor_equal(struct torture_context *tctx,
1553                                            const struct security_descriptor *sd1,
1554                                            const struct security_descriptor *sd2)
1555 {
1556         if (sd1 == sd2) {
1557                 return true;
1558         }
1559
1560         if (!sd1 || !sd2) {
1561                 torture_comment(tctx, "%s\n", __location__);
1562                 return false;
1563         }
1564
1565         torture_assert_int_equal(tctx, sd1->revision, sd2->revision, "revision mismatch");
1566         torture_assert_int_equal(tctx, sd1->type, sd2->type, "type mismatch");
1567
1568         torture_assert_sid_equal(tctx, sd1->owner_sid, sd2->owner_sid, "owner mismatch");
1569         torture_assert_sid_equal(tctx, sd1->group_sid, sd2->group_sid, "group mismatch");
1570
1571         if (!security_acl_equal(sd1->sacl, sd2->sacl)) {
1572                 torture_comment(tctx, "%s: sacl mismatch\n", __location__);
1573                 NDR_PRINT_DEBUG(security_acl, sd1->sacl);
1574                 NDR_PRINT_DEBUG(security_acl, sd2->sacl);
1575                 return false;
1576         }
1577         if (!security_acl_equal(sd1->dacl, sd2->dacl)) {
1578                 torture_comment(tctx, "%s: dacl mismatch\n", __location__);
1579                 NDR_PRINT_DEBUG(security_acl, sd1->dacl);
1580                 NDR_PRINT_DEBUG(security_acl, sd2->dacl);
1581                 return false;
1582         }
1583
1584         return true;
1585 }
1586
1587 static bool test_sd_set_level(struct torture_context *tctx,
1588                               struct dcerpc_pipe *p,
1589                               struct policy_handle *handle,
1590                               uint32_t level,
1591                               struct security_descriptor *sd)
1592 {
1593         struct spoolss_SetPrinterInfoCtr info_ctr;
1594         struct spoolss_DevmodeContainer devmode_ctr;
1595         struct sec_desc_buf secdesc_ctr;
1596
1597         ZERO_STRUCT(devmode_ctr);
1598         ZERO_STRUCT(secdesc_ctr);
1599
1600         switch (level) {
1601         case 2: {
1602                 union spoolss_PrinterInfo info;
1603                 struct spoolss_SetPrinterInfo2 info2;
1604                 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 2, &info), "");
1605
1606                 info2.servername        = info.info2.servername;
1607                 info2.printername       = info.info2.printername;
1608                 info2.sharename         = info.info2.sharename;
1609                 info2.portname          = info.info2.portname;
1610                 info2.drivername        = info.info2.drivername;
1611                 info2.comment           = info.info2.comment;
1612                 info2.location          = info.info2.location;
1613                 info2.devmode_ptr       = 0;
1614                 info2.sepfile           = info.info2.sepfile;
1615                 info2.printprocessor    = info.info2.printprocessor;
1616                 info2.datatype          = info.info2.datatype;
1617                 info2.parameters        = info.info2.parameters;
1618                 info2.secdesc_ptr       = 0;
1619                 info2.attributes        = info.info2.attributes;
1620                 info2.priority          = info.info2.priority;
1621                 info2.defaultpriority   = info.info2.defaultpriority;
1622                 info2.starttime         = info.info2.starttime;
1623                 info2.untiltime         = info.info2.untiltime;
1624                 info2.status            = info.info2.status;
1625                 info2.cjobs             = info.info2.cjobs;
1626                 info2.averageppm        = info.info2.averageppm;
1627
1628                 info_ctr.level = 2;
1629                 info_ctr.info.info2 = &info2;
1630
1631                 break;
1632         }
1633         case 3: {
1634                 struct spoolss_SetPrinterInfo3 info3;
1635
1636                 info3.sec_desc_ptr = 0;
1637
1638                 info_ctr.level = 3;
1639                 info_ctr.info.info3 = &info3;
1640
1641                 break;
1642         }
1643         default:
1644                 return false;
1645         }
1646
1647         secdesc_ctr.sd = sd;
1648
1649         torture_assert(tctx,
1650                 test_SetPrinter(tctx, p, handle, &info_ctr, &devmode_ctr, &secdesc_ctr, 0), "");
1651
1652         return true;
1653 }
1654
1655 static bool test_PrinterInfo_SDs(struct torture_context *tctx,
1656                                  struct dcerpc_pipe *p,
1657                                  struct policy_handle *handle)
1658 {
1659         union spoolss_PrinterInfo info;
1660         struct security_descriptor *sd1, *sd2;
1661         int i;
1662
1663         /* just compare level 2 and level 3 */
1664
1665         torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 2, &info), "");
1666
1667         sd1 = info.info2.secdesc;
1668
1669         torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 3, &info), "");
1670
1671         sd2 = info.info3.secdesc;
1672
1673         torture_assert(tctx, test_security_descriptor_equal(tctx, sd1, sd2),
1674                 "SD level 2 != SD level 3");
1675
1676
1677         /* query level 2, set level 2, query level 2 */
1678
1679         torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 2, &info), "");
1680
1681         sd1 = info.info2.secdesc;
1682
1683         torture_assert(tctx, test_sd_set_level(tctx, p, handle, 2, sd1), "");
1684
1685         torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 2, &info), "");
1686
1687         sd2 = info.info2.secdesc;
1688         if (sd1->type & SEC_DESC_DACL_DEFAULTED) {
1689                 torture_comment(tctx, "removing SEC_DESC_DACL_DEFAULTED\n");
1690                 sd1->type &= ~SEC_DESC_DACL_DEFAULTED;
1691         }
1692
1693         torture_assert(tctx, test_security_descriptor_equal(tctx, sd1, sd2),
1694                 "SD level 2 != SD level 2 after SD has been set via level 2");
1695
1696
1697         /* query level 2, set level 3, query level 2 */
1698
1699         torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 2, &info), "");
1700
1701         sd1 = info.info2.secdesc;
1702
1703         torture_assert(tctx, test_sd_set_level(tctx, p, handle, 3, sd1), "");
1704
1705         torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 2, &info), "");
1706
1707         sd2 = info.info2.secdesc;
1708
1709         torture_assert(tctx, test_security_descriptor_equal(tctx, sd1, sd2),
1710                 "SD level 2 != SD level 2 after SD has been set via level 3");
1711
1712         /* set modified sd level 3, query level 2 */
1713
1714         for (i=0; i < 93; i++) {
1715                 struct security_ace a;
1716                 const char *sid_string = talloc_asprintf(tctx, "S-1-5-32-9999%i", i);
1717                 a.type = SEC_ACE_TYPE_ACCESS_ALLOWED;
1718                 a.flags = 0;
1719                 a.size = 0; /* autogenerated */
1720                 a.access_mask = 0;
1721                 a.trustee = *dom_sid_parse_talloc(tctx, sid_string);
1722                 torture_assert_ntstatus_ok(tctx, security_descriptor_dacl_add(sd1, &a), "");
1723         }
1724
1725         torture_assert(tctx, test_sd_set_level(tctx, p, handle, 3, sd1), "");
1726
1727         torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 2, &info), "");
1728         sd2 = info.info2.secdesc;
1729
1730         if (sd1->type & SEC_DESC_DACL_DEFAULTED) {
1731                 torture_comment(tctx, "removing SEC_DESC_DACL_DEFAULTED\n");
1732                 sd1->type &= ~SEC_DESC_DACL_DEFAULTED;
1733         }
1734
1735         torture_assert(tctx, test_security_descriptor_equal(tctx, sd1, sd2),
1736                 "modified SD level 2 != SD level 2 after SD has been set via level 3");
1737
1738
1739         return true;
1740 }
1741
1742 /*
1743  * wrapper call that saves original sd, runs tests, and restores sd
1744  */
1745
1746 static bool test_PrinterInfo_SD(struct torture_context *tctx,
1747                                 struct dcerpc_pipe *p,
1748                                 struct policy_handle *handle)
1749 {
1750         union spoolss_PrinterInfo info;
1751         struct security_descriptor *sd;
1752         bool ret = true;
1753
1754         torture_comment(tctx, "\nTesting Printer Security Descriptors\n");
1755
1756         /* save original sd */
1757
1758         torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 2, &info),
1759                 "failed to get initial security descriptor");
1760
1761         sd = security_descriptor_copy(tctx, info.info2.secdesc);
1762
1763         /* run tests */
1764
1765         ret = test_PrinterInfo_SDs(tctx, p, handle);
1766
1767         /* restore original sd */
1768
1769         torture_assert(tctx, test_sd_set_level(tctx, p, handle, 3, sd),
1770                 "failed to restore initial security descriptor");
1771
1772         torture_comment(tctx, "Printer Security Descriptors test %s\n",
1773                 ret ? "succeeded" : "failed");
1774
1775
1776         return ret;
1777 }
1778
1779 static bool test_devmode_set_level(struct torture_context *tctx,
1780                                    struct dcerpc_pipe *p,
1781                                    struct policy_handle *handle,
1782                                    uint32_t level,
1783                                    struct spoolss_DeviceMode *devmode)
1784 {
1785         struct spoolss_SetPrinterInfoCtr info_ctr;
1786         struct spoolss_DevmodeContainer devmode_ctr;
1787         struct sec_desc_buf secdesc_ctr;
1788
1789         ZERO_STRUCT(devmode_ctr);
1790         ZERO_STRUCT(secdesc_ctr);
1791
1792         switch (level) {
1793         case 2: {
1794                 union spoolss_PrinterInfo info;
1795                 struct spoolss_SetPrinterInfo2 info2;
1796                 torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 2, &info), "");
1797
1798                 info2.servername        = info.info2.servername;
1799                 info2.printername       = info.info2.printername;
1800                 info2.sharename         = info.info2.sharename;
1801                 info2.portname          = info.info2.portname;
1802                 info2.drivername        = info.info2.drivername;
1803                 info2.comment           = info.info2.comment;
1804                 info2.location          = info.info2.location;
1805                 info2.devmode_ptr       = 0;
1806                 info2.sepfile           = info.info2.sepfile;
1807                 info2.printprocessor    = info.info2.printprocessor;
1808                 info2.datatype          = info.info2.datatype;
1809                 info2.parameters        = info.info2.parameters;
1810                 info2.secdesc_ptr       = 0;
1811                 info2.attributes        = info.info2.attributes;
1812                 info2.priority          = info.info2.priority;
1813                 info2.defaultpriority   = info.info2.defaultpriority;
1814                 info2.starttime         = info.info2.starttime;
1815                 info2.untiltime         = info.info2.untiltime;
1816                 info2.status            = info.info2.status;
1817                 info2.cjobs             = info.info2.cjobs;
1818                 info2.averageppm        = info.info2.averageppm;
1819
1820                 info_ctr.level = 2;
1821                 info_ctr.info.info2 = &info2;
1822
1823                 break;
1824         }
1825         case 8: {
1826                 struct spoolss_SetPrinterInfo8 info8;
1827
1828                 info8.devmode_ptr = 0;
1829
1830                 info_ctr.level = 8;
1831                 info_ctr.info.info8 = &info8;
1832
1833                 break;
1834         }
1835         default:
1836                 return false;
1837         }
1838
1839         devmode_ctr.devmode = devmode;
1840
1841         torture_assert(tctx,
1842                 test_SetPrinter(tctx, p, handle, &info_ctr, &devmode_ctr, &secdesc_ctr, 0), "");
1843
1844         return true;
1845 }
1846
1847
1848 static bool test_devicemode_equal(struct torture_context *tctx,
1849                                   const struct spoolss_DeviceMode *d1,
1850                                   const struct spoolss_DeviceMode *d2)
1851 {
1852         if (d1 == d2) {
1853                 return true;
1854         }
1855
1856         if (!d1 || !d2) {
1857                 torture_comment(tctx, "%s\n", __location__);
1858                 return false;
1859         }
1860         torture_assert_str_equal(tctx, d1->devicename, d2->devicename, "devicename mismatch");
1861         torture_assert_int_equal(tctx, d1->specversion, d2->specversion, "specversion mismatch");
1862         torture_assert_int_equal(tctx, d1->driverversion, d2->driverversion, "driverversion mismatch");
1863         torture_assert_int_equal(tctx, d1->size, d2->size, "size mismatch");
1864         torture_assert_int_equal(tctx, d1->__driverextra_length, d2->__driverextra_length, "__driverextra_length mismatch");
1865         torture_assert_int_equal(tctx, d1->fields, d2->fields, "fields mismatch");
1866         torture_assert_int_equal(tctx, d1->orientation, d2->orientation, "orientation mismatch");
1867         torture_assert_int_equal(tctx, d1->papersize, d2->papersize, "papersize mismatch");
1868         torture_assert_int_equal(tctx, d1->paperlength, d2->paperlength, "paperlength mismatch");
1869         torture_assert_int_equal(tctx, d1->paperwidth, d2->paperwidth, "paperwidth mismatch");
1870         torture_assert_int_equal(tctx, d1->scale, d2->scale, "scale mismatch");
1871         torture_assert_int_equal(tctx, d1->copies, d2->copies, "copies mismatch");
1872         torture_assert_int_equal(tctx, d1->defaultsource, d2->defaultsource, "defaultsource mismatch");
1873         torture_assert_int_equal(tctx, d1->printquality, d2->printquality, "printquality mismatch");
1874         torture_assert_int_equal(tctx, d1->color, d2->color, "color mismatch");
1875         torture_assert_int_equal(tctx, d1->duplex, d2->duplex, "duplex mismatch");
1876         torture_assert_int_equal(tctx, d1->yresolution, d2->yresolution, "yresolution mismatch");
1877         torture_assert_int_equal(tctx, d1->ttoption, d2->ttoption, "ttoption mismatch");
1878         torture_assert_int_equal(tctx, d1->collate, d2->collate, "collate mismatch");
1879         torture_assert_str_equal(tctx, d1->formname, d2->formname, "formname mismatch");
1880         torture_assert_int_equal(tctx, d1->logpixels, d2->logpixels, "logpixels mismatch");
1881         torture_assert_int_equal(tctx, d1->bitsperpel, d2->bitsperpel, "bitsperpel mismatch");
1882         torture_assert_int_equal(tctx, d1->pelswidth, d2->pelswidth, "pelswidth mismatch");
1883         torture_assert_int_equal(tctx, d1->pelsheight, d2->pelsheight, "pelsheight mismatch");
1884         torture_assert_int_equal(tctx, d1->displayflags, d2->displayflags, "displayflags mismatch");
1885         torture_assert_int_equal(tctx, d1->displayfrequency, d2->displayfrequency, "displayfrequency mismatch");
1886         torture_assert_int_equal(tctx, d1->icmmethod, d2->icmmethod, "icmmethod mismatch");
1887         torture_assert_int_equal(tctx, d1->icmintent, d2->icmintent, "icmintent mismatch");
1888         torture_assert_int_equal(tctx, d1->mediatype, d2->mediatype, "mediatype mismatch");
1889         torture_assert_int_equal(tctx, d1->dithertype, d2->dithertype, "dithertype mismatch");
1890         torture_assert_int_equal(tctx, d1->reserved1, d2->reserved1, "reserved1 mismatch");
1891         torture_assert_int_equal(tctx, d1->reserved2, d2->reserved2, "reserved2 mismatch");
1892         torture_assert_int_equal(tctx, d1->panningwidth, d2->panningwidth, "panningwidth mismatch");
1893         torture_assert_int_equal(tctx, d1->panningheight, d2->panningheight, "panningheight mismatch");
1894         torture_assert_data_blob_equal(tctx, d1->driverextra_data, d2->driverextra_data, "driverextra_data mismatch");
1895
1896         return true;
1897 }
1898
1899 static bool test_devicemode_full(struct torture_context *tctx,
1900                                  struct dcerpc_pipe *p,
1901                                  struct policy_handle *handle)
1902 {
1903         struct spoolss_SetPrinter s;
1904         struct spoolss_GetPrinter q;
1905         struct spoolss_GetPrinter q0;
1906         struct spoolss_SetPrinterInfoCtr info_ctr;
1907         struct spoolss_SetPrinterInfo8 info8;
1908         union spoolss_PrinterInfo info;
1909         struct spoolss_DevmodeContainer devmode_ctr;
1910         struct sec_desc_buf secdesc_ctr;
1911         uint32_t needed;
1912         bool ret = true;
1913         NTSTATUS status;
1914
1915 #define TEST_DEVMODE_INT_EXP(lvl1, field1, lvl2, field2, value, exp_value) do { \
1916                 torture_comment(tctx, "field test %d/%s vs %d/%s\n", lvl1, #field1, lvl2, #field2); \
1917                 q.in.level = lvl1; \
1918                 TESTGETCALL(GetPrinter, q) \
1919                 info_ctr.level = lvl1; \
1920                 if (lvl1 == 2) {\
1921                         info_ctr.info.info ## lvl1 = (struct spoolss_SetPrinterInfo ## lvl1 *)&q.out.info->info ## lvl1; \
1922                 } else if (lvl1 == 8) {\
1923                         info_ctr.info.info ## lvl1 = &info8; \
1924                 }\
1925                 devmode_ctr.devmode = q.out.info->info ## lvl1.devmode; \
1926                 devmode_ctr.devmode->field1 = value; \
1927                 TESTSETCALL(SetPrinter, s) \
1928                 TESTGETCALL(GetPrinter, q) \
1929                 INT_EQUAL(q.out.info->info ## lvl1.devmode->field1, exp_value, field1); \
1930                 q.in.level = lvl2; \
1931                 TESTGETCALL(GetPrinter, q) \
1932                 INT_EQUAL(q.out.info->info ## lvl2.devmode->field2, exp_value, field1); \
1933         } while (0)
1934
1935 #define TEST_DEVMODE_INT(lvl1, field1, lvl2, field2, value) do { \
1936         TEST_DEVMODE_INT_EXP(lvl1, field1, lvl2, field2, value, value); \
1937         } while (0)
1938
1939         ZERO_STRUCT(devmode_ctr);
1940         ZERO_STRUCT(secdesc_ctr);
1941         ZERO_STRUCT(info8);
1942
1943         s.in.handle = handle;
1944         s.in.command = 0;
1945         s.in.info_ctr = &info_ctr;
1946         s.in.devmode_ctr = &devmode_ctr;
1947         s.in.secdesc_ctr = &secdesc_ctr;
1948
1949         q.in.handle = handle;
1950         q.out.info = &info;
1951         q0 = q;
1952
1953 #if 0
1954         const char *devicename;/* [charset(UTF16)] */
1955         enum spoolss_DeviceModeSpecVersion specversion;
1956         uint16_t driverversion;
1957         uint16_t size;
1958         uint16_t __driverextra_length;/* [value(r->driverextra_data.length)] */
1959         uint32_t fields;
1960 #endif
1961
1962         TEST_DEVMODE_INT(8, orientation,        8, orientation, __LINE__);
1963         TEST_DEVMODE_INT(8, papersize,          8, papersize, __LINE__);
1964         TEST_DEVMODE_INT(8, paperlength,        8, paperlength, __LINE__);
1965         TEST_DEVMODE_INT(8, paperwidth,         8, paperwidth, __LINE__);
1966         TEST_DEVMODE_INT(8, scale,              8, scale, __LINE__);
1967         TEST_DEVMODE_INT(8, copies,             8, copies, __LINE__);
1968         TEST_DEVMODE_INT(8, defaultsource,      8, defaultsource, __LINE__);
1969         TEST_DEVMODE_INT(8, printquality,       8, printquality, __LINE__);
1970         TEST_DEVMODE_INT(8, color,              8, color, __LINE__);
1971         TEST_DEVMODE_INT(8, duplex,             8, duplex, __LINE__);
1972         TEST_DEVMODE_INT(8, yresolution,        8, yresolution, __LINE__);
1973         TEST_DEVMODE_INT(8, ttoption,           8, ttoption, __LINE__);
1974         TEST_DEVMODE_INT(8, collate,            8, collate, __LINE__);
1975 #if 0
1976         const char *formname;/* [charset(UTF16)] */
1977 #endif
1978         TEST_DEVMODE_INT(8, logpixels,          8, logpixels, __LINE__);
1979         TEST_DEVMODE_INT(8, bitsperpel,         8, bitsperpel, __LINE__);
1980         TEST_DEVMODE_INT(8, pelswidth,          8, pelswidth, __LINE__);
1981         TEST_DEVMODE_INT(8, pelsheight,         8, pelsheight, __LINE__);
1982         TEST_DEVMODE_INT(8, displayflags,       8, displayflags, __LINE__);
1983         TEST_DEVMODE_INT(8, displayfrequency,   8, displayfrequency, __LINE__);
1984         TEST_DEVMODE_INT(8, icmmethod,          8, icmmethod, __LINE__);
1985         TEST_DEVMODE_INT(8, icmintent,          8, icmintent, __LINE__);
1986         TEST_DEVMODE_INT(8, mediatype,          8, mediatype, __LINE__);
1987         TEST_DEVMODE_INT(8, dithertype,         8, dithertype, __LINE__);
1988         TEST_DEVMODE_INT(8, reserved1,          8, reserved1, __LINE__);
1989         TEST_DEVMODE_INT(8, reserved2,          8, reserved2, __LINE__);
1990         TEST_DEVMODE_INT(8, panningwidth,       8, panningwidth, __LINE__);
1991         TEST_DEVMODE_INT(8, panningheight,      8, panningheight, __LINE__);
1992
1993         return ret;
1994 }
1995
1996 static bool call_OpenPrinterEx(struct torture_context *tctx,
1997                                struct dcerpc_pipe *p,
1998                                const char *name,
1999                                struct spoolss_DeviceMode *devmode,
2000                                struct policy_handle *handle);
2001
2002 static bool test_ClosePrinter(struct torture_context *tctx,
2003                               struct dcerpc_pipe *p,
2004                               struct policy_handle *handle);
2005
2006 static bool test_PrinterInfo_DevModes(struct torture_context *tctx,
2007                                       struct dcerpc_pipe *p,
2008                                       struct policy_handle *handle,
2009                                       const char *name)
2010 {
2011         union spoolss_PrinterInfo info;
2012         struct spoolss_DeviceMode *devmode;
2013         struct spoolss_DeviceMode *devmode2;
2014         struct policy_handle handle_devmode;
2015
2016         /* simply compare level8 and level2 devmode */
2017
2018         torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 8, &info), "");
2019
2020         devmode = info.info8.devmode;
2021
2022         torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 2, &info), "");
2023
2024         devmode2 = info.info2.devmode;
2025
2026         torture_assert(tctx, test_devicemode_equal(tctx, devmode, devmode2),
2027                 "DM level 8 != DM level 2");
2028
2029
2030         /* set devicemode level 8 and see if it persists */
2031
2032         devmode->copies = 93;
2033         devmode->formname = talloc_strdup(tctx, "Legal");
2034
2035         torture_assert(tctx, test_devmode_set_level(tctx, p, handle, 8, devmode), "");
2036
2037         torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 8, &info), "");
2038
2039         devmode2 = info.info8.devmode;
2040
2041         torture_assert(tctx, test_devicemode_equal(tctx, devmode, devmode2),
2042                 "modified DM level 8 != DM level 8 after DM has been set via level 8");
2043
2044         torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 2, &info), "");
2045
2046         devmode2 = info.info2.devmode;
2047
2048         torture_assert(tctx, test_devicemode_equal(tctx, devmode, devmode2),
2049                 "modified DM level 8 != DM level 2");
2050
2051
2052         /* set devicemode level 2 and see if it persists */
2053
2054         devmode->copies = 39;
2055         devmode->formname = talloc_strdup(tctx, "Executive");
2056
2057         torture_assert(tctx, test_devmode_set_level(tctx, p, handle, 2, devmode), "");
2058
2059         torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 8, &info), "");
2060
2061         devmode2 = info.info8.devmode;
2062
2063         torture_assert(tctx, test_devicemode_equal(tctx, devmode, devmode2),
2064                 "modified DM level 8 != DM level 8 after DM has been set via level 2");
2065
2066         torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 2, &info), "");
2067
2068         devmode2 = info.info2.devmode;
2069
2070         torture_assert(tctx, test_devicemode_equal(tctx, devmode, devmode2),
2071                 "modified DM level 8 != DM level 2");
2072
2073
2074         /* check every single bit in public part of devicemode */
2075
2076         torture_assert(tctx, test_devicemode_full(tctx, p, handle),
2077                 "failed to set every single devicemode component");
2078
2079
2080         /* change formname upon open and see if it persists in getprinter calls */
2081
2082         devmode->formname = talloc_strdup(tctx, "A4");
2083         devmode->copies = 42;
2084
2085         torture_assert(tctx, call_OpenPrinterEx(tctx, p, name, devmode, &handle_devmode),
2086                 "failed to open printer handle");
2087
2088         torture_assert(tctx, test_GetPrinter_level(tctx, p, &handle_devmode, 8, &info), "");
2089
2090         devmode2 = info.info8.devmode;
2091
2092         if (strequal(devmode->devicename, devmode2->devicename)) {
2093                 torture_comment(tctx, "devicenames are the same\n");
2094         } else {
2095                 torture_comment(tctx, "devicename passed in for open: %s\n", devmode->devicename);
2096                 torture_comment(tctx, "devicename after level 8 get: %s\n", devmode2->devicename);
2097         }
2098
2099         if (strequal(devmode->formname, devmode2->formname)) {
2100                 torture_warning(tctx, "formname are the same\n");
2101         } else {
2102                 torture_comment(tctx, "formname passed in for open: %s\n", devmode->formname);
2103                 torture_comment(tctx, "formname after level 8 get: %s\n", devmode2->formname);
2104         }
2105
2106         if (devmode->copies == devmode2->copies) {
2107                 torture_warning(tctx, "copies are the same\n");
2108         } else {
2109                 torture_comment(tctx, "copies passed in for open: %d\n", devmode->copies);
2110                 torture_comment(tctx, "copies after level 8 get: %d\n", devmode2->copies);
2111         }
2112
2113         torture_assert(tctx, test_GetPrinter_level(tctx, p, &handle_devmode, 2, &info), "");
2114
2115         devmode2 = info.info2.devmode;
2116
2117         if (strequal(devmode->devicename, devmode2->devicename)) {
2118                 torture_comment(tctx, "devicenames are the same\n");
2119         } else {
2120                 torture_comment(tctx, "devicename passed in for open: %s\n", devmode->devicename);
2121                 torture_comment(tctx, "devicename after level 2 get: %s\n", devmode2->devicename);
2122         }
2123
2124         if (strequal(devmode->formname, devmode2->formname)) {
2125                 torture_warning(tctx, "formname is the same\n");
2126         } else {
2127                 torture_comment(tctx, "formname passed in for open: %s\n", devmode->formname);
2128                 torture_comment(tctx, "formname after level 2 get: %s\n", devmode2->formname);
2129         }
2130
2131         if (devmode->copies == devmode2->copies) {
2132                 torture_warning(tctx, "copies are the same\n");
2133         } else {
2134                 torture_comment(tctx, "copies passed in for open: %d\n", devmode->copies);
2135                 torture_comment(tctx, "copies after level 2 get: %d\n", devmode2->copies);
2136         }
2137
2138         test_ClosePrinter(tctx, p, &handle_devmode);
2139
2140         return true;
2141 }
2142
2143 /*
2144  * wrapper call that saves original devmode, runs tests, and restores devmode
2145  */
2146
2147 static bool test_PrinterInfo_DevMode(struct torture_context *tctx,
2148                                      struct dcerpc_pipe *p,
2149                                      struct policy_handle *handle,
2150                                      const char *name)
2151 {
2152         union spoolss_PrinterInfo info;
2153         struct spoolss_DeviceMode *devmode;
2154         bool ret = true;
2155
2156         torture_comment(tctx, "\nTesting Printer Devicemodes\n");
2157
2158         /* save original devmode */
2159
2160         torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 8, &info),
2161                 "failed to get initial global devicemode");
2162
2163         devmode = info.info8.devmode;
2164
2165         /* run tests */
2166
2167         ret = test_PrinterInfo_DevModes(tctx, p, handle, name);
2168
2169         /* restore original devmode */
2170
2171         torture_assert(tctx, test_devmode_set_level(tctx, p, handle, 8, devmode),
2172                 "failed to restore initial global device mode");
2173
2174         torture_comment(tctx, "Printer Devicemodes test %s\n",
2175                 ret ? "succeeded" : "failed");
2176
2177
2178         return ret;
2179 }
2180
2181 static bool test_ClosePrinter(struct torture_context *tctx,
2182                               struct dcerpc_pipe *p,
2183                               struct policy_handle *handle)
2184 {
2185         NTSTATUS status;
2186         struct spoolss_ClosePrinter r;
2187
2188         r.in.handle = handle;
2189         r.out.handle = handle;
2190
2191         torture_comment(tctx, "Testing ClosePrinter\n");
2192
2193         status = dcerpc_spoolss_ClosePrinter(p, tctx, &r);
2194         torture_assert_ntstatus_ok(tctx, status, "ClosePrinter failed");
2195         torture_assert_werr_ok(tctx, r.out.result, "ClosePrinter failed");
2196
2197         return true;
2198 }
2199
2200 static bool test_GetForm(struct torture_context *tctx,
2201                          struct dcerpc_pipe *p,
2202                          struct policy_handle *handle,
2203                          const char *form_name,
2204                          uint32_t level)
2205 {
2206         NTSTATUS status;
2207         struct spoolss_GetForm r;
2208         uint32_t needed;
2209
2210         r.in.handle = handle;
2211         r.in.form_name = form_name;
2212         r.in.level = level;
2213         r.in.buffer = NULL;
2214         r.in.offered = 0;
2215         r.out.needed = &needed;
2216
2217         torture_comment(tctx, "Testing GetForm level %d\n", r.in.level);
2218
2219         status = dcerpc_spoolss_GetForm(p, tctx, &r);
2220         torture_assert_ntstatus_ok(tctx, status, "GetForm failed");
2221
2222         if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
2223                 DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed);
2224                 data_blob_clear(&blob);
2225                 r.in.buffer = &blob;
2226                 r.in.offered = needed;
2227                 status = dcerpc_spoolss_GetForm(p, tctx, &r);
2228                 torture_assert_ntstatus_ok(tctx, status, "GetForm failed");
2229
2230                 torture_assert_werr_ok(tctx, r.out.result, "GetForm failed");
2231
2232                 torture_assert(tctx, r.out.info, "No form info returned");
2233         }
2234
2235         torture_assert_werr_ok(tctx, r.out.result, "GetForm failed");
2236
2237         CHECK_NEEDED_SIZE_LEVEL(spoolss_FormInfo, r.out.info, r.in.level, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
2238
2239         return true;
2240 }
2241
2242 static bool test_EnumForms(struct torture_context *tctx,
2243                            struct dcerpc_pipe *p,
2244                            struct policy_handle *handle, bool print_server)
2245 {
2246         NTSTATUS status;
2247         struct spoolss_EnumForms r;
2248         bool ret = true;
2249         uint32_t needed;
2250         uint32_t count;
2251         uint32_t levels[] = { 1, 2 };
2252         int i;
2253
2254         for (i=0; i<ARRAY_SIZE(levels); i++) {
2255
2256                 union spoolss_FormInfo *info;
2257
2258                 r.in.handle = handle;
2259                 r.in.level = levels[i];
2260                 r.in.buffer = NULL;
2261                 r.in.offered = 0;
2262                 r.out.needed = &needed;
2263                 r.out.count = &count;
2264                 r.out.info = &info;
2265
2266                 torture_comment(tctx, "Testing EnumForms level %d\n", levels[i]);
2267
2268                 status = dcerpc_spoolss_EnumForms(p, tctx, &r);
2269                 torture_assert_ntstatus_ok(tctx, status, "EnumForms failed");
2270
2271                 if ((r.in.level == 2) && (W_ERROR_EQUAL(r.out.result, WERR_UNKNOWN_LEVEL))) {
2272                         break;
2273                 }
2274
2275                 if (print_server && W_ERROR_EQUAL(r.out.result, WERR_BADFID))
2276                         torture_fail(tctx, "EnumForms on the PrintServer isn't supported by test server (NT4)");
2277
2278                 if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
2279                         int j;
2280                         DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed);
2281                         data_blob_clear(&blob);
2282                         r.in.buffer = &blob;
2283                         r.in.offered = needed;
2284
2285                         status = dcerpc_spoolss_EnumForms(p, tctx, &r);
2286
2287                         torture_assert(tctx, info, "No forms returned");
2288
2289                         for (j = 0; j < count; j++) {
2290                                 if (!print_server)
2291                                         ret &= test_GetForm(tctx, p, handle, info[j].info1.form_name, levels[i]);
2292                         }
2293                 }
2294
2295                 torture_assert_ntstatus_ok(tctx, status, "EnumForms failed");
2296
2297                 torture_assert_werr_ok(tctx, r.out.result, "EnumForms failed");
2298
2299                 CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumForms, info, r.in.level, count, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
2300         }
2301
2302         return true;
2303 }
2304
2305 static bool test_DeleteForm(struct torture_context *tctx,
2306                             struct dcerpc_pipe *p,
2307                             struct policy_handle *handle,
2308                             const char *form_name)
2309 {
2310         NTSTATUS status;
2311         struct spoolss_DeleteForm r;
2312
2313         r.in.handle = handle;
2314         r.in.form_name = form_name;
2315
2316         status = dcerpc_spoolss_DeleteForm(p, tctx, &r);
2317
2318         torture_assert_ntstatus_ok(tctx, status, "DeleteForm failed");
2319
2320         torture_assert_werr_ok(tctx, r.out.result, "DeleteForm failed");
2321
2322         return true;
2323 }
2324
2325 static bool test_AddForm(struct torture_context *tctx,
2326                          struct dcerpc_pipe *p,
2327                          struct policy_handle *handle, bool print_server)
2328 {
2329         struct spoolss_AddForm r;
2330         struct spoolss_AddFormInfo1 addform;
2331         const char *form_name = "testform3";
2332         NTSTATUS status;
2333         bool ret = true;
2334
2335         r.in.handle     = handle;
2336         r.in.level      = 1;
2337         r.in.info.info1 = &addform;
2338         addform.flags           = SPOOLSS_FORM_USER;
2339         addform.form_name       = form_name;
2340         addform.size.width      = 50;
2341         addform.size.height     = 25;
2342         addform.area.left       = 5;
2343         addform.area.top        = 10;
2344         addform.area.right      = 45;
2345         addform.area.bottom     = 15;
2346
2347         status = dcerpc_spoolss_AddForm(p, tctx, &r);
2348
2349         torture_assert_ntstatus_ok(tctx, status, "AddForm failed");
2350
2351         torture_assert_werr_ok(tctx, r.out.result, "AddForm failed");
2352
2353         if (!print_server) ret &= test_GetForm(tctx, p, handle, form_name, 1);
2354
2355         {
2356                 struct spoolss_SetForm sf;
2357                 struct spoolss_AddFormInfo1 setform;
2358
2359                 sf.in.handle    = handle;
2360                 sf.in.form_name = form_name;
2361                 sf.in.level     = 1;
2362                 sf.in.info.info1= &setform;
2363                 setform.flags           = addform.flags;
2364                 setform.form_name       = addform.form_name;
2365                 setform.size            = addform.size;
2366                 setform.area            = addform.area;
2367
2368                 setform.size.width      = 1234;
2369
2370                 status = dcerpc_spoolss_SetForm(p, tctx, &sf);
2371
2372                 torture_assert_ntstatus_ok(tctx, status, "SetForm failed");
2373
2374                 torture_assert_werr_ok(tctx, r.out.result, "SetForm failed");
2375         }
2376
2377         if (!print_server) ret &= test_GetForm(tctx, p, handle, form_name, 1);
2378
2379         {
2380                 struct spoolss_EnumForms e;
2381                 union spoolss_FormInfo *info;
2382                 uint32_t needed;
2383                 uint32_t count;
2384                 bool found = false;
2385
2386                 e.in.handle = handle;
2387                 e.in.level = 1;
2388                 e.in.buffer = NULL;
2389                 e.in.offered = 0;
2390                 e.out.needed = &needed;
2391                 e.out.count = &count;
2392                 e.out.info = &info;
2393
2394                 torture_comment(tctx, "Testing EnumForms level 1\n");
2395
2396                 status = dcerpc_spoolss_EnumForms(p, tctx, &e);
2397                 torture_assert_ntstatus_ok(tctx, status, "EnumForms failed");
2398
2399                 if (print_server && W_ERROR_EQUAL(e.out.result, WERR_BADFID))
2400                         torture_fail(tctx, "EnumForms on the PrintServer isn't supported by test server (NT4)");
2401
2402                 if (W_ERROR_EQUAL(e.out.result, WERR_INSUFFICIENT_BUFFER)) {
2403                         int j;
2404                         DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed);
2405                         data_blob_clear(&blob);
2406                         e.in.buffer = &blob;
2407                         e.in.offered = needed;
2408
2409                         status = dcerpc_spoolss_EnumForms(p, tctx, &e);
2410
2411                         torture_assert(tctx, info, "No forms returned");
2412
2413                         for (j = 0; j < count; j++) {
2414                                 if (strequal(form_name, info[j].info1.form_name)) {
2415                                         found = true;
2416                                         break;
2417                                 }
2418                         }
2419                 }
2420                 torture_assert(tctx, found, "Newly added form not found in enum call");
2421         }
2422
2423         if (!test_DeleteForm(tctx, p, handle, form_name)) {
2424                 ret = false;
2425         }
2426
2427         return ret;
2428 }
2429
2430 static bool test_EnumPorts_old(struct torture_context *tctx,
2431                                struct dcerpc_pipe *p)
2432 {
2433         NTSTATUS status;
2434         struct spoolss_EnumPorts r;
2435         uint32_t needed;
2436         uint32_t count;
2437         union spoolss_PortInfo *info;
2438
2439         r.in.servername = talloc_asprintf(tctx, "\\\\%s",
2440                                           dcerpc_server_name(p));
2441         r.in.level = 2;
2442         r.in.buffer = NULL;
2443         r.in.offered = 0;
2444         r.out.needed = &needed;
2445         r.out.count = &count;
2446         r.out.info = &info;
2447
2448         torture_comment(tctx, "Testing EnumPorts\n");
2449
2450         status = dcerpc_spoolss_EnumPorts(p, tctx, &r);
2451
2452         torture_assert_ntstatus_ok(tctx, status, "EnumPorts failed");
2453
2454         if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
2455                 DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed);
2456                 data_blob_clear(&blob);
2457                 r.in.buffer = &blob;
2458                 r.in.offered = needed;
2459
2460                 status = dcerpc_spoolss_EnumPorts(p, tctx, &r);
2461                 torture_assert_ntstatus_ok(tctx, status, "EnumPorts failed");
2462                 torture_assert_werr_ok(tctx, r.out.result, "EnumPorts failed");
2463
2464                 torture_assert(tctx, info, "No ports returned");
2465         }
2466
2467         torture_assert_werr_ok(tctx, r.out.result, "EnumPorts failed");
2468
2469         CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumPorts, info, 2, count, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
2470
2471         return true;
2472 }
2473
2474 static bool test_AddPort(struct torture_context *tctx,
2475                          struct dcerpc_pipe *p)
2476 {
2477         NTSTATUS status;
2478         struct spoolss_AddPort r;
2479
2480         r.in.server_name = talloc_asprintf(tctx, "\\\\%s",
2481                                            dcerpc_server_name(p));
2482         r.in.unknown = 0;
2483         r.in.monitor_name = "foo";
2484
2485         torture_comment(tctx, "Testing AddPort\n");
2486
2487         status = dcerpc_spoolss_AddPort(p, tctx, &r);
2488
2489         torture_assert_ntstatus_ok(tctx, status, "AddPort failed");
2490
2491         /* win2k3 returns WERR_NOT_SUPPORTED */
2492
2493 #if 0
2494
2495         if (!W_ERROR_IS_OK(r.out.result)) {
2496                 printf("AddPort failed - %s\n", win_errstr(r.out.result));
2497                 return false;
2498         }
2499
2500 #endif
2501
2502         return true;
2503 }
2504
2505 static bool test_GetJob(struct torture_context *tctx,
2506                         struct dcerpc_pipe *p,
2507                         struct policy_handle *handle, uint32_t job_id)
2508 {
2509         NTSTATUS status;
2510         struct spoolss_GetJob r;
2511         union spoolss_JobInfo info;
2512         uint32_t needed;
2513         uint32_t levels[] = {1, 2 /* 3, 4 */};
2514         uint32_t i;
2515
2516         r.in.handle = handle;
2517         r.in.job_id = job_id;
2518         r.in.level = 0;
2519         r.in.buffer = NULL;
2520         r.in.offered = 0;
2521         r.out.needed = &needed;
2522         r.out.info = &info;
2523
2524         torture_comment(tctx, "Testing GetJob level %d\n", r.in.level);
2525
2526         status = dcerpc_spoolss_GetJob(p, tctx, &r);
2527         torture_assert_werr_equal(tctx, r.out.result, WERR_UNKNOWN_LEVEL, "Unexpected return code");
2528
2529         for (i = 0; i < ARRAY_SIZE(levels); i++) {
2530
2531                 torture_comment(tctx, "Testing GetJob level %d\n", r.in.level);
2532
2533                 needed = 0;
2534
2535                 r.in.level = levels[i];
2536                 r.in.offered = 0;
2537                 r.in.buffer = NULL;
2538
2539                 status = dcerpc_spoolss_GetJob(p, tctx, &r);
2540                 torture_assert_ntstatus_ok(tctx, status, "GetJob failed");
2541
2542                 if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
2543                         DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed);
2544                         data_blob_clear(&blob);
2545                         r.in.buffer = &blob;
2546                         r.in.offered = needed;
2547
2548                         status = dcerpc_spoolss_GetJob(p, tctx, &r);
2549                         torture_assert_ntstatus_ok(tctx, status, "GetJob failed");
2550
2551                 }
2552                 torture_assert(tctx, r.out.info, "No job info returned");
2553                 torture_assert_werr_ok(tctx, r.out.result, "GetJob failed");
2554
2555                 CHECK_NEEDED_SIZE_LEVEL(spoolss_JobInfo, r.out.info, r.in.level, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
2556         }
2557
2558         return true;
2559 }
2560
2561 static bool test_SetJob(struct torture_context *tctx,
2562                         struct dcerpc_pipe *p,
2563                         struct policy_handle *handle, uint32_t job_id,
2564                         enum spoolss_JobControl command)
2565 {
2566         NTSTATUS status;
2567         struct spoolss_SetJob r;
2568
2569         r.in.handle     = handle;
2570         r.in.job_id     = job_id;
2571         r.in.ctr        = NULL;
2572         r.in.command    = command;
2573
2574         switch (command) {
2575         case SPOOLSS_JOB_CONTROL_PAUSE:
2576                 torture_comment(tctx, "Testing SetJob: SPOOLSS_JOB_CONTROL_PAUSE\n");
2577                 break;
2578         case SPOOLSS_JOB_CONTROL_RESUME:
2579                 torture_comment(tctx, "Testing SetJob: SPOOLSS_JOB_CONTROL_RESUME\n");
2580                 break;
2581         case SPOOLSS_JOB_CONTROL_CANCEL:
2582                 torture_comment(tctx, "Testing SetJob: SPOOLSS_JOB_CONTROL_CANCEL\n");
2583                 break;
2584         case SPOOLSS_JOB_CONTROL_RESTART:
2585                 torture_comment(tctx, "Testing SetJob: SPOOLSS_JOB_CONTROL_RESTART\n");
2586                 break;
2587         case SPOOLSS_JOB_CONTROL_DELETE:
2588                 torture_comment(tctx, "Testing SetJob: SPOOLSS_JOB_CONTROL_DELETE\n");
2589                 break;
2590         case SPOOLSS_JOB_CONTROL_SEND_TO_PRINTER:
2591                 torture_comment(tctx, "Testing SetJob: SPOOLSS_JOB_CONTROL_SEND_TO_PRINTER\n");
2592                 break;
2593         case SPOOLSS_JOB_CONTROL_LAST_PAGE_EJECTED:
2594                 torture_comment(tctx, "Testing SetJob: SPOOLSS_JOB_CONTROL_LAST_PAGE_EJECTED\n");
2595                 break;
2596         case SPOOLSS_JOB_CONTROL_RETAIN:
2597                 torture_comment(tctx, "Testing SetJob: SPOOLSS_JOB_CONTROL_RETAIN\n");
2598                 break;
2599         case SPOOLSS_JOB_CONTROL_RELEASE:
2600                 torture_comment(tctx, "Testing SetJob: SPOOLSS_JOB_CONTROL_RELEASE\n");
2601                 break;
2602         default:
2603                 torture_comment(tctx, "Testing SetJob\n");
2604                 break;
2605         }
2606
2607         status = dcerpc_spoolss_SetJob(p, tctx, &r);
2608         torture_assert_ntstatus_ok(tctx, status, "SetJob failed");
2609         torture_assert_werr_ok(tctx, r.out.result, "SetJob failed");
2610
2611         return true;
2612 }
2613
2614 static bool test_AddJob(struct torture_context *tctx,
2615                         struct dcerpc_pipe *p,
2616                         struct policy_handle *handle)
2617 {
2618         NTSTATUS status;
2619         struct spoolss_AddJob r;
2620         uint32_t needed;
2621
2622         r.in.level = 0;
2623         r.in.handle = handle;
2624         r.in.offered = 0;
2625         r.out.needed = &needed;
2626         r.in.buffer = r.out.buffer = NULL;
2627
2628         torture_comment(tctx, "Testing AddJob\n");
2629
2630         status = dcerpc_spoolss_AddJob(p, tctx, &r);
2631         torture_assert_werr_equal(tctx, r.out.result, WERR_UNKNOWN_LEVEL, "AddJob failed");
2632
2633         r.in.level = 1;
2634
2635         status = dcerpc_spoolss_AddJob(p, tctx, &r);
2636         torture_assert_werr_equal(tctx, r.out.result, WERR_INVALID_PARAM, "AddJob failed");
2637
2638         return true;
2639 }
2640
2641
2642 static bool test_EnumJobs(struct torture_context *tctx,
2643                           struct dcerpc_pipe *p,
2644                           struct policy_handle *handle)
2645 {
2646         NTSTATUS status;
2647         struct spoolss_EnumJobs r;
2648         uint32_t needed;
2649         uint32_t count;
2650         union spoolss_JobInfo *info;
2651
2652         r.in.handle = handle;
2653         r.in.firstjob = 0;
2654         r.in.numjobs = 0xffffffff;
2655         r.in.level = 1;
2656         r.in.buffer = NULL;
2657         r.in.offered = 0;
2658         r.out.needed = &needed;
2659         r.out.count = &count;
2660         r.out.info = &info;
2661
2662         torture_comment(tctx, "Testing EnumJobs\n");
2663
2664         status = dcerpc_spoolss_EnumJobs(p, tctx, &r);
2665
2666         torture_assert_ntstatus_ok(tctx, status, "EnumJobs failed");
2667
2668         if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
2669                 int j;
2670                 DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed);
2671                 data_blob_clear(&blob);
2672                 r.in.buffer = &blob;
2673                 r.in.offered = needed;
2674
2675                 status = dcerpc_spoolss_EnumJobs(p, tctx, &r);
2676
2677                 torture_assert_ntstatus_ok(tctx, status, "EnumJobs failed");
2678                 torture_assert_werr_ok(tctx, r.out.result, "EnumJobs failed");
2679                 torture_assert(tctx, info, "No jobs returned");
2680
2681                 CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumJobs, *r.out.info, r.in.level, count, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
2682
2683                 for (j = 0; j < count; j++) {
2684
2685                         torture_assert(tctx, test_GetJob(tctx, p, handle, info[j].info1.job_id),
2686                                 "failed to call test_GetJob");
2687
2688                         /* FIXME - gd */
2689                         if (!torture_setting_bool(tctx, "samba3", false)) {
2690                                 test_SetJob(tctx, p, handle, info[j].info1.job_id, SPOOLSS_JOB_CONTROL_PAUSE);
2691                                 test_SetJob(tctx, p, handle, info[j].info1.job_id, SPOOLSS_JOB_CONTROL_RESUME);
2692                         }
2693                 }
2694
2695         } else {
2696                 torture_assert_werr_ok(tctx, r.out.result, "EnumJobs failed");
2697         }
2698
2699         return true;
2700 }
2701
2702 static bool test_DoPrintTest(struct torture_context *tctx,
2703                              struct dcerpc_pipe *p,
2704                              struct policy_handle *handle)
2705 {
2706         bool ret = true;
2707         NTSTATUS status;
2708         struct spoolss_StartDocPrinter s;
2709         struct spoolss_DocumentInfo1 info1;
2710         struct spoolss_StartPagePrinter sp;
2711         struct spoolss_WritePrinter w;
2712         struct spoolss_EndPagePrinter ep;
2713         struct spoolss_EndDocPrinter e;
2714         int i;
2715         uint32_t job_id;
2716         uint32_t num_written;
2717
2718         torture_comment(tctx, "Testing StartDocPrinter\n");
2719
2720         s.in.handle             = handle;
2721         s.in.level              = 1;
2722         s.in.info.info1         = &info1;
2723         s.out.job_id            = &job_id;
2724         info1.document_name     = "TorturePrintJob";
2725         info1.output_file       = NULL;
2726         info1.datatype          = "RAW";
2727
2728         status = dcerpc_spoolss_StartDocPrinter(p, tctx, &s);
2729         torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_StartDocPrinter failed");
2730         torture_assert_werr_ok(tctx, s.out.result, "StartDocPrinter failed");
2731
2732         for (i=1; i < 4; i++) {
2733                 torture_comment(tctx, "Testing StartPagePrinter: Page[%d]\n", i);
2734
2735                 sp.in.handle            = handle;
2736
2737                 status = dcerpc_spoolss_StartPagePrinter(p, tctx, &sp);
2738                 torture_assert_ntstatus_ok(tctx, status,
2739                                            "dcerpc_spoolss_StartPagePrinter failed");
2740                 torture_assert_werr_ok(tctx, sp.out.result, "StartPagePrinter failed");
2741
2742                 torture_comment(tctx, "Testing WritePrinter: Page[%d]\n", i);
2743
2744                 w.in.handle             = handle;
2745                 w.in.data               = data_blob_string_const(talloc_asprintf(tctx,"TortureTestPage: %d\nData\n",i));
2746                 w.out.num_written       = &num_written;
2747
2748                 status = dcerpc_spoolss_WritePrinter(p, tctx, &w);
2749                 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_WritePrinter failed");
2750                 torture_assert_werr_ok(tctx, w.out.result, "WritePrinter failed");
2751
2752                 torture_comment(tctx, "Testing EndPagePrinter: Page[%d]\n", i);
2753
2754                 ep.in.handle            = handle;
2755
2756                 status = dcerpc_spoolss_EndPagePrinter(p, tctx, &ep);
2757                 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EndPagePrinter failed");
2758                 torture_assert_werr_ok(tctx, ep.out.result, "EndPagePrinter failed");
2759         }
2760
2761         torture_comment(tctx, "Testing EndDocPrinter\n");
2762
2763         e.in.handle = handle;
2764
2765         status = dcerpc_spoolss_EndDocPrinter(p, tctx, &e);
2766         torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EndDocPrinter failed");
2767         torture_assert_werr_ok(tctx, e.out.result, "EndDocPrinter failed");
2768
2769         ret &= test_AddJob(tctx, p, handle);
2770         ret &= test_EnumJobs(tctx, p, handle);
2771
2772         ret &= test_SetJob(tctx, p, handle, job_id, SPOOLSS_JOB_CONTROL_DELETE);
2773
2774         return ret;
2775 }
2776
2777 static bool test_PausePrinter(struct torture_context *tctx,
2778                               struct dcerpc_pipe *p,
2779                               struct policy_handle *handle)
2780 {
2781         NTSTATUS status;
2782         struct spoolss_SetPrinter r;
2783         struct spoolss_SetPrinterInfoCtr info_ctr;
2784         struct spoolss_DevmodeContainer devmode_ctr;
2785         struct sec_desc_buf secdesc_ctr;
2786
2787         info_ctr.level = 0;
2788         info_ctr.info.info0 = NULL;
2789
2790         ZERO_STRUCT(devmode_ctr);
2791         ZERO_STRUCT(secdesc_ctr);
2792
2793         r.in.handle             = handle;
2794         r.in.info_ctr           = &info_ctr;
2795         r.in.devmode_ctr        = &devmode_ctr;
2796         r.in.secdesc_ctr        = &secdesc_ctr;
2797         r.in.command            = SPOOLSS_PRINTER_CONTROL_PAUSE;
2798
2799         torture_comment(tctx, "Testing SetPrinter: SPOOLSS_PRINTER_CONTROL_PAUSE\n");
2800
2801         status = dcerpc_spoolss_SetPrinter(p, tctx, &r);
2802
2803         torture_assert_ntstatus_ok(tctx, status, "SetPrinter failed");
2804
2805         torture_assert_werr_ok(tctx, r.out.result, "SetPrinter failed");
2806
2807         return true;
2808 }
2809
2810 static bool test_ResumePrinter(struct torture_context *tctx,
2811                                struct dcerpc_pipe *p,
2812                                struct policy_handle *handle)
2813 {
2814         NTSTATUS status;
2815         struct spoolss_SetPrinter r;
2816         struct spoolss_SetPrinterInfoCtr info_ctr;
2817         struct spoolss_DevmodeContainer devmode_ctr;
2818         struct sec_desc_buf secdesc_ctr;
2819
2820         info_ctr.level = 0;
2821         info_ctr.info.info0 = NULL;
2822
2823         ZERO_STRUCT(devmode_ctr);
2824         ZERO_STRUCT(secdesc_ctr);
2825
2826         r.in.handle             = handle;
2827         r.in.info_ctr           = &info_ctr;
2828         r.in.devmode_ctr        = &devmode_ctr;
2829         r.in.secdesc_ctr        = &secdesc_ctr;
2830         r.in.command            = SPOOLSS_PRINTER_CONTROL_RESUME;
2831
2832         torture_comment(tctx, "Testing SetPrinter: SPOOLSS_PRINTER_CONTROL_RESUME\n");
2833
2834         status = dcerpc_spoolss_SetPrinter(p, tctx, &r);
2835
2836         torture_assert_ntstatus_ok(tctx, status, "SetPrinter failed");
2837
2838         torture_assert_werr_ok(tctx, r.out.result, "SetPrinter failed");
2839
2840         return true;
2841 }
2842
2843 static bool test_GetPrinterData(struct torture_context *tctx,
2844                                 struct dcerpc_pipe *p,
2845                                 struct policy_handle *handle,
2846                                 const char *value_name,
2847                                 enum winreg_Type *type_p,
2848                                 uint8_t **data_p,
2849                                 uint32_t *needed_p)
2850 {
2851         NTSTATUS status;
2852         struct spoolss_GetPrinterData r;
2853         uint32_t needed;
2854         enum winreg_Type type;
2855         union spoolss_PrinterData data;
2856
2857         r.in.handle = handle;
2858         r.in.value_name = value_name;
2859         r.in.offered = 0;
2860         r.out.needed = &needed;
2861         r.out.type = &type;
2862         r.out.data = talloc_zero_array(tctx, uint8_t, r.in.offered);
2863
2864         torture_comment(tctx, "Testing GetPrinterData(%s)\n", r.in.value_name);
2865
2866         status = dcerpc_spoolss_GetPrinterData(p, tctx, &r);
2867         torture_assert_ntstatus_ok(tctx, status, "GetPrinterData failed");
2868
2869         if (W_ERROR_EQUAL(r.out.result, WERR_MORE_DATA)) {
2870                 r.in.offered = needed;
2871                 r.out.data = talloc_zero_array(tctx, uint8_t, r.in.offered);
2872                 status = dcerpc_spoolss_GetPrinterData(p, tctx, &r);
2873                 torture_assert_ntstatus_ok(tctx, status, "GetPrinterData failed");
2874         }
2875
2876         torture_assert_werr_ok(tctx, r.out.result,
2877                 talloc_asprintf(tctx, "GetPrinterData(%s) failed", r.in.value_name));
2878
2879         CHECK_NEEDED_SIZE_LEVEL(spoolss_PrinterData, &data, type, lp_iconv_convenience(tctx->lp_ctx), needed, 1);
2880
2881         if (type_p) {
2882                 *type_p = type;
2883         }
2884
2885         if (data_p) {
2886                 *data_p = r.out.data;
2887         }
2888
2889         if (needed_p) {
2890                 *needed_p = needed;
2891         }
2892
2893         return true;
2894 }
2895
2896 static bool test_GetPrinterDataEx(struct torture_context *tctx,
2897                                   struct dcerpc_pipe *p,
2898                                   struct policy_handle *handle,
2899                                   const char *key_name,
2900                                   const char *value_name,
2901                                   enum winreg_Type *type_p,
2902                                   uint8_t **data_p,
2903                                   uint32_t *needed_p)
2904 {
2905         NTSTATUS status;
2906         struct spoolss_GetPrinterDataEx r;
2907         enum winreg_Type type;
2908         uint32_t needed;
2909         union spoolss_PrinterData data;
2910
2911         r.in.handle = handle;
2912         r.in.key_name = key_name;
2913         r.in.value_name = value_name;
2914         r.in.offered = 0;
2915         r.out.type = &type;
2916         r.out.needed = &needed;
2917         r.out.data = talloc_zero_array(tctx, uint8_t, r.in.offered);
2918
2919         torture_comment(tctx, "Testing GetPrinterDataEx(%s - %s)\n",
2920                 r.in.key_name, r.in.value_name);
2921
2922         status = dcerpc_spoolss_GetPrinterDataEx(p, tctx, &r);
2923         if (!NT_STATUS_IS_OK(status)) {
2924                 if (NT_STATUS_EQUAL(status,NT_STATUS_NET_WRITE_FAULT) &&
2925                     p->last_fault_code == DCERPC_FAULT_OP_RNG_ERROR) {
2926                         torture_skip(tctx, "GetPrinterDataEx not supported by server\n");
2927                 }
2928                 torture_assert_ntstatus_ok(tctx, status, "GetPrinterDataEx failed");
2929         }
2930
2931         if (W_ERROR_EQUAL(r.out.result, WERR_MORE_DATA)) {
2932                 r.in.offered = needed;
2933                 r.out.data = talloc_zero_array(tctx, uint8_t, r.in.offered);
2934                 status = dcerpc_spoolss_GetPrinterDataEx(p, tctx, &r);
2935                 torture_assert_ntstatus_ok(tctx, status, "GetPrinterDataEx failed");
2936         }
2937
2938         torture_assert_werr_ok(tctx, r.out.result,
2939                 talloc_asprintf(tctx, "GetPrinterDataEx(%s - %s) failed", r.in.key_name, r.in.value_name));
2940
2941         CHECK_NEEDED_SIZE_LEVEL(spoolss_PrinterData, &data, type, lp_iconv_convenience(tctx->lp_ctx), needed, 1);
2942
2943         if (type_p) {
2944                 *type_p = type;
2945         }
2946
2947         if (data_p) {
2948                 *data_p = r.out.data;
2949         }
2950
2951         if (needed_p) {
2952                 *needed_p = needed;
2953         }
2954
2955         return true;
2956 }
2957
2958 static bool test_GetPrinterData_list(struct torture_context *tctx,
2959                                      struct dcerpc_pipe *p,
2960                                      struct policy_handle *handle)
2961 {
2962         const char *list[] = {
2963                 "W3SvcInstalled",
2964                 "BeepEnabled",
2965                 "EventLog",
2966                 /* "NetPopup", not on w2k8 */
2967                 /* "NetPopupToComputer", not on w2k8 */
2968                 "MajorVersion",
2969                 "MinorVersion",
2970                 "DefaultSpoolDirectory",
2971                 "Architecture",
2972                 "DsPresent",
2973                 "OSVersion",
2974                 /* "OSVersionEx", not on s3 */
2975                 "DNSMachineName"
2976         };
2977         int i;
2978
2979         for (i=0; i < ARRAY_SIZE(list); i++) {
2980                 enum winreg_Type type, type_ex;
2981                 uint8_t *data, *data_ex;
2982                 uint32_t needed, needed_ex;
2983
2984                 torture_assert(tctx, test_GetPrinterData(tctx, p, handle, list[i], &type, &data, &needed),
2985                         talloc_asprintf(tctx, "GetPrinterData failed on %s\n", list[i]));
2986                 torture_assert(tctx, test_GetPrinterDataEx(tctx, p, handle, "random_string", list[i], &type_ex, &data_ex, &needed_ex),
2987                         talloc_asprintf(tctx, "GetPrinterDataEx failed on %s\n", list[i]));
2988                 torture_assert_int_equal(tctx, type, type_ex, "type mismatch");
2989                 torture_assert_int_equal(tctx, needed, needed_ex, "needed mismatch");
2990                 torture_assert_mem_equal(tctx, data, data_ex, needed, "data mismatch");
2991         }
2992
2993         return true;
2994 }
2995
2996 static bool test_EnumPrinterData(struct torture_context *tctx, struct dcerpc_pipe *p,
2997                                  struct policy_handle *handle)
2998 {
2999         NTSTATUS status;
3000         struct spoolss_EnumPrinterData r;
3001
3002         ZERO_STRUCT(r);
3003         r.in.handle = handle;
3004         r.in.enum_index = 0;
3005
3006         do {
3007                 uint32_t value_size = 0;
3008                 uint32_t data_size = 0;
3009                 enum winreg_Type type = 0;
3010
3011                 r.in.value_offered = value_size;
3012                 r.out.value_needed = &value_size;
3013                 r.in.data_offered = data_size;
3014                 r.out.data_needed = &data_size;
3015
3016                 r.out.type = &type;
3017                 r.out.data = talloc_zero_array(tctx, uint8_t, 0);
3018
3019                 torture_comment(tctx, "Testing EnumPrinterData\n");
3020
3021                 status = dcerpc_spoolss_EnumPrinterData(p, tctx, &r);
3022
3023                 torture_assert_ntstatus_ok(tctx, status, "EnumPrinterData failed");
3024                 if (W_ERROR_EQUAL(r.out.result, WERR_NO_MORE_ITEMS)) {
3025                         break;
3026                 }
3027                 torture_assert_werr_ok(tctx, r.out.result, "EnumPrinterData");
3028
3029                 r.in.value_offered = value_size;
3030                 r.out.value_name = talloc_zero_array(tctx, const char, value_size);
3031                 r.in.data_offered = data_size;
3032                 r.out.data = talloc_zero_array(tctx, uint8_t, data_size);
3033
3034                 status = dcerpc_spoolss_EnumPrinterData(p, tctx, &r);
3035
3036                 torture_assert_ntstatus_ok(tctx, status, "EnumPrinterData failed");
3037                 if (W_ERROR_EQUAL(r.out.result, WERR_NO_MORE_ITEMS)) {
3038                         break;
3039                 }
3040
3041                 torture_assert_werr_ok(tctx, r.out.result, "EnumPrinterData failed");
3042
3043                 torture_assert(tctx, test_GetPrinterData(tctx, p, handle, r.out.value_name, NULL, NULL, NULL),
3044                         talloc_asprintf(tctx, "failed to call GetPrinterData for %s\n", r.out.value_name));
3045
3046                 torture_assert(tctx, test_GetPrinterDataEx(tctx, p, handle, "PrinterDriverData", r.out.value_name, NULL, NULL, NULL),
3047                         talloc_asprintf(tctx, "failed to call GetPrinterDataEx on PrinterDriverData for %s\n", r.out.value_name));
3048
3049                 r.in.enum_index++;
3050
3051         } while (W_ERROR_IS_OK(r.out.result));
3052
3053         return true;
3054 }
3055
3056 static bool test_EnumPrinterDataEx(struct torture_context *tctx,
3057                                    struct dcerpc_pipe *p,
3058                                    struct policy_handle *handle,
3059                                    const char *key_name)
3060 {
3061         struct spoolss_EnumPrinterDataEx r;
3062         struct spoolss_PrinterEnumValues *info;
3063         uint32_t needed;
3064         uint32_t count;
3065
3066         r.in.handle = handle;
3067         r.in.key_name = key_name;
3068         r.in.offered = 0;
3069         r.out.needed = &needed;
3070         r.out.count = &count;
3071         r.out.info = &info;
3072
3073         torture_comment(tctx, "Testing EnumPrinterDataEx(%s)\n", key_name);
3074
3075         torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_EnumPrinterDataEx(p, tctx, &r),
3076                 "EnumPrinterDataEx failed");
3077         if (W_ERROR_EQUAL(r.out.result, WERR_MORE_DATA)) {
3078                 r.in.offered = needed;
3079                 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_EnumPrinterDataEx(p, tctx, &r),
3080                         "EnumPrinterDataEx failed");
3081         }
3082
3083         torture_assert_werr_ok(tctx, r.out.result, "EnumPrinterDataEx failed");
3084
3085         CHECK_NEEDED_SIZE_ENUM(spoolss_EnumPrinterDataEx, info, count, lp_iconv_convenience(tctx->lp_ctx), needed, 1);
3086
3087         return true;
3088 }
3089
3090
3091 static bool test_DeletePrinterData(struct torture_context *tctx,
3092                                    struct dcerpc_pipe *p,
3093                                    struct policy_handle *handle,
3094                                    const char *value_name)
3095 {
3096         NTSTATUS status;
3097         struct spoolss_DeletePrinterData r;
3098
3099         r.in.handle = handle;
3100         r.in.value_name = value_name;
3101
3102         torture_comment(tctx, "Testing DeletePrinterData(%s)\n",
3103                 r.in.value_name);
3104
3105         status = dcerpc_spoolss_DeletePrinterData(p, tctx, &r);
3106
3107         torture_assert_ntstatus_ok(tctx, status, "DeletePrinterData failed");
3108         torture_assert_werr_ok(tctx, r.out.result, "DeletePrinterData failed");
3109
3110         return true;
3111 }
3112
3113 static bool test_DeletePrinterDataEx(struct torture_context *tctx,
3114                                      struct dcerpc_pipe *p,
3115                                      struct policy_handle *handle,
3116                                      const char *key_name,
3117                                      const char *value_name)
3118 {
3119         struct spoolss_DeletePrinterDataEx r;
3120
3121         r.in.handle = handle;
3122         r.in.key_name = key_name;
3123         r.in.value_name = value_name;
3124
3125         torture_comment(tctx, "Testing DeletePrinterDataEx(%s - %s)\n",
3126                 r.in.key_name, r.in.value_name);
3127
3128         torture_assert_ntstatus_ok(tctx,
3129                 dcerpc_spoolss_DeletePrinterDataEx(p, tctx, &r),
3130                 "DeletePrinterDataEx failed");
3131         torture_assert_werr_ok(tctx, r.out.result,
3132                 "DeletePrinterDataEx failed");
3133
3134         return true;
3135 }
3136
3137 static bool test_DeletePrinterKey(struct torture_context *tctx,
3138                                   struct dcerpc_pipe *p,
3139                                   struct policy_handle *handle,
3140                                   const char *key_name)
3141 {
3142         struct spoolss_DeletePrinterKey r;
3143
3144         r.in.handle = handle;
3145         r.in.key_name = key_name;
3146
3147         torture_comment(tctx, "Testing DeletePrinterKey(%s)\n", r.in.key_name);
3148
3149         if (strequal(key_name, "") && !torture_setting_bool(tctx, "dangerous", false)) {
3150                 torture_skip(tctx, "not wiping out printer registry - enable dangerous tests to use\n");
3151                 return true;
3152         }
3153
3154         torture_assert_ntstatus_ok(tctx,
3155                 dcerpc_spoolss_DeletePrinterKey(p, tctx, &r),
3156                 "DeletePrinterKey failed");
3157         torture_assert_werr_ok(tctx, r.out.result,
3158                 "DeletePrinterKey failed");
3159
3160         return true;
3161 }
3162
3163 static bool test_SetPrinterData(struct torture_context *tctx,
3164                                 struct dcerpc_pipe *p,
3165                                 struct policy_handle *handle)
3166 {
3167         NTSTATUS status;
3168         struct spoolss_SetPrinterData r;
3169         const char *values[] = {
3170                 "spootyfoot",
3171                 "spooty\\foot",
3172 #if 0
3173         /* FIXME: not working with s3 atm. */
3174                 "spooty,foot",
3175                 "spooty,fo,ot",
3176 #endif
3177                 "spooty foot",
3178 #if 0
3179         /* FIXME: not working with s3 atm. */
3180                 "spooty\\fo,ot",
3181                 "spooty,fo\\ot"
3182 #endif
3183         };
3184         int i;
3185
3186         for (i=0; i < ARRAY_SIZE(values); i++) {
3187
3188                 enum winreg_Type type;
3189                 uint8_t *data;
3190                 DATA_BLOB blob;
3191                 uint32_t needed;
3192
3193                 torture_assert(tctx,
3194                         reg_string_to_val(tctx, lp_iconv_convenience(tctx->lp_ctx),
3195                                           "REG_SZ", "dog", &r.in.type, &blob), "");
3196
3197                 r.in.handle = handle;
3198                 r.in.value_name = values[i];
3199                 r.in.data = blob.data;
3200                 r.in.offered = blob.length;
3201
3202                 torture_comment(tctx, "Testing SetPrinterData(%s)\n",
3203                         r.in.value_name);
3204
3205                 status = dcerpc_spoolss_SetPrinterData(p, tctx, &r);
3206
3207                 torture_assert_ntstatus_ok(tctx, status, "SetPrinterData failed");
3208                 torture_assert_werr_ok(tctx, r.out.result, "SetPrinterData failed");
3209
3210                 if (!test_GetPrinterData(tctx, p, handle, r.in.value_name, &type, &data, &needed)) {
3211                         return false;
3212                 }
3213
3214                 torture_assert_int_equal(tctx, r.in.type, type, "type mismatch");
3215                 torture_assert_int_equal(tctx, r.in.offered, needed, "size mismatch");
3216                 torture_assert_mem_equal(tctx, blob.data, data, needed, "buffer mismatch");
3217
3218                 if (!test_DeletePrinterData(tctx, p, handle, r.in.value_name)) {
3219                         return false;
3220                 }
3221         }
3222
3223         return true;
3224 }
3225
3226 static bool test_EnumPrinterKey(struct torture_context *tctx,
3227                                 struct dcerpc_pipe *p,
3228                                 struct policy_handle *handle,
3229                                 const char *key_name,
3230                                 const char ***array);
3231
3232 static bool test_SetPrinterDataEx(struct torture_context *tctx,
3233                                   struct dcerpc_pipe *p,
3234                                   struct policy_handle *handle,
3235                                   const char *key_name,
3236                                   const char *value_name,
3237                                   enum winreg_Type type,
3238                                   uint8_t *data,
3239                                   uint32_t offered)
3240 {
3241         NTSTATUS status;
3242         struct spoolss_SetPrinterDataEx r;
3243
3244         r.in.handle = handle;
3245         r.in.key_name = key_name;
3246         r.in.value_name = value_name;
3247         r.in.type = type;
3248         r.in.data = data;
3249         r.in.offered = offered;
3250
3251         torture_comment(tctx, "Testing SetPrinterDataEx(%s - %s) type: %s, offered: 0x%08x\n",
3252                 r.in.key_name, r.in.value_name, str_regtype(r.in.type), r.in.offered);
3253
3254         status = dcerpc_spoolss_SetPrinterDataEx(p, tctx, &r);
3255
3256         torture_assert_ntstatus_ok(tctx, status, "SetPrinterDataEx failed");
3257         torture_assert_werr_ok(tctx, r.out.result, "SetPrinterDataEx failed");
3258
3259         return true;
3260 }
3261
3262 static bool test_SetPrinterDataEx_matrix(struct torture_context *tctx,
3263                                          struct dcerpc_pipe *p,
3264                                          struct policy_handle *handle,
3265                                          const char *printername)
3266 {
3267         const char *value_name = "dog";
3268         const char *keys[] = {
3269                 "torturedataex",
3270                 "torture data ex",
3271 #if 0
3272         /* FIXME: not working with s3 atm. */
3273                 "torturedataex_with_subkey\\subkey",
3274                 "torturedataex_with_subkey\\subkey:0",
3275                 "torturedataex_with_subkey\\subkey:1",
3276                 "torturedataex_with_subkey\\subkey\\subsubkey",
3277                 "torturedataex_with_subkey\\subkey\\subsubkey:0",
3278                 "torturedataex_with_subkey\\subkey\\subsubkey:1",
3279 #endif
3280                 "torture,data",
3281 #if 0
3282         /* FIXME: not working with s3 atm. */
3283
3284                 "torture,data,ex",
3285                 "torture,data\\ex",
3286                 "torture\\data,ex"
3287 #endif
3288         };
3289         enum winreg_Type types[] = {
3290                 REG_SZ,
3291                 REG_DWORD,
3292                 REG_BINARY
3293         };
3294         const char *str = "abcdefghijklmnopqrstuvwxzy";
3295         int i, t, s;
3296
3297
3298         for (i=0; i < ARRAY_SIZE(keys); i++) {
3299         for (t=0; t < ARRAY_SIZE(types); t++) {
3300         for (s=0; s < strlen(str); s++) {
3301
3302                 char *c;
3303                 const char *key;
3304                 enum winreg_Type type;
3305                 const char *string = talloc_strndup(tctx, str, s);
3306                 DATA_BLOB blob = data_blob_string_const(string);
3307                 const char **subkeys;
3308                 DATA_BLOB data;
3309                 uint8_t *data_out;
3310                 uint32_t needed, offered = 0;
3311
3312                 switch (types[t]) {
3313                 case REG_BINARY:
3314                 case REG_DWORD:
3315                         data = blob;
3316                         offered = blob.length;
3317                         break;
3318                 case REG_SZ:
3319                         torture_assert(tctx,
3320                                 reg_string_to_val(tctx, lp_iconv_convenience(tctx->lp_ctx),
3321                                                   "REG_SZ", string, &type, &data), "");
3322                         offered = data.length;
3323                         /*strlen_m_term(data.string)*2;*/
3324                         break;
3325                 default:
3326                         torture_fail(tctx, talloc_asprintf(tctx, "type %d untested\n", types[t]));
3327                 }
3328
3329                 torture_assert(tctx,
3330                         test_SetPrinterDataEx(tctx, p, handle, keys[i], value_name, types[t], data.data, offered),
3331                         "failed to call SetPrinterDataEx");
3332
3333                 if (!test_GetPrinterDataEx(tctx, p, handle, keys[i], value_name, &type, &data_out, &needed)) {
3334                         return false;
3335                 }
3336                 torture_assert_int_equal(tctx, types[t], type, "type mismatch");
3337                 torture_assert_int_equal(tctx, needed, offered, "size mismatch");
3338                 torture_assert_mem_equal(tctx, data_out, data.data, offered, "buffer mismatch");
3339
3340                 key = talloc_strdup(tctx, keys[i]);
3341
3342                 if (!test_EnumPrinterDataEx(tctx, p, handle, keys[i])) {
3343                         return false;
3344                 }
3345
3346                 if (!test_DeletePrinterDataEx(tctx, p, handle, keys[i], value_name)) {
3347                         return false;
3348                 }
3349
3350                 c = strchr(key, '\\');
3351                 if (c) {
3352                         int i;
3353
3354                         /* we have subkeys */
3355
3356                         *c = 0;
3357
3358                         if (!test_EnumPrinterKey(tctx, p, handle, key, &subkeys)) {
3359                                 return false;
3360                         }
3361
3362                         for (i=0; subkeys && subkeys[i]; i++) {
3363
3364                                 const char *current_key = talloc_asprintf(tctx, "%s\\%s", key, subkeys[i]);
3365
3366                                 if (!test_DeletePrinterKey(tctx, p, handle, current_key)) {
3367                                         return false;
3368                                 }
3369                         }
3370
3371                         if (!test_DeletePrinterKey(tctx, p, handle, key)) {
3372                                 return false;
3373                         }
3374
3375                 } else {
3376                         if (!test_DeletePrinterKey(tctx, p, handle, key)) {
3377                                 return false;
3378                         }
3379                 }
3380         }
3381         }
3382         }
3383
3384         return true;
3385 }
3386
3387 static bool test_GetChangeID_PrinterData(struct torture_context *tctx,
3388                                          struct dcerpc_pipe *p,
3389                                          struct policy_handle *handle,
3390                                          uint32_t *change_id)
3391 {
3392         enum winreg_Type type;
3393         uint8_t *data;
3394         uint32_t needed;
3395
3396         torture_assert(tctx,
3397                 test_GetPrinterData(tctx, p, handle, "ChangeID", &type, &data, &needed),
3398                 "failed to call GetPrinterData");
3399
3400         torture_assert(tctx, type == REG_DWORD, "unexpected type");
3401         torture_assert_int_equal(tctx, needed, 4, "unexpected size");
3402
3403         *change_id = IVAL(data, 0);
3404
3405         return true;
3406 }
3407
3408 static bool test_GetChangeID_PrinterDataEx(struct torture_context *tctx,
3409                                            struct dcerpc_pipe *p,
3410                                            struct policy_handle *handle,
3411                                            uint32_t *change_id)
3412 {
3413         enum winreg_Type type;
3414         uint8_t *data;
3415         uint32_t needed;
3416
3417         torture_assert(tctx,
3418                 test_GetPrinterDataEx(tctx, p, handle, "PrinterDriverData", "ChangeID", &type, &data, &needed),
3419                 "failed to call GetPrinterData");
3420
3421         torture_assert(tctx, type == REG_DWORD, "unexpected type");
3422         torture_assert_int_equal(tctx, needed, 4, "unexpected size");
3423
3424         *change_id = IVAL(data, 0);
3425
3426         return true;
3427 }
3428
3429 static bool test_GetChangeID_PrinterInfo(struct torture_context *tctx,
3430                                          struct dcerpc_pipe *p,
3431                                          struct policy_handle *handle,
3432                                          uint32_t *change_id)
3433 {
3434         union spoolss_PrinterInfo info;
3435
3436         torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 0, &info),
3437                 "failed to query Printer level 0");
3438
3439         *change_id = info.info0.change_id;
3440
3441         return true;
3442 }
3443
3444 static bool test_ChangeID(struct torture_context *tctx,
3445                           struct dcerpc_pipe *p,
3446                           struct policy_handle *handle)
3447 {
3448         uint32_t change_id, change_id_ex, change_id_info;
3449         uint32_t change_id2, change_id_ex2, change_id_info2;
3450         union spoolss_PrinterInfo info;
3451         const char *comment;
3452
3453
3454         torture_comment(tctx, "Testing ChangeID: id change test #1\n");
3455
3456         torture_assert(tctx, test_GetChangeID_PrinterData(tctx, p, handle, &change_id),
3457                 "failed to query for ChangeID");
3458         torture_assert(tctx, test_GetChangeID_PrinterDataEx(tctx, p, handle, &change_id_ex),
3459                 "failed to query for ChangeID");
3460         torture_assert(tctx, test_GetChangeID_PrinterInfo(tctx, p, handle, &change_id_info),
3461                 "failed to query for ChangeID");
3462
3463         torture_assert_int_equal(tctx, change_id, change_id_ex,
3464                 "change_ids should all be equal");
3465         torture_assert_int_equal(tctx, change_id_ex, change_id_info,
3466                 "change_ids should all be equal");
3467
3468
3469         torture_comment(tctx, "Testing ChangeID: id change test #2\n");
3470
3471         torture_assert(tctx, test_GetChangeID_PrinterData(tctx, p, handle, &change_id),
3472                 "failed to query for ChangeID");
3473         torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 2, &info),
3474                 "failed to query Printer level 2");
3475         torture_assert(tctx, test_GetChangeID_PrinterDataEx(tctx, p, handle, &change_id_ex),
3476                 "failed to query for ChangeID");
3477         torture_assert(tctx, test_GetChangeID_PrinterInfo(tctx, p, handle, &change_id_info),
3478                 "failed to query for ChangeID");
3479         torture_assert_int_equal(tctx, change_id, change_id_ex,
3480                 "change_id should not have changed");
3481         torture_assert_int_equal(tctx, change_id_ex, change_id_info,
3482                 "change_id should not have changed");
3483
3484
3485         torture_comment(tctx, "Testing ChangeID: id change test #3\n");
3486
3487         torture_assert(tctx, test_GetChangeID_PrinterData(tctx, p, handle, &change_id),
3488                 "failed to query for ChangeID");
3489         torture_assert(tctx, test_GetChangeID_PrinterDataEx(tctx, p, handle, &change_id_ex),
3490                 "failed to query for ChangeID");
3491         torture_assert(tctx, test_GetChangeID_PrinterInfo(tctx, p, handle, &change_id_info),
3492                 "failed to query for ChangeID");
3493         torture_assert(tctx, test_GetPrinter_level(tctx, p, handle, 2, &info),
3494                 "failed to query Printer level 2");
3495         comment = talloc_strdup(tctx, info.info2.comment);
3496
3497         {
3498                 struct spoolss_SetPrinterInfoCtr info_ctr;
3499                 struct spoolss_DevmodeContainer devmode_ctr;
3500                 struct sec_desc_buf secdesc_ctr;
3501                 struct spoolss_SetPrinterInfo2 info2;
3502
3503                 ZERO_STRUCT(info_ctr);
3504                 ZERO_STRUCT(devmode_ctr);
3505                 ZERO_STRUCT(secdesc_ctr);
3506
3507                 info2.servername        = info.info2.servername;
3508                 info2.printername       = info.info2.printername;
3509                 info2.sharename         = info.info2.sharename;
3510                 info2.portname          = info.info2.portname;
3511                 info2.drivername        = info.info2.drivername;
3512                 info2.comment           = "torture_comment";
3513                 info2.location          = info.info2.location;
3514                 info2.devmode_ptr       = 0;
3515                 info2.sepfile           = info.info2.sepfile;
3516                 info2.printprocessor    = info.info2.printprocessor;
3517                 info2.datatype          = info.info2.datatype;
3518                 info2.parameters        = info.info2.parameters;
3519                 info2.secdesc_ptr       = 0;
3520                 info2.attributes        = info.info2.attributes;
3521                 info2.priority          = info.info2.priority;
3522                 info2.defaultpriority   = info.info2.defaultpriority;
3523                 info2.starttime         = info.info2.starttime;
3524                 info2.untiltime         = info.info2.untiltime;
3525                 info2.status            = info.info2.status;
3526                 info2.cjobs             = info.info2.cjobs;
3527                 info2.averageppm        = info.info2.averageppm;
3528
3529                 info_ctr.level = 2;
3530                 info_ctr.info.info2 = &info2;
3531
3532                 torture_assert(tctx, test_SetPrinter(tctx, p, handle, &info_ctr, &devmode_ctr, &secdesc_ctr, 0),
3533                         "failed to call SetPrinter");
3534
3535                 info2.comment           = comment;
3536
3537                 torture_assert(tctx, test_SetPrinter(tctx, p, handle, &info_ctr, &devmode_ctr, &secdesc_ctr, 0),
3538                         "failed to call SetPrinter");
3539
3540         }
3541
3542         torture_assert(tctx, test_GetChangeID_PrinterData(tctx, p, handle, &change_id2),
3543                 "failed to query for ChangeID");
3544         torture_assert(tctx, test_GetChangeID_PrinterDataEx(tctx, p, handle, &change_id_ex2),
3545                 "failed to query for ChangeID");
3546         torture_assert(tctx, test_GetChangeID_PrinterInfo(tctx, p, handle, &change_id_info2),
3547                 "failed to query for ChangeID");
3548
3549         torture_assert_int_equal(tctx, change_id2, change_id_ex2,
3550                 "change_ids should all be equal");
3551         torture_assert_int_equal(tctx, change_id_ex2, change_id_info2,
3552                 "change_ids should all be equal");
3553
3554         torture_assert(tctx, (change_id < change_id2),
3555                 talloc_asprintf(tctx, "change_id %d needs to be larger than change_id %d",
3556                 change_id2, change_id));
3557         torture_assert(tctx, (change_id_ex < change_id_ex2),
3558                 talloc_asprintf(tctx, "change_id %d needs to be larger than change_id %d",
3559                 change_id_ex2, change_id_ex));
3560         torture_assert(tctx, (change_id_info < change_id_info2),
3561                 talloc_asprintf(tctx, "change_id %d needs to be larger than change_id %d",
3562                 change_id_info2, change_id_info));
3563
3564         return true;
3565 }
3566
3567 static bool test_SecondaryClosePrinter(struct torture_context *tctx,
3568                                        struct dcerpc_pipe *p,
3569                                        struct policy_handle *handle)
3570 {
3571         NTSTATUS status;
3572         struct dcerpc_binding *b;
3573         struct dcerpc_pipe *p2;
3574         struct spoolss_ClosePrinter cp;
3575
3576         /* only makes sense on SMB */
3577         if (p->conn->transport.transport != NCACN_NP) {
3578                 return true;
3579         }
3580
3581         torture_comment(tctx, "testing close on secondary pipe\n");
3582
3583         status = dcerpc_parse_binding(tctx, p->conn->binding_string, &b);
3584         torture_assert_ntstatus_ok(tctx, status, "Failed to parse dcerpc binding");
3585
3586         status = dcerpc_secondary_connection(p, &p2, b);
3587         torture_assert_ntstatus_ok(tctx, status, "Failed to create secondary connection");
3588
3589         status = dcerpc_bind_auth_none(p2, &ndr_table_spoolss);
3590         torture_assert_ntstatus_ok(tctx, status, "Failed to create bind on secondary connection");
3591
3592         cp.in.handle = handle;
3593         cp.out.handle = handle;
3594
3595         status = dcerpc_spoolss_ClosePrinter(p2, tctx, &cp);
3596         torture_assert_ntstatus_equal(tctx, status, NT_STATUS_NET_WRITE_FAULT,
3597                         "ERROR: Allowed close on secondary connection");
3598
3599         torture_assert_int_equal(tctx, p2->last_fault_code, DCERPC_FAULT_CONTEXT_MISMATCH,
3600                                  "Unexpected fault code");
3601
3602         talloc_free(p2);
3603
3604         return true;
3605 }
3606
3607 static bool test_OpenPrinter_badname(struct torture_context *tctx,
3608                                      struct dcerpc_pipe *p, const char *name)
3609 {
3610         NTSTATUS status;
3611         struct spoolss_OpenPrinter op;
3612         struct spoolss_OpenPrinterEx opEx;
3613         struct policy_handle handle;
3614         bool ret = true;
3615
3616         op.in.printername       = name;
3617         op.in.datatype          = NULL;
3618         op.in.devmode_ctr.devmode= NULL;
3619         op.in.access_mask       = 0;
3620         op.out.handle           = &handle;
3621
3622         torture_comment(tctx, "\nTesting OpenPrinter(%s) with bad name\n", op.in.printername);
3623
3624         status = dcerpc_spoolss_OpenPrinter(p, tctx, &op);
3625         torture_assert_ntstatus_ok(tctx, status, "OpenPrinter failed");
3626         if (!W_ERROR_EQUAL(WERR_INVALID_PRINTER_NAME,op.out.result)) {
3627                 torture_comment(tctx, "OpenPrinter(%s) unexpected result[%s] should be WERR_INVALID_PRINTER_NAME\n",
3628                         name, win_errstr(op.out.result));
3629         }
3630
3631         if (W_ERROR_IS_OK(op.out.result)) {
3632                 ret &=test_ClosePrinter(tctx, p, &handle);
3633         }
3634
3635         opEx.in.printername             = name;
3636         opEx.in.datatype                = NULL;
3637         opEx.in.devmode_ctr.devmode     = NULL;
3638         opEx.in.access_mask             = 0;
3639         opEx.in.level                   = 1;
3640         opEx.in.userlevel.level1        = NULL;
3641         opEx.out.handle                 = &handle;
3642
3643         torture_comment(tctx, "Testing OpenPrinterEx(%s) with bad name\n", opEx.in.printername);
3644
3645         status = dcerpc_spoolss_OpenPrinterEx(p, tctx, &opEx);
3646         torture_assert_ntstatus_ok(tctx, status, "OpenPrinterEx failed");
3647         if (!W_ERROR_EQUAL(WERR_INVALID_PARAM,opEx.out.result)) {
3648                 torture_comment(tctx, "OpenPrinterEx(%s) unexpected result[%s] should be WERR_INVALID_PARAM\n",
3649                         name, win_errstr(opEx.out.result));
3650         }
3651
3652         if (W_ERROR_IS_OK(opEx.out.result)) {
3653                 ret &=test_ClosePrinter(tctx, p, &handle);
3654         }
3655
3656         return ret;
3657 }
3658
3659 static bool test_OpenPrinter(struct torture_context *tctx,
3660                              struct dcerpc_pipe *p,
3661                              const char *name,
3662                              const char *environment)
3663 {
3664         NTSTATUS status;
3665         struct spoolss_OpenPrinter r;
3666         struct policy_handle handle;
3667         bool ret = true;
3668
3669         r.in.printername        = talloc_asprintf(tctx, "\\\\%s\\%s", dcerpc_server_name(p), name);
3670         r.in.datatype           = NULL;
3671         r.in.devmode_ctr.devmode= NULL;
3672         r.in.access_mask        = SEC_FLAG_MAXIMUM_ALLOWED;
3673         r.out.handle            = &handle;
3674
3675         torture_comment(tctx, "Testing OpenPrinter(%s)\n", r.in.printername);
3676
3677         status = dcerpc_spoolss_OpenPrinter(p, tctx, &r);
3678
3679         torture_assert_ntstatus_ok(tctx, status, "OpenPrinter failed");
3680
3681         torture_assert_werr_ok(tctx, r.out.result, "OpenPrinter failed");
3682
3683         if (!test_GetPrinter(tctx, p, &handle, environment)) {
3684                 ret = false;
3685         }
3686
3687         if (!torture_setting_bool(tctx, "samba3", false)) {
3688                 if (!test_SecondaryClosePrinter(tctx, p, &handle)) {
3689                         ret = false;
3690                 }
3691         }
3692
3693         if (!test_ClosePrinter(tctx, p, &handle)) {
3694                 ret = false;
3695         }
3696
3697         return ret;
3698 }
3699
3700 static bool call_OpenPrinterEx(struct torture_context *tctx,
3701                                struct dcerpc_pipe *p,
3702                                const char *name,
3703                                struct spoolss_DeviceMode *devmode,
3704                                struct policy_handle *handle)
3705 {
3706         struct spoolss_OpenPrinterEx r;
3707         struct spoolss_UserLevel1 userlevel1;
3708         NTSTATUS status;
3709
3710         if (name && name[0]) {
3711                 r.in.printername = talloc_asprintf(tctx, "\\\\%s\\%s",
3712                                                    dcerpc_server_name(p), name);
3713         } else {
3714                 r.in.printername = talloc_asprintf(tctx, "\\\\%s",
3715                                                    dcerpc_server_name(p));
3716         }
3717
3718         r.in.datatype           = NULL;
3719         r.in.devmode_ctr.devmode= devmode;
3720         r.in.access_mask        = SEC_FLAG_MAXIMUM_ALLOWED;
3721         r.in.level              = 1;
3722         r.in.userlevel.level1   = &userlevel1;
3723         r.out.handle = handle;
3724
3725         userlevel1.size = 1234;
3726         userlevel1.client = "hello";
3727         userlevel1.user = "spottyfoot!";
3728         userlevel1.build = 1;
3729         userlevel1.major = 2;
3730         userlevel1.minor = 3;
3731         userlevel1.processor = 4;
3732
3733         torture_comment(tctx, "Testing OpenPrinterEx(%s)\n", r.in.printername);
3734
3735         status = dcerpc_spoolss_OpenPrinterEx(p, tctx, &r);
3736
3737         torture_assert_ntstatus_ok(tctx, status, "OpenPrinterEx failed");
3738
3739         torture_assert_werr_ok(tctx, r.out.result, "OpenPrinterEx failed");
3740
3741         return true;
3742 }
3743
3744 static bool test_OpenPrinterEx(struct torture_context *tctx,
3745                                struct dcerpc_pipe *p,
3746                                const char *name,
3747                                const char *environment)
3748 {
3749         struct policy_handle handle;
3750         bool ret = true;
3751
3752         if (!call_OpenPrinterEx(tctx, p, name, NULL, &handle)) {
3753                 return false;
3754         }
3755
3756         if (!test_PrinterInfo_SD(tctx, p, &handle)) {
3757                 ret = false;
3758         }
3759
3760         if (!test_GetPrinter(tctx, p, &handle, environment)) {
3761                 ret = false;
3762         }
3763
3764         if (!test_EnumForms(tctx, p, &handle, false)) {
3765                 ret = false;
3766         }
3767
3768         if (!test_AddForm(tctx, p, &handle, false)) {
3769                 ret = false;
3770         }
3771
3772         if (!test_EnumPrinterData(tctx, p, &handle)) {
3773                 ret = false;
3774         }
3775
3776         if (!test_EnumPrinterDataEx(tctx, p, &handle, "PrinterDriverData")) {
3777                 ret = false;
3778         }
3779
3780         if (!test_printer_keys(tctx, p, &handle)) {
3781                 ret = false;
3782         }
3783
3784         if (!test_PausePrinter(tctx, p, &handle)) {
3785                 ret = false;
3786         }
3787
3788         if (!test_DoPrintTest(tctx, p, &handle)) {
3789                 ret = false;
3790         }
3791
3792         if (!test_ResumePrinter(tctx, p, &handle)) {
3793                 ret = false;
3794         }
3795
3796         if (!test_SetPrinterData(tctx, p, &handle)) {
3797                 ret = false;
3798         }
3799
3800         if (!test_SetPrinterDataEx_matrix(tctx, p, &handle, name)) {
3801                 ret = false;
3802         }
3803
3804         if (!torture_setting_bool(tctx, "samba3", false)) {
3805                 if (!test_SecondaryClosePrinter(tctx, p, &handle)) {
3806                         ret = false;
3807                 }
3808         }
3809
3810         if (!test_ClosePrinter(tctx, p, &handle)) {
3811                 ret = false;
3812         }
3813
3814         return ret;
3815 }
3816
3817 static bool test_EnumPrinters_old(struct torture_context *tctx,
3818                                   struct dcerpc_pipe *p,
3819                                   const char *environment)
3820 {
3821         struct spoolss_EnumPrinters r;
3822         NTSTATUS status;
3823         uint16_t levels[] = {1, 2, 4, 5};
3824         int i;
3825         bool ret = true;
3826
3827         for (i=0;i<ARRAY_SIZE(levels);i++) {
3828                 union spoolss_PrinterInfo *info;
3829                 int j;
3830                 uint32_t needed;
3831                 uint32_t count;
3832
3833                 r.in.flags      = PRINTER_ENUM_LOCAL;
3834                 r.in.server     = "";
3835                 r.in.level      = levels[i];
3836                 r.in.buffer     = NULL;
3837                 r.in.offered    = 0;
3838                 r.out.needed    = &needed;
3839                 r.out.count     = &count;
3840                 r.out.info      = &info;
3841
3842                 torture_comment(tctx, "Testing EnumPrinters level %u\n", r.in.level);
3843
3844                 status = dcerpc_spoolss_EnumPrinters(p, tctx, &r);
3845                 torture_assert_ntstatus_ok(tctx, status, "EnumPrinters failed");
3846
3847                 if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
3848                         DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed);
3849                         data_blob_clear(&blob);
3850                         r.in.buffer = &blob;
3851                         r.in.offered = needed;
3852                         status = dcerpc_spoolss_EnumPrinters(p, tctx, &r);
3853                 }
3854
3855                 torture_assert_ntstatus_ok(tctx, status, "EnumPrinters failed");
3856
3857                 torture_assert_werr_ok(tctx, r.out.result, "EnumPrinters failed");
3858
3859                 CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumPrinters, info, r.in.level, count, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
3860
3861                 if (!info) {
3862                         torture_comment(tctx, "No printers returned\n");
3863                         return true;
3864                 }
3865
3866                 for (j=0;j<count;j++) {
3867                         if (r.in.level == 1) {
3868                                 char *unc = talloc_strdup(tctx, info[j].info1.name);
3869                                 char *slash, *name;
3870                                 name = unc;
3871                                 if (unc[0] == '\\' && unc[1] == '\\') {
3872                                         unc +=2;
3873                                 }
3874                                 slash = strchr(unc, '\\');
3875                                 if (slash) {
3876                                         slash++;
3877                                         name = slash;
3878                                 }
3879                                 if (!test_OpenPrinter(tctx, p, name, environment)) {
3880                                         ret = false;
3881                                 }
3882                                 if (!test_OpenPrinterEx(tctx, p, name, environment)) {
3883                                         ret = false;
3884                                 }
3885                         }
3886                 }
3887         }
3888
3889         return ret;
3890 }
3891
3892 static bool test_GetPrinterDriver(struct torture_context *tctx,
3893                                   struct dcerpc_pipe *p,
3894                                   struct policy_handle *handle,
3895                                   const char *driver_name)
3896 {
3897         struct spoolss_GetPrinterDriver r;
3898         uint32_t needed;
3899
3900         r.in.handle = handle;
3901         r.in.architecture = "W32X86";
3902         r.in.level = 1;
3903         r.in.buffer = NULL;
3904         r.in.offered = 0;
3905         r.out.needed = &needed;
3906
3907         torture_comment(tctx, "Testing GetPrinterDriver level %d\n", r.in.level);
3908
3909         torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_GetPrinterDriver(p, tctx, &r),
3910                 "failed to call GetPrinterDriver");
3911         if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
3912                 DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed);
3913                 data_blob_clear(&blob);
3914                 r.in.buffer = &blob;
3915                 r.in.offered = needed;
3916                 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_GetPrinterDriver(p, tctx, &r),
3917                         "failed to call GetPrinterDriver");
3918         }
3919
3920         torture_assert_werr_ok(tctx, r.out.result,
3921                 "failed to call GetPrinterDriver");
3922
3923         CHECK_NEEDED_SIZE_LEVEL(spoolss_DriverInfo, r.out.info, r.in.level, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
3924
3925         return true;
3926 }
3927
3928 static bool test_GetPrinterDriver2(struct torture_context *tctx,
3929                                    struct dcerpc_pipe *p,
3930                                    struct policy_handle *handle,
3931                                    const char *driver_name,
3932                                    const char *architecture)
3933 {
3934         struct spoolss_GetPrinterDriver2 r;
3935         uint16_t levels[] = {1, 2, 3, 4, 5, 6, 8, 101 };
3936         uint32_t needed;
3937         uint32_t server_major_version;
3938         uint32_t server_minor_version;
3939         int i;
3940
3941         r.in.handle = handle;
3942         r.in.architecture = architecture;
3943         r.in.client_major_version = 3;
3944         r.in.client_minor_version = 0;
3945         r.out.needed = &needed;
3946         r.out.server_major_version = &server_major_version;
3947         r.out.server_minor_version = &server_minor_version;
3948
3949         for (i=0;i<ARRAY_SIZE(levels);i++) {
3950
3951                 r.in.buffer = NULL;
3952                 r.in.offered = 0;
3953                 r.in.level = levels[i];
3954
3955                 torture_comment(tctx, "Testing GetPrinterDriver2(%s) level %d\n",
3956                         driver_name, r.in.level);
3957
3958                 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_GetPrinterDriver2(p, tctx, &r),
3959                         "failed to call GetPrinterDriver2");
3960                 if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
3961                         DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed);
3962                         data_blob_clear(&blob);
3963                         r.in.buffer = &blob;
3964                         r.in.offered = needed;
3965                         torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_GetPrinterDriver2(p, tctx, &r),
3966                                 "failed to call GetPrinterDriver2");
3967                 }
3968
3969                 if (W_ERROR_EQUAL(r.out.result, WERR_INVALID_LEVEL)) {
3970                         switch (r.in.level) {
3971                         case 101:
3972                         case 8:
3973                                 continue;
3974                         default:
3975                                 break;
3976                         }
3977                 }
3978
3979                 torture_assert_werr_ok(tctx, r.out.result,
3980                         "failed to call GetPrinterDriver2");
3981
3982                 CHECK_NEEDED_SIZE_LEVEL(spoolss_DriverInfo, r.out.info, r.in.level, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
3983         }
3984
3985         return true;
3986 }
3987
3988 static bool test_EnumPrinterDrivers_old(struct torture_context *tctx,
3989                                         struct dcerpc_pipe *p,
3990                                         const char *environment)
3991 {
3992         struct spoolss_EnumPrinterDrivers r;
3993         NTSTATUS status;
3994         uint16_t levels[] = {1, 2, 3, 4, 5, 6};
3995         int i;
3996
3997         for (i=0;i<ARRAY_SIZE(levels);i++) {
3998
3999                 uint32_t needed;
4000                 uint32_t count;
4001                 union spoolss_DriverInfo *info;
4002
4003                 r.in.server = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
4004                 r.in.environment = environment;
4005                 r.in.level = levels[i];
4006                 r.in.buffer = NULL;
4007                 r.in.offered = 0;
4008                 r.out.needed = &needed;
4009                 r.out.count = &count;
4010                 r.out.info = &info;
4011
4012                 torture_comment(tctx, "Testing EnumPrinterDrivers level %u\n", r.in.level);
4013
4014                 status = dcerpc_spoolss_EnumPrinterDrivers(p, tctx, &r);
4015
4016                 torture_assert_ntstatus_ok(tctx, status, "EnumPrinterDrivers failed");
4017
4018                 if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
4019                         DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed);
4020                         data_blob_clear(&blob);
4021                         r.in.buffer = &blob;
4022                         r.in.offered = needed;
4023                         status = dcerpc_spoolss_EnumPrinterDrivers(p, tctx, &r);
4024                 }
4025
4026                 torture_assert_ntstatus_ok(tctx, status, "EnumPrinterDrivers failed");
4027
4028                 torture_assert_werr_ok(tctx, r.out.result, "EnumPrinterDrivers failed");
4029
4030                 if (!info) {
4031                         torture_comment(tctx, "No printer drivers returned\n");
4032                         break;
4033                 }
4034
4035                 CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumPrinterDrivers, info, r.in.level, count, lp_iconv_convenience(tctx->lp_ctx), needed, 4);
4036         }
4037
4038         return true;
4039 }
4040
4041 static bool test_DeletePrinter(struct torture_context *tctx,
4042                                struct dcerpc_pipe *p,
4043                                struct policy_handle *handle)
4044 {
4045         struct spoolss_DeletePrinter r;
4046
4047         torture_comment(tctx, "Testing DeletePrinter\n");
4048
4049         r.in.handle = handle;
4050
4051         torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_DeletePrinter(p, tctx, &r),
4052                 "failed to delete printer");
4053         torture_assert_werr_ok(tctx, r.out.result,
4054                 "failed to delete printer");
4055
4056         return true;
4057 }
4058
4059 static bool test_EnumPrinters_findname(struct torture_context *tctx,
4060                                        struct dcerpc_pipe *p,
4061                                        uint32_t flags,
4062                                        uint32_t level,
4063                                        const char *name,
4064                                        bool *found)
4065 {
4066         struct spoolss_EnumPrinters e;
4067         uint32_t count;
4068         union spoolss_PrinterInfo *info;
4069         uint32_t needed;
4070         int i;
4071
4072         *found = false;
4073
4074         e.in.flags = flags;
4075         e.in.server = NULL;
4076         e.in.level = level;
4077         e.in.buffer = NULL;
4078         e.in.offered = 0;
4079         e.out.count = &count;
4080         e.out.info = &info;
4081         e.out.needed = &needed;
4082
4083         torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_EnumPrinters(p, tctx, &e),
4084                 "failed to enum printers");
4085
4086         if (W_ERROR_EQUAL(e.out.result, WERR_INSUFFICIENT_BUFFER)) {
4087                 DATA_BLOB blob = data_blob_talloc(tctx, NULL, needed);
4088                 data_blob_clear(&blob);
4089                 e.in.buffer = &blob;
4090                 e.in.offered = needed;
4091
4092                 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_EnumPrinters(p, tctx, &e),
4093                         "failed to enum printers");
4094         }
4095
4096         torture_assert_werr_ok(tctx, e.out.result,
4097                 "failed to enum printers");
4098
4099         for (i=0; i < count; i++) {
4100
4101                 const char *current = NULL;
4102                 const char *p;
4103
4104                 switch (level) {
4105                 case 1:
4106                         current = info[i].info1.name;
4107                         break;
4108                 }
4109
4110                 if (strequal(current, name)) {
4111                         *found = true;
4112                         break;
4113                 }
4114
4115                 p = strrchr(current, '\\');
4116                 if (p) {
4117                         if (!e.in.server) {
4118                                 torture_warning(tctx,
4119                                         "server returns printername %s incl. servername although we did not set servername", current);
4120                         }
4121                         p++;
4122                         if (strequal(p, name)) {
4123                                 *found = true;
4124                                 break;
4125                         }
4126                 }
4127         }
4128
4129         return true;
4130 }
4131
4132 static bool test_AddPrinter_wellknown(struct torture_context *tctx,
4133                                       struct dcerpc_pipe *p,
4134                                       const char *printername,
4135                                       bool ex)
4136 {
4137         WERROR result;
4138         struct spoolss_AddPrinter r;
4139         struct spoolss_AddPrinterEx rex;
4140         struct spoolss_SetPrinterInfoCtr info_ctr;
4141         struct spoolss_SetPrinterInfo1 info1;
4142         struct spoolss_DevmodeContainer devmode_ctr;
4143         struct sec_desc_buf secdesc_ctr;
4144         struct spoolss_UserLevelCtr userlevel_ctr;
4145         struct policy_handle handle;
4146         bool found = false;
4147
4148         ZERO_STRUCT(devmode_ctr);
4149         ZERO_STRUCT(secdesc_ctr);
4150         ZERO_STRUCT(userlevel_ctr);
4151         ZERO_STRUCT(info1);
4152
4153         torture_comment(tctx, "Testing AddPrinter%s level 1\n", ex ? "Ex":"");
4154
4155         /* try to add printer to wellknown printer list (level 1) */
4156
4157         userlevel_ctr.level = 1;
4158
4159         info_ctr.info.info1 = &info1;
4160         info_ctr.level = 1;
4161
4162         rex.in.server = NULL;
4163         rex.in.info_ctr = &info_ctr;
4164         rex.in.devmode_ctr = &devmode_ctr;
4165         rex.in.secdesc_ctr = &secdesc_ctr;
4166         rex.in.userlevel_ctr = &userlevel_ctr;
4167         rex.out.handle = &handle;
4168
4169         r.in.server = NULL;
4170         r.in.info_ctr = &info_ctr;
4171         r.in.devmode_ctr = &devmode_ctr;
4172         r.in.secdesc_ctr = &secdesc_ctr;
4173         r.out.handle = &handle;
4174
4175         torture_assert_ntstatus_ok(tctx, ex ? dcerpc_spoolss_AddPrinterEx(p, tctx, &rex) :
4176                                               dcerpc_spoolss_AddPrinter(p, tctx, &r),
4177                 "failed to add printer");
4178         result = ex ? rex.out.result : r.out.result;
4179         torture_assert_werr_equal(tctx, result, WERR_INVALID_PRINTER_NAME,
4180                 "unexpected result code");
4181
4182         info1.name = printername;
4183         info1.flags = PRINTER_ATTRIBUTE_SHARED;
4184
4185         torture_assert_ntstatus_ok(tctx, ex ? dcerpc_spoolss_AddPrinterEx(p, tctx, &rex) :
4186                                               dcerpc_spoolss_AddPrinter(p, tctx, &r),
4187                 "failed to add printer");
4188         result = ex ? rex.out.result : r.out.result;
4189         torture_assert_werr_equal(tctx, result, WERR_PRINTER_ALREADY_EXISTS,
4190                 "unexpected result code");
4191
4192         /* bizarre protocol, WERR_PRINTER_ALREADY_EXISTS means success here,
4193            better do a real check to see the printer is really there */
4194
4195         torture_assert(tctx, test_EnumPrinters_findname(tctx, p,
4196                                                         PRINTER_ENUM_NETWORK, 1,
4197                                                         printername,
4198                                                         &found),
4199                         "failed to enum printers");
4200
4201         torture_assert(tctx, found, "failed to find newly added printer");
4202
4203         info1.flags = 0;
4204
4205         torture_assert_ntstatus_ok(tctx, ex ? dcerpc_spoolss_AddPrinterEx(p, tctx, &rex) :
4206                                               dcerpc_spoolss_AddPrinter(p, tctx, &r),
4207                 "failed to add printer");
4208         result = ex ? rex.out.result : r.out.result;
4209         torture_assert_werr_equal(tctx, result, WERR_PRINTER_ALREADY_EXISTS,
4210                 "unexpected result code");
4211
4212         /* bizarre protocol, WERR_PRINTER_ALREADY_EXISTS means success here,
4213            better do a real check to see the printer has really been removed
4214            from the well known printer list */
4215
4216         found = false;
4217
4218         torture_assert(tctx, test_EnumPrinters_findname(tctx, p,
4219                                                         PRINTER_ENUM_NETWORK, 1,
4220                                                         printername,
4221                                                         &found),
4222                         "failed to enum printers");
4223 #if 0
4224         torture_assert(tctx, !found, "printer still in well known printer list");
4225 #endif
4226         return true;
4227 }
4228
4229 static bool test_AddPrinter_normal(struct torture_context *tctx,
4230                                    struct dcerpc_pipe *p,
4231                                    struct policy_handle *handle_p,
4232                                    const char *printername,
4233                                    const char *drivername,
4234                                    const char *portname,
4235                                    bool ex)
4236 {
4237         WERROR result;
4238         struct spoolss_AddPrinter r;
4239         struct spoolss_AddPrinterEx rex;
4240         struct spoolss_SetPrinterInfoCtr info_ctr;
4241         struct spoolss_SetPrinterInfo2 info2;
4242         struct spoolss_DevmodeContainer devmode_ctr;
4243         struct sec_desc_buf secdesc_ctr;
4244         struct spoolss_UserLevelCtr userlevel_ctr;
4245         struct policy_handle handle;
4246         bool found = false;
4247         bool existing_printer_deleted = false;
4248
4249         ZERO_STRUCT(devmode_ctr);
4250         ZERO_STRUCT(secdesc_ctr);
4251         ZERO_STRUCT(userlevel_ctr);
4252
4253         torture_comment(tctx, "Testing AddPrinter%s level 2\n", ex ? "Ex":"");
4254
4255         userlevel_ctr.level = 1;
4256
4257         rex.in.server = NULL;
4258         rex.in.info_ctr = &info_ctr;
4259         rex.in.devmode_ctr = &devmode_ctr;
4260         rex.in.secdesc_ctr = &secdesc_ctr;
4261         rex.in.userlevel_ctr = &userlevel_ctr;
4262         rex.out.handle = &handle;
4263
4264         r.in.server = NULL;
4265         r.in.info_ctr = &info_ctr;
4266         r.in.devmode_ctr = &devmode_ctr;
4267         r.in.secdesc_ctr = &secdesc_ctr;
4268         r.out.handle = &handle;
4269
4270  again:
4271
4272         /* try to add printer to printer list (level 2) */
4273
4274         ZERO_STRUCT(info2);
4275
4276         info_ctr.info.info2 = &info2;
4277         info_ctr.level = 2;
4278
4279         torture_assert_ntstatus_ok(tctx, ex ? dcerpc_spoolss_AddPrinterEx(p, tctx, &rex) :
4280                                               dcerpc_spoolss_AddPrinter(p, tctx, &r),
4281                 "failed to add printer");
4282         result = ex ? rex.out.result : r.out.result;
4283         torture_assert_werr_equal(tctx, result, WERR_INVALID_PRINTER_NAME,
4284                 "unexpected result code");
4285
4286         info2.printername = printername;
4287
4288         torture_assert_ntstatus_ok(tctx, ex ? dcerpc_spoolss_AddPrinterEx(p, tctx, &rex) :
4289                                               dcerpc_spoolss_AddPrinter(p, tctx, &r),
4290                 "failed to add printer");
4291         result = ex ? rex.out.result : r.out.result;
4292
4293         if (W_ERROR_EQUAL(result, WERR_PRINTER_ALREADY_EXISTS)) {
4294                 struct policy_handle printer_handle;
4295
4296                 if (existing_printer_deleted) {
4297                         torture_fail(tctx, "already deleted printer still existing?");
4298                 }
4299
4300                 torture_assert(tctx, call_OpenPrinterEx(tctx, p, printername, NULL, &printer_handle),
4301                         "failed to open printer handle");
4302
4303                 torture_assert(tctx, test_DeletePrinter(tctx, p, &printer_handle),
4304                         "failed to delete printer");
4305
4306                 torture_assert(tctx, test_ClosePrinter(tctx, p, &printer_handle),
4307                         "failed to close server handle");
4308
4309                 existing_printer_deleted = true;
4310
4311                 goto again;
4312         }
4313
4314         torture_assert_werr_equal(tctx, result, WERR_UNKNOWN_PORT,
4315                 "unexpected result code");
4316
4317         info2.portname = portname;
4318
4319         torture_assert_ntstatus_ok(tctx, ex ? dcerpc_spoolss_AddPrinterEx(p, tctx, &rex) :
4320                                               dcerpc_spoolss_AddPrinter(p, tctx, &r),
4321                 "failed to add printer");
4322         result = ex ? rex.out.result : r.out.result;
4323         torture_assert_werr_equal(tctx, result, WERR_UNKNOWN_PRINTER_DRIVER,
4324                 "unexpected result code");
4325
4326         info2.drivername = drivername;
4327
4328         torture_assert_ntstatus_ok(tctx, ex ? dcerpc_spoolss_AddPrinterEx(p, tctx, &rex) :
4329                                               dcerpc_spoolss_AddPrinter(p, tctx, &r),
4330                 "failed to add printer");
4331         result = ex ? rex.out.result : r.out.result;
4332
4333         /* w2k8r2 allows to add printer w/o defining printprocessor */
4334
4335         if (!W_ERROR_IS_OK(result)) {
4336                 torture_assert_werr_equal(tctx, result, WERR_UNKNOWN_PRINTPROCESSOR,
4337                         "unexpected result code");
4338
4339                 info2.printprocessor = "winprint";
4340
4341                 torture_assert_ntstatus_ok(tctx, ex ? dcerpc_spoolss_AddPrinterEx(p, tctx, &rex) :
4342                                                       dcerpc_spoolss_AddPrinter(p, tctx, &r),
4343                         "failed to add printer");
4344                 result = ex ? rex.out.result : r.out.result;
4345                 torture_assert_werr_ok(tctx, result,
4346                         "failed to add printer");
4347         }
4348
4349         *handle_p = handle;
4350
4351         /* we are paranoid, really check if the printer is there now */
4352
4353         torture_assert(tctx, test_EnumPrinters_findname(tctx, p,
4354                                                         PRINTER_ENUM_LOCAL, 1,
4355                                                         printername,
4356                                                         &found),
4357                         "failed to enum printers");
4358         torture_assert(tctx, found, "failed to find newly added printer");
4359
4360         torture_assert_ntstatus_ok(tctx, ex ? dcerpc_spoolss_AddPrinterEx(p, tctx, &rex) :
4361                                               dcerpc_spoolss_AddPrinter(p, tctx, &r),
4362                 "failed to add printer");
4363         result = ex ? rex.out.result : r.out.result;
4364         torture_assert_werr_equal(tctx, result, WERR_PRINTER_ALREADY_EXISTS,
4365                 "unexpected result code");
4366
4367         return true;
4368 }
4369
4370 static bool test_AddPrinterEx(struct torture_context *tctx,
4371                               struct dcerpc_pipe *p,
4372                               struct policy_handle *handle_p,
4373                               const char *printername,
4374                               const char *drivername,
4375                               const char *portname)
4376 {
4377         bool ret = true;
4378
4379         if (!torture_setting_bool(tctx, "samba3", false)) {
4380                 if (!test_AddPrinter_wellknown(tctx, p, TORTURE_WELLKNOWN_PRINTER_EX, true)) {
4381                         torture_comment(tctx, "failed to add printer to well known list\n");
4382                         ret = false;
4383                 }
4384         }
4385
4386         if (!test_AddPrinter_normal(tctx, p, handle_p,
4387                                     printername, drivername, portname,
4388                                     true)) {
4389                 torture_comment(tctx, "failed to add printer to printer list\n");
4390                 ret = false;
4391         }
4392
4393         return ret;
4394 }
4395
4396 static bool test_AddPrinter(struct torture_context *tctx,
4397                             struct dcerpc_pipe *p,
4398                             struct policy_handle *handle_p,
4399                             const char *printername,
4400                             const char *drivername,
4401                             const char *portname)
4402 {
4403         bool ret = true;
4404
4405         if (!torture_setting_bool(tctx, "samba3", false)) {
4406                 if (!test_AddPrinter_wellknown(tctx, p, TORTURE_WELLKNOWN_PRINTER, false)) {
4407                         torture_comment(tctx, "failed to add printer to well known list\n");
4408                         ret = false;
4409                 }
4410         }
4411
4412         if (!test_AddPrinter_normal(tctx, p, handle_p,
4413                                     printername, drivername, portname,
4414                                     false)) {
4415                 torture_comment(tctx, "failed to add printer to printer list\n");
4416                 ret = false;
4417         }
4418
4419         return ret;
4420 }
4421
4422 static bool test_printer_info(struct torture_context *tctx,
4423                               struct dcerpc_pipe *p,
4424                               struct policy_handle *handle)
4425 {
4426         bool ret = true;
4427
4428         if (torture_setting_bool(tctx, "samba3", false)) {
4429                 torture_skip(tctx, "skipping printer info cross tests against samba 3");
4430         }
4431
4432         if (!test_PrinterInfo(tctx, p, handle)) {
4433                 ret = false;
4434         }
4435
4436         if (!test_SetPrinter_errors(tctx, p, handle)) {
4437                 ret = false;
4438         }
4439
4440         return ret;
4441 }
4442
4443 static bool test_EnumPrinterKey(struct torture_context *tctx,
4444                                 struct dcerpc_pipe *p,
4445                                 struct policy_handle *handle,
4446                                 const char *key_name,
4447                                 const char ***array)
4448 {
4449         struct spoolss_EnumPrinterKey r;
4450         uint32_t needed = 0;
4451         union spoolss_KeyNames key_buffer;
4452         int32_t offered[] = { 0, 1, 2, 3, 4, 5, -1, -2, -3, -4, -5, 256, 512, 1024, 2048 };
4453         uint32_t _ndr_size;
4454         int i;
4455
4456         r.in.handle = handle;
4457         r.in.key_name = key_name;
4458         r.out.key_buffer = &key_buffer;
4459         r.out.needed = &needed;
4460         r.out._ndr_size = &_ndr_size;
4461
4462         for (i=0; i < ARRAY_SIZE(offered); i++) {
4463
4464                 if (offered[i] < 0 && needed) {
4465                         if (needed <= 4) {
4466                                 continue;
4467                         }
4468                         r.in.offered = needed + offered[i];
4469                 } else {
4470                         r.in.offered = offered[i];
4471                 }
4472
4473                 ZERO_STRUCT(key_buffer);
4474
4475                 torture_comment(tctx, "Testing EnumPrinterKey(%s) with %d offered\n", r.in.key_name, r.in.offered);
4476
4477                 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_EnumPrinterKey(p, tctx, &r),
4478                         "failed to call EnumPrinterKey");
4479                 if (W_ERROR_EQUAL(r.out.result, WERR_MORE_DATA)) {
4480
4481                         torture_assert(tctx, (_ndr_size == r.in.offered/2),
4482                                 talloc_asprintf(tctx, "EnumPrinterKey size mismatch, _ndr_size %d (expected %d)",
4483                                         _ndr_size, r.in.offered/2));
4484
4485                         r.in.offered = needed;
4486                         torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_EnumPrinterKey(p, tctx, &r),
4487                                 "failed to call EnumPrinterKey");
4488                 }
4489
4490                 if (offered[i] > 0) {
4491                         torture_assert_werr_ok(tctx, r.out.result,
4492                                 "failed to call EnumPrinterKey");
4493                 }
4494
4495                 torture_assert(tctx, (_ndr_size == r.in.offered/2),
4496                         talloc_asprintf(tctx, "EnumPrinterKey size mismatch, _ndr_size %d (expected %d)",
4497                                 _ndr_size, r.in.offered/2));
4498
4499                 torture_assert(tctx, (*r.out.needed <= r.in.offered),
4500                         talloc_asprintf(tctx, "EnumPrinterKey size mismatch: needed %d is not <= offered %d", *r.out.needed, r.in.offered));
4501
4502                 torture_assert(tctx, (*r.out.needed <= _ndr_size * 2),
4503                         talloc_asprintf(tctx, "EnumPrinterKey size mismatch: needed %d is not <= _ndr_size %d * 2", *r.out.needed, _ndr_size));
4504
4505                 if (key_buffer.string_array) {
4506                         uint32_t calc_needed = 0;
4507                         int s;
4508                         for (s=0; key_buffer.string_array[s]; s++) {
4509                                 calc_needed += strlen_m_term(key_buffer.string_array[s])*2;
4510                         }
4511                         if (!key_buffer.string_array[0]) {
4512                                 calc_needed += 2;
4513                         }
4514                         calc_needed += 2;
4515
4516                         torture_assert_int_equal(tctx, *r.out.needed, calc_needed,
4517                                 "EnumPrinterKey unexpected size");
4518                 }
4519         }
4520
4521         if (array) {
4522                 *array = key_buffer.string_array;
4523         }
4524
4525         return true;
4526 }
4527
4528 bool test_printer_keys(struct torture_context *tctx,
4529                        struct dcerpc_pipe *p,
4530                        struct policy_handle *handle)
4531 {
4532         const char **key_array = NULL;
4533         int i;
4534
4535         torture_comment(tctx, "\nTesting Printer Keys\n");
4536
4537         torture_assert(tctx, test_EnumPrinterKey(tctx, p, handle, "", &key_array),
4538                 "failed to call test_EnumPrinterKey");
4539
4540         for (i=0; key_array && key_array[i]; i++) {
4541                 torture_assert(tctx, test_EnumPrinterKey(tctx, p, handle, key_array[i], NULL),
4542                         "failed to call test_EnumPrinterKey");
4543         }
4544         for (i=0; key_array && key_array[i]; i++) {
4545                 torture_assert(tctx, test_EnumPrinterDataEx(tctx, p, handle, key_array[i]),
4546                         "failed to call test_EnumPrinterDataEx");
4547         }
4548
4549         return true;
4550 }
4551
4552 static bool test_one_printer(struct torture_context *tctx,
4553                              struct dcerpc_pipe *p,
4554                              struct policy_handle *handle,
4555                              const char *name)
4556 {
4557         bool ret = true;
4558
4559         if (!test_printer_info(tctx, p, handle)) {
4560                 ret = false;
4561         }
4562
4563         if (!test_PrinterInfo_SD(tctx, p, handle)) {
4564                 ret = false;
4565         }
4566
4567         if (!test_PrinterInfo_DevMode(tctx, p, handle, name)) {
4568                 ret = false;
4569         }
4570
4571         if (!test_ChangeID(tctx, p, handle)) {
4572                 ret = false;
4573         }
4574
4575         if (!test_printer_keys(tctx, p, handle)) {
4576                 ret = false;
4577         }
4578
4579         if (!test_SetPrinterDataEx_matrix(tctx, p, handle, name)) {
4580                 ret = false;
4581         }
4582
4583         return ret;
4584 }
4585
4586 static bool test_printer(struct torture_context *tctx,
4587                          struct dcerpc_pipe *p)
4588 {
4589         bool ret = true;
4590         struct policy_handle handle[2];
4591         bool found = false;
4592         const char *drivername = "Microsoft XPS Document Writer";
4593         const char *portname = "LPT1:";
4594
4595         /* test printer created via AddPrinter */
4596
4597         if (!test_AddPrinter(tctx, p, &handle[0], TORTURE_PRINTER, drivername, portname)) {
4598                 return false;
4599         }
4600
4601         if (!test_one_printer(tctx, p, &handle[0], TORTURE_PRINTER)) {
4602                 ret = false;
4603         }
4604
4605         if (!test_DeletePrinter(tctx, p, &handle[0])) {
4606                 ret = false;
4607         }
4608
4609         if (!test_EnumPrinters_findname(tctx, p, PRINTER_ENUM_LOCAL, 1,
4610                                         TORTURE_PRINTER, &found)) {
4611                 ret = false;
4612         }
4613
4614         torture_assert(tctx, !found, "deleted printer still there");
4615
4616         /* test printer created via AddPrinterEx */
4617
4618         if (!test_AddPrinterEx(tctx, p, &handle[1], TORTURE_PRINTER_EX, drivername, portname)) {
4619                 return false;
4620         }
4621
4622         if (!test_one_printer(tctx, p, &handle[1], TORTURE_PRINTER_EX)) {
4623                 ret = false;
4624         }
4625
4626         if (!test_DeletePrinter(tctx, p, &handle[1])) {
4627                 ret = false;
4628         }
4629
4630         if (!test_EnumPrinters_findname(tctx, p, PRINTER_ENUM_LOCAL, 1,
4631                                         TORTURE_PRINTER_EX, &found)) {
4632                 ret = false;
4633         }
4634
4635         torture_assert(tctx, !found, "deleted printer still there");
4636
4637         return ret;
4638 }
4639
4640 static bool test_architecture_buffer(struct torture_context *tctx,
4641                                      struct dcerpc_pipe *p)
4642 {
4643         struct spoolss_OpenPrinterEx r;
4644         struct spoolss_UserLevel1 u1;
4645         struct policy_handle handle;
4646         uint32_t architectures[] = {
4647                 PROCESSOR_ARCHITECTURE_INTEL,
4648                 PROCESSOR_ARCHITECTURE_IA64,
4649                 PROCESSOR_ARCHITECTURE_AMD64
4650         };
4651         uint32_t needed[3];
4652         int i;
4653
4654         for (i=0; i < ARRAY_SIZE(architectures); i++) {
4655
4656                 torture_comment(tctx, "Testing OpenPrinterEx with architecture %d\n", architectures[i]);
4657
4658                 u1.size = 0;
4659                 u1.client = NULL;
4660                 u1.user = NULL;
4661                 u1.build = 0;
4662                 u1.major = 3;
4663                 u1.minor = 0;
4664                 u1.processor = architectures[i];
4665
4666                 r.in.printername        = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
4667                 r.in.datatype           = NULL;
4668                 r.in.devmode_ctr.devmode= NULL;
4669                 r.in.access_mask        = SEC_FLAG_MAXIMUM_ALLOWED;
4670                 r.in.level               = 1;
4671                 r.in.userlevel.level1   = &u1;
4672                 r.out.handle            = &handle;
4673
4674                 torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_OpenPrinterEx(p, tctx, &r), "");
4675                 torture_assert_werr_ok(tctx, r.out.result, "");
4676
4677                 {
4678                         struct spoolss_EnumPrinters e;
4679                         uint32_t count;
4680                         union spoolss_PrinterInfo *info;
4681
4682                         e.in.flags = PRINTER_ENUM_LOCAL;
4683                         e.in.server = NULL;
4684                         e.in.level = 2;
4685                         e.in.buffer = NULL;
4686                         e.in.offered = 0;
4687                         e.out.count = &count;
4688                         e.out.info = &info;
4689                         e.out.needed = &needed[i];
4690
4691                         torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_EnumPrinters(p, tctx, &e), "");
4692 #if 0
4693                         torture_comment(tctx, "needed was %d\n", needed[i]);
4694 #endif
4695                 }
4696
4697                 torture_assert(tctx, test_ClosePrinter(tctx, p, &handle), "");
4698         }
4699
4700         for (i=1; i < ARRAY_SIZE(architectures); i++) {
4701                 if (needed[i-1] != needed[i]) {
4702                         torture_fail(tctx,
4703                                 talloc_asprintf(tctx, "needed size %d for architecture %d != needed size %d for architecture %d\n",
4704                                                 needed[i-1], architectures[i-1], needed[i], architectures[i]));
4705                 }
4706         }
4707
4708         return true;
4709 }
4710
4711 bool torture_rpc_spoolss(struct torture_context *torture)
4712 {
4713         NTSTATUS status;
4714         struct dcerpc_pipe *p;
4715         bool ret = true;
4716         struct test_spoolss_context *ctx;
4717         const char *environment = SPOOLSS_ARCHITECTURE_NT_X86;
4718
4719         status = torture_rpc_connection(torture, &p, &ndr_table_spoolss);
4720         if (!NT_STATUS_IS_OK(status)) {
4721                 return false;
4722         }
4723
4724         ctx = talloc_zero(torture, struct test_spoolss_context);
4725
4726         ret &= test_OpenPrinter_server(torture, p, &ctx->server_handle);
4727         ret &= test_GetPrinterData_list(torture, p, &ctx->server_handle);
4728         ret &= test_EnumForms(torture, p, &ctx->server_handle, true);
4729         ret &= test_AddForm(torture, p, &ctx->server_handle, true);
4730         ret &= test_EnumPorts(torture, p, ctx);
4731         ret &= test_GetPrinterDriverDirectory(torture, p, ctx, environment);
4732         ret &= test_GetPrintProcessorDirectory(torture, p, ctx, environment);
4733         ret &= test_EnumPrinterDrivers(torture, p, ctx, environment);
4734         ret &= test_EnumPrinterDrivers(torture, p, ctx, SPOOLSS_ARCHITECTURE_ALL);
4735         ret &= test_EnumMonitors(torture, p, ctx);
4736         ret &= test_EnumPrintProcessors(torture, p, ctx, environment);
4737         ret &= test_EnumPrintProcDataTypes(torture, p, ctx);
4738         ret &= test_EnumPrinters(torture, p, ctx);
4739         ret &= test_OpenPrinter_badname(torture, p, "__INVALID_PRINTER__");
4740         ret &= test_OpenPrinter_badname(torture, p, "\\\\__INVALID_HOST__");
4741         ret &= test_OpenPrinter_badname(torture, p, "");
4742         ret &= test_OpenPrinter_badname(torture, p, "\\\\\\");
4743         ret &= test_OpenPrinter_badname(torture, p, "\\\\\\__INVALID_PRINTER__");
4744         ret &= test_OpenPrinter_badname(torture, p, talloc_asprintf(torture, "\\\\%s\\", dcerpc_server_name(p)));
4745         ret &= test_OpenPrinter_badname(torture, p,
4746                                         talloc_asprintf(torture, "\\\\%s\\__INVALID_PRINTER__", dcerpc_server_name(p)));
4747
4748
4749         ret &= test_AddPort(torture, p);
4750         ret &= test_EnumPorts_old(torture, p);
4751         ret &= test_EnumPrinters_old(torture, p, environment);
4752         ret &= test_EnumPrinterDrivers_old(torture, p, environment);
4753         ret &= test_architecture_buffer(torture, p);
4754
4755         return ret;
4756 }
4757
4758 struct torture_suite *torture_rpc_spoolss_printer(TALLOC_CTX *mem_ctx)
4759 {
4760         struct torture_suite *suite = torture_suite_create(mem_ctx, "SPOOLSS-PRINTER");
4761
4762         struct torture_rpc_tcase *tcase = torture_suite_add_rpc_iface_tcase(suite,
4763                                                         "printer", &ndr_table_spoolss);
4764
4765         torture_rpc_tcase_add_test(tcase, "printer", test_printer);
4766
4767         return suite;
4768 }