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