Merge commit 'release-4-0-0alpha1' into v4-0-test
[ira/wip.git] / source4 / torture / rpc / spoolss.c
1 /* 
2    Unix SMB/CIFS implementation.
3    test suite for spoolss rpc operations
4
5    Copyright (C) Tim Potter 2003
6    Copyright (C) Stefan Metzmacher 2005
7    Copyright (C) Jelmer Vernooij 2007
8    
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 3 of the License, or
12    (at your option) any later version.
13    
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18    
19    You should have received a copy of the GNU General Public License
20    along with this program.  If not, see <http://www.gnu.org/licenses/>.
21 */
22
23 #include "includes.h"
24 #include "torture/torture.h"
25 #include "torture/rpc/rpc.h"
26 #include "librpc/gen_ndr/ndr_spoolss_c.h"
27
28 struct test_spoolss_context {
29         /* print server handle */
30         struct policy_handle server_handle;
31
32         /* for EnumPorts */
33         uint32_t port_count[3];
34         union spoolss_PortInfo *ports[3];
35
36         /* for EnumPrinterDrivers */
37         uint32_t driver_count[7];
38         union spoolss_DriverInfo *drivers[7];
39
40         /* for EnumMonitors */
41         uint32_t monitor_count[3];
42         union spoolss_MonitorInfo *monitors[3];
43
44         /* for EnumPrintProcessors */
45         uint32_t print_processor_count[2];
46         union spoolss_PrintProcessorInfo *print_processors[2];
47
48         /* for EnumPrinters */
49         uint32_t printer_count[6];
50         union spoolss_PrinterInfo *printers[6];
51 };
52
53 #define COMPARE_STRING(tctx, c,r,e) \
54         torture_assert_str_equal(tctx, c.e, r.e, "invalid value")
55
56 /* not every compiler supports __typeof__() */
57 #if (__GNUC__ >= 3)
58 #define _CHECK_FIELD_SIZE(c,r,e,type) do {\
59         if (sizeof(__typeof__(c.e)) != sizeof(type)) { \
60                 torture_fail(tctx, #c "." #e "field is not " #type "\n"); \
61         }\
62         if (sizeof(__typeof__(r.e)) != sizeof(type)) { \
63                 torture_fail(tctx, #r "." #e "field is not " #type "\n"); \
64         }\
65 } while(0)
66 #else
67 #define _CHECK_FIELD_SIZE(c,r,e,type) do {} while(0)
68 #endif
69
70 #define COMPARE_UINT32(tctx, c, r, e) do {\
71         _CHECK_FIELD_SIZE(c, r, e, uint32_t); \
72         torture_assert_int_equal(tctx, c.e, r.e, "invalid value"); \
73 } while(0)
74
75 #define COMPARE_STRING_ARRAY(tctx, c,r,e)
76
77 static bool test_OpenPrinter_server(struct torture_context *tctx, struct dcerpc_pipe *p, struct test_spoolss_context *ctx)
78 {
79         NTSTATUS status;
80         struct spoolss_OpenPrinter op;
81
82         op.in.printername       = talloc_asprintf(ctx, "\\\\%s", dcerpc_server_name(p));
83         op.in.datatype          = NULL;
84         op.in.devmode_ctr.devmode= NULL;
85         op.in.access_mask       = 0;
86         op.out.handle           = &ctx->server_handle;
87
88         torture_comment(tctx, "Testing OpenPrinter(%s)\n", op.in.printername);
89
90         status = dcerpc_spoolss_OpenPrinter(p, ctx, &op);
91         torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_OpenPrinter failed");
92         torture_assert_werr_ok(tctx, op.out.result, "dcerpc_spoolss_OpenPrinter failed"); 
93
94         return true;
95 }
96
97 static bool test_EnumPorts(struct torture_context *tctx, 
98                            struct dcerpc_pipe *p, 
99                            struct test_spoolss_context *ctx)
100 {
101         NTSTATUS status;
102         struct spoolss_EnumPorts r;
103         uint16_t levels[] = { 1, 2 };
104         int i, j;
105
106         for (i=0;i<ARRAY_SIZE(levels);i++) {
107                 int level = levels[i];
108                 DATA_BLOB blob;
109
110                 r.in.servername = "";
111                 r.in.level = level;
112                 r.in.buffer = NULL;
113                 r.in.offered = 0;
114
115                 torture_comment(tctx, "Testing EnumPorts level %u\n", r.in.level);
116
117                 status = dcerpc_spoolss_EnumPorts(p, ctx, &r);
118                 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EnumPorts failed");
119                 if (W_ERROR_IS_OK(r.out.result)) {
120                         /* TODO: do some more checks here */
121                         continue;
122                 }
123                 torture_assert_werr_equal(tctx, r.out.result, WERR_INSUFFICIENT_BUFFER, 
124                         "EnumPorts unexpected return code");
125
126                 blob = data_blob_talloc(ctx, NULL, r.out.needed);
127                 data_blob_clear(&blob);
128                 r.in.buffer = &blob;
129                 r.in.offered = r.out.needed;
130
131                 status = dcerpc_spoolss_EnumPorts(p, ctx, &r);
132                 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EnumPorts failed");
133
134                 torture_assert_werr_ok(tctx, r.out.result, "EnumPorts failed");
135
136                 ctx->port_count[level]  = r.out.count;
137                 ctx->ports[level]       = r.out.info;
138         }
139
140         for (i=1;i<ARRAY_SIZE(levels);i++) {
141                 int level = levels[i];
142                 int old_level = levels[i-1];
143                 torture_assert_int_equal(tctx, ctx->port_count[level], ctx->port_count[old_level], 
144                         "EnumPorts invalid value");
145         }
146         /* if the array sizes are not the same we would maybe segfault in the following code */
147
148         for (i=0;i<ARRAY_SIZE(levels);i++) {
149                 int level = levels[i];
150                 for (j=0;j<ctx->port_count[level];j++) {
151                         union spoolss_PortInfo *cur = &ctx->ports[level][j];
152                         union spoolss_PortInfo *ref = &ctx->ports[2][j];
153                         switch (level) {
154                         case 1:
155                                 COMPARE_STRING(tctx, cur->info1, ref->info2, port_name);
156                                 break;
157                         case 2:
158                                 /* level 2 is our reference, and it makes no sense to compare it to itself */
159                                 break;
160                         }
161                 }
162         }
163
164         return true;
165 }
166
167 static bool test_GetPrinterDriverDirectory(struct torture_context *tctx, 
168                                            struct dcerpc_pipe *p, 
169                                            struct test_spoolss_context *ctx)
170 {
171         NTSTATUS status;
172         struct spoolss_GetPrinterDriverDirectory r;
173         struct {
174                 uint16_t level;
175                 const char *server;
176         } levels[] = {{
177                         .level  = 1,
178                         .server = NULL
179                 },{
180                         .level  = 1,
181                         .server = ""
182                 },{
183                         .level  = 78,
184                         .server = ""
185                 },{
186                         .level  = 1,
187                         .server = talloc_asprintf(ctx, "\\\\%s", dcerpc_server_name(p))
188                 },{
189                         .level  = 1024,
190                         .server = talloc_asprintf(ctx, "\\\\%s", dcerpc_server_name(p))
191                 }
192         };
193         int i;
194
195         for (i=0;i<ARRAY_SIZE(levels);i++) {
196                 int level = levels[i].level;
197                 DATA_BLOB blob;
198
199                 r.in.server             = levels[i].server;
200                 r.in.environment        = SPOOLSS_ARCHITECTURE_NT_X86;
201                 r.in.level              = level;
202                 r.in.buffer             = NULL;
203                 r.in.offered            = 0;
204
205                 torture_comment(tctx, "Testing GetPrinterDriverDirectory level %u\n", r.in.level);
206
207                 status = dcerpc_spoolss_GetPrinterDriverDirectory(p, ctx, &r);
208                 torture_assert_ntstatus_ok(tctx, status, 
209                         "dcerpc_spoolss_GetPrinterDriverDirectory failed");
210                 torture_assert_werr_equal(tctx, r.out.result, WERR_INSUFFICIENT_BUFFER, 
211                         "GetPrinterDriverDirectory unexpected return code");
212
213                 blob = data_blob_talloc(ctx, NULL, r.out.needed);
214                 data_blob_clear(&blob);
215                 r.in.buffer = &blob;
216                 r.in.offered = r.out.needed;
217
218                 status = dcerpc_spoolss_GetPrinterDriverDirectory(p, ctx, &r);
219                 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_GetPrinterDriverDirectory failed");
220
221                 torture_assert_werr_ok(tctx, r.out.result, "GetPrinterDriverDirectory failed");
222         }
223
224         return true;
225 }
226
227 static bool test_EnumPrinterDrivers(struct torture_context *tctx, 
228                                     struct dcerpc_pipe *p,
229                                     struct test_spoolss_context *ctx)
230 {
231         NTSTATUS status;
232         struct spoolss_EnumPrinterDrivers r;
233         uint16_t levels[] = { 1, 2, 3, 4, 5, 6 };
234         int i, j;
235
236         for (i=0;i<ARRAY_SIZE(levels);i++) {
237                 int level = levels[i];
238                 DATA_BLOB blob;
239
240                 r.in.server             = "";
241                 r.in.environment        = SPOOLSS_ARCHITECTURE_NT_X86;
242                 r.in.level              = level;
243                 r.in.buffer             = NULL;
244                 r.in.offered            = 0;
245
246                 torture_comment(tctx, "Testing EnumPrinterDrivers level %u\n", r.in.level);
247
248                 status = dcerpc_spoolss_EnumPrinterDrivers(p, ctx, &r);
249                 torture_assert_ntstatus_ok(tctx, status, 
250                                            "dcerpc_spoolss_EnumPrinterDrivers failed");
251                 if (W_ERROR_IS_OK(r.out.result)) {
252                         /* TODO: do some more checks here */
253                         continue;
254                 }
255                 torture_assert_werr_equal(tctx, r.out.result, WERR_INSUFFICIENT_BUFFER, 
256                         "EnumPrinterDrivers failed");
257
258                 blob = data_blob_talloc(ctx, NULL, r.out.needed);
259                 data_blob_clear(&blob);
260                 r.in.buffer = &blob;
261                 r.in.offered = r.out.needed;
262
263                 status = dcerpc_spoolss_EnumPrinterDrivers(p, ctx, &r);
264                 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EnumPrinterDrivers failed");
265
266                 torture_assert_werr_ok(tctx, r.out.result, "EnumPrinterDrivers failed");
267
268                 ctx->driver_count[level]        = r.out.count;
269                 ctx->drivers[level]             = r.out.info;
270         }
271
272         for (i=1;i<ARRAY_SIZE(levels);i++) {
273                 int level = levels[i];
274                 int old_level = levels[i-1];
275                 torture_assert_int_equal(tctx, ctx->driver_count[level], ctx->driver_count[old_level],
276                         "EnumPrinterDrivers invalid value");
277         }
278
279         for (i=0;i<ARRAY_SIZE(levels);i++) {
280                 int level = levels[i];
281                 for (j=0;j<ctx->driver_count[level];j++) {
282                         union spoolss_DriverInfo *cur = &ctx->drivers[level][j];
283                         union spoolss_DriverInfo *ref = &ctx->drivers[6][j];
284                         switch (level) {
285                         case 1:
286                                 COMPARE_STRING(tctx, cur->info1, ref->info6, driver_name);
287                                 break;
288                         case 2:
289                                 COMPARE_UINT32(tctx, cur->info2, ref->info6, version);
290                                 COMPARE_STRING(tctx, cur->info2, ref->info6, driver_name);
291                                 COMPARE_STRING(tctx, cur->info2, ref->info6, architecture);
292                                 COMPARE_STRING(tctx, cur->info2, ref->info6, driver_path);
293                                 COMPARE_STRING(tctx, cur->info2, ref->info6, data_file);
294                                 COMPARE_STRING(tctx, cur->info2, ref->info6, config_file);
295                                 break;
296                         case 3:
297                                 COMPARE_UINT32(tctx, cur->info3, ref->info6, version);
298                                 COMPARE_STRING(tctx, cur->info3, ref->info6, driver_name);
299                                 COMPARE_STRING(tctx, cur->info3, ref->info6, architecture);
300                                 COMPARE_STRING(tctx, cur->info3, ref->info6, driver_path);
301                                 COMPARE_STRING(tctx, cur->info3, ref->info6, data_file);
302                                 COMPARE_STRING(tctx, cur->info3, ref->info6, config_file);
303                                 COMPARE_STRING(tctx, cur->info3, ref->info6, help_file);
304                                 COMPARE_STRING_ARRAY(tctx, cur->info3, ref->info6, dependent_files);
305                                 COMPARE_STRING(tctx, cur->info3, ref->info6, monitor_name);
306                                 COMPARE_STRING(tctx, cur->info3, ref->info6, default_datatype);
307                                 break;
308                         case 4:
309                                 COMPARE_UINT32(tctx, cur->info4, ref->info6, version);
310                                 COMPARE_STRING(tctx, cur->info4, ref->info6, driver_name);
311                                 COMPARE_STRING(tctx, cur->info4, ref->info6, architecture);
312                                 COMPARE_STRING(tctx, cur->info4, ref->info6, driver_path);
313                                 COMPARE_STRING(tctx, cur->info4, ref->info6, data_file);
314                                 COMPARE_STRING(tctx, cur->info4, ref->info6, config_file);
315                                 COMPARE_STRING(tctx, cur->info4, ref->info6, help_file);
316                                 COMPARE_STRING_ARRAY(tctx, cur->info4, ref->info6, dependent_files);
317                                 COMPARE_STRING(tctx, cur->info4, ref->info6, monitor_name);
318                                 COMPARE_STRING(tctx, cur->info4, ref->info6, default_datatype);
319                                 COMPARE_STRING_ARRAY(tctx, cur->info4, ref->info6, previous_names);
320                                 break;
321                         case 5:
322                                 COMPARE_UINT32(tctx, cur->info5, ref->info6, version);
323                                 COMPARE_STRING(tctx, cur->info5, ref->info6, driver_name);
324                                 COMPARE_STRING(tctx, cur->info5, ref->info6, architecture);
325                                 COMPARE_STRING(tctx, cur->info5, ref->info6, driver_path);
326                                 COMPARE_STRING(tctx, cur->info5, ref->info6, data_file);
327                                 COMPARE_STRING(tctx, cur->info5, ref->info6, config_file);
328                                 /*COMPARE_UINT32(tctx, cur->info5, ref->info6, driver_attributes);*/
329                                 /*COMPARE_UINT32(tctx, cur->info5, ref->info6, config_version);*/
330                                 /*TODO: ! COMPARE_UINT32(tctx, cur->info5, ref->info6, driver_version); */
331                                 break;
332                         case 6:
333                                 /* level 6 is our reference, and it makes no sense to compare it to itself */
334                                 break;
335                         }
336                 }
337         }
338
339         return true;
340 }
341
342 static bool test_EnumMonitors(struct torture_context *tctx, 
343                               struct dcerpc_pipe *p, 
344                               struct test_spoolss_context *ctx)
345 {
346         NTSTATUS status;
347         struct spoolss_EnumMonitors r;
348         uint16_t levels[] = { 1, 2 };
349         int i, j;
350
351         for (i=0;i<ARRAY_SIZE(levels);i++) {
352                 int level = levels[i];
353                 DATA_BLOB blob;
354
355                 r.in.servername = "";
356                 r.in.level = level;
357                 r.in.buffer = NULL;
358                 r.in.offered = 0;
359
360                 torture_comment(tctx, "Testing EnumMonitors level %u\n", r.in.level);
361
362                 status = dcerpc_spoolss_EnumMonitors(p, ctx, &r);
363                 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EnumMonitors failed");
364                 if (W_ERROR_IS_OK(r.out.result)) {
365                         /* TODO: do some more checks here */
366                         continue;
367                 }
368                 torture_assert_werr_equal(tctx, r.out.result, WERR_INSUFFICIENT_BUFFER, 
369                         "EnumMonitors failed");
370
371                 blob = data_blob_talloc(ctx, NULL, r.out.needed);
372                 data_blob_clear(&blob);
373                 r.in.buffer = &blob;
374                 r.in.offered = r.out.needed;
375
376                 status = dcerpc_spoolss_EnumMonitors(p, ctx, &r);
377                 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EnumMonitors failed");
378
379                 torture_assert_werr_ok(tctx, r.out.result, "EnumMonitors failed");
380
381                 ctx->monitor_count[level]       = r.out.count;
382                 ctx->monitors[level]            = r.out.info;
383         }
384
385         for (i=1;i<ARRAY_SIZE(levels);i++) {
386                 int level = levels[i];
387                 int old_level = levels[i-1];
388                 torture_assert_int_equal(tctx, ctx->monitor_count[level], ctx->monitor_count[old_level], 
389                                          "EnumMonitors invalid value");
390         }
391
392         for (i=0;i<ARRAY_SIZE(levels);i++) {
393                 int level = levels[i];
394                 for (j=0;j<ctx->monitor_count[level];j++) {
395                         union spoolss_MonitorInfo *cur = &ctx->monitors[level][j];
396                         union spoolss_MonitorInfo *ref = &ctx->monitors[2][j];
397                         switch (level) {
398                         case 1:
399                                 COMPARE_STRING(tctx, cur->info1, ref->info2, monitor_name);
400                                 break;
401                         case 2:
402                                 /* level 2 is our reference, and it makes no sense to compare it to itself */
403                                 break;
404                         }
405                 }
406         }
407
408         return true;
409 }
410
411 static bool test_EnumPrintProcessors(struct torture_context *tctx, 
412                                      struct dcerpc_pipe *p,
413                                      struct test_spoolss_context *ctx)
414 {
415         NTSTATUS status;
416         struct spoolss_EnumPrintProcessors r;
417         uint16_t levels[] = { 1 };
418         int i, j;
419
420         for (i=0;i<ARRAY_SIZE(levels);i++) {
421                 int level = levels[i];
422                 DATA_BLOB blob;
423
424                 r.in.servername = "";
425                 r.in.environment = "Windows NT x86";
426                 r.in.level = level;
427                 r.in.buffer = NULL;
428                 r.in.offered = 0;
429
430                 torture_comment(tctx, "Testing EnumPrintProcessors level %u\n", r.in.level);
431
432                 status = dcerpc_spoolss_EnumPrintProcessors(p, ctx, &r);
433                 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EnumPrintProcessors failed");
434                 if (W_ERROR_IS_OK(r.out.result)) {
435                         /* TODO: do some more checks here */
436                         continue;
437                 }
438                 torture_assert_werr_equal(tctx, r.out.result, WERR_INSUFFICIENT_BUFFER, 
439                         "EnumPrintProcessors unexpected return code");
440
441                 blob = data_blob_talloc(ctx, NULL, r.out.needed);
442                 data_blob_clear(&blob);
443                 r.in.buffer = &blob;
444                 r.in.offered = r.out.needed;
445
446                 status = dcerpc_spoolss_EnumPrintProcessors(p, ctx, &r);
447                 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EnumPrintProcessors failed");
448
449                 torture_assert_werr_ok(tctx, r.out.result, "EnumPrintProcessors failed");
450
451                 ctx->print_processor_count[level]       = r.out.count;
452                 ctx->print_processors[level]            = r.out.info;
453         }
454
455         for (i=1;i<ARRAY_SIZE(levels);i++) {
456                 int level = levels[i];
457                 int old_level = levels[i-1];
458                 torture_assert_int_equal(tctx, ctx->print_processor_count[level], ctx->print_processor_count[old_level],
459                         "EnumPrintProcessors failed");
460         }
461
462         for (i=0;i<ARRAY_SIZE(levels);i++) {
463                 int level = levels[i];
464                 for (j=0;j<ctx->print_processor_count[level];j++) {
465 #if 0
466                         union spoolss_PrintProcessorInfo *cur = &ctx->print_processors[level][j];
467                         union spoolss_PrintProcessorInfo *ref = &ctx->print_processors[1][j];
468 #endif
469                         switch (level) {
470                         case 1:
471                                 /* level 1 is our reference, and it makes no sense to compare it to itself */
472                                 break;
473                         }
474                 }
475         }
476
477         return true;
478 }
479
480 static bool test_EnumPrinters(struct torture_context *tctx, 
481                               struct dcerpc_pipe *p,
482                               struct test_spoolss_context *ctx)
483 {
484         struct spoolss_EnumPrinters r;
485         NTSTATUS status;
486         uint16_t levels[] = { 0, 1, 2, 4, 5 };
487         int i, j;
488
489         for (i=0;i<ARRAY_SIZE(levels);i++) {
490                 int level = levels[i];
491                 DATA_BLOB blob;
492
493                 r.in.flags      = PRINTER_ENUM_LOCAL;
494                 r.in.server     = "";
495                 r.in.level      = level;
496                 r.in.buffer     = NULL;
497                 r.in.offered    = 0;
498
499                 torture_comment(tctx, "Testing EnumPrinters level %u\n", r.in.level);
500
501                 status = dcerpc_spoolss_EnumPrinters(p, ctx, &r);
502                 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EnumPrinters failed");
503                 if (W_ERROR_IS_OK(r.out.result)) {
504                         /* TODO: do some more checks here */
505                         continue;
506                 }
507                 torture_assert_werr_equal(tctx, r.out.result, WERR_INSUFFICIENT_BUFFER, 
508                         "EnumPrinters unexpected return code");
509
510                 blob = data_blob_talloc(ctx, NULL, r.out.needed);
511                 data_blob_clear(&blob);
512                 r.in.buffer = &blob;
513                 r.in.offered = r.out.needed;
514
515                 status = dcerpc_spoolss_EnumPrinters(p, ctx, &r);
516                 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EnumPrinters failed");
517
518                 torture_assert_werr_ok(tctx, r.out.result, "EnumPrinters failed");
519
520                 ctx->printer_count[level]       = r.out.count;
521                 ctx->printers[level]            = r.out.info;
522         }
523
524         for (i=1;i<ARRAY_SIZE(levels);i++) {
525                 int level = levels[i];
526                 int old_level = levels[i-1];
527                 torture_assert_int_equal(tctx, ctx->printer_count[level], ctx->printer_count[old_level],
528                                          "EnumPrinters invalid value");
529         }
530
531         for (i=0;i<ARRAY_SIZE(levels);i++) {
532                 int level = levels[i];
533                 for (j=0;j<ctx->printer_count[level];j++) {
534                         union spoolss_PrinterInfo *cur = &ctx->printers[level][j];
535                         union spoolss_PrinterInfo *ref = &ctx->printers[2][j];
536                         switch (level) {
537                         case 0:
538                                 COMPARE_STRING(tctx, cur->info0, ref->info2, printername);
539                                 COMPARE_STRING(tctx, cur->info0, ref->info2, servername);
540                                 COMPARE_UINT32(tctx, cur->info0, ref->info2, cjobs);
541                                 /*COMPARE_UINT32(tctx, cur->info0, ref->info2, total_jobs);
542                                 COMPARE_UINT32(tctx, cur->info0, ref->info2, total_bytes);
543                                 COMPARE_SPOOLSS_TIME(cur->info0, ref->info2, spoolss_Time time);                
544                                 COMPARE_UINT32(tctx, cur->info0, ref->info2, global_counter);
545                                 COMPARE_UINT32(tctx, cur->info0, ref->info2, total_pages);
546                                 COMPARE_UINT32(tctx, cur->info0, ref->info2, version);
547                                 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown10);
548                                 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown11);
549                                 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown12);
550                                 COMPARE_UINT32(tctx, cur->info0, ref->info2, session_counter);
551                                 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown14);
552                                 COMPARE_UINT32(tctx, cur->info0, ref->info2, printer_errors);
553                                 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown16);
554                                 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown17);
555                                 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown18);
556                                 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown19);
557                                 COMPARE_UINT32(tctx, cur->info0, ref->info2, change_id);
558                                 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown21);*/
559                                 COMPARE_UINT32(tctx, cur->info0, ref->info2, status);
560                                 /*COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown23);
561                                 COMPARE_UINT32(tctx, cur->info0, ref->info2, c_setprinter);
562                                 COMPARE_UINT16(cur->info0, ref->info2, unknown25);
563                                 COMPARE_UINT16(cur->info0, ref->info2, unknown26);
564                                 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown27);
565                                 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown28);
566                                 COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown29);*/
567                                 break;
568                         case 1:
569                                 /*COMPARE_UINT32(tctx, cur->info1, ref->info2, flags);*/
570                                 /*COMPARE_STRING(tctx, cur->info1, ref->info2, name);*/
571                                 /*COMPARE_STRING(tctx, cur->info1, ref->info2, description);*/
572                                 COMPARE_STRING(tctx, cur->info1, ref->info2, comment);
573                                 break;
574                         case 2:
575                                 /* level 2 is our reference, and it makes no sense to compare it to itself */
576                                 break;
577                         case 4:
578                                 COMPARE_STRING(tctx, cur->info4, ref->info2, printername);
579                                 COMPARE_STRING(tctx, cur->info4, ref->info2, servername);
580                                 COMPARE_UINT32(tctx, cur->info4, ref->info2, attributes);
581                                 break;
582                         case 5:
583                                 COMPARE_STRING(tctx, cur->info5, ref->info2, printername);
584                                 COMPARE_STRING(tctx, cur->info5, ref->info2, portname);
585                                 COMPARE_UINT32(tctx, cur->info5, ref->info2, attributes);
586                                 /*COMPARE_UINT32(tctx, cur->info5, ref->info2, device_not_selected_timeout);
587                                 COMPARE_UINT32(tctx, cur->info5, ref->info2, transmission_retry_timeout);*/
588                                 break;
589                         }
590                 }
591         }
592
593         /* TODO:
594          *      - verify that the port of a printer was in the list returned by EnumPorts
595          */
596
597         return true;
598 }
599
600 static bool test_GetPrinter(struct torture_context *tctx, 
601                             struct dcerpc_pipe *p, 
602                      struct policy_handle *handle)
603 {
604         NTSTATUS status;
605         struct spoolss_GetPrinter r;
606         uint16_t levels[] = {0, 1, 2, 3, 4, 5, 6, 7, 8};
607         int i;
608         
609         for (i=0;i<ARRAY_SIZE(levels);i++) {
610                 r.in.handle = handle;
611                 r.in.level = levels[i];
612                 r.in.buffer = NULL;
613                 r.in.offered = 0;
614
615                 torture_comment(tctx, "Testing GetPrinter level %u\n", r.in.level);
616
617                 status = dcerpc_spoolss_GetPrinter(p, tctx, &r);
618                 torture_assert_ntstatus_ok(tctx, status, "GetPrinter failed");
619                 
620                 if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
621                         DATA_BLOB blob = data_blob_talloc(tctx, NULL, r.out.needed);
622                         data_blob_clear(&blob);
623                         r.in.buffer = &blob;
624                         r.in.offered = r.out.needed;
625                         status = dcerpc_spoolss_GetPrinter(p, tctx, &r);
626                 }
627                 
628                 torture_assert_ntstatus_ok(tctx, status, "GetPrinter failed");
629
630                 torture_assert_werr_ok(tctx, r.out.result, "GetPrinter failed");
631         }
632
633         return true;
634 }
635
636
637 static bool test_ClosePrinter(struct torture_context *tctx, 
638                               struct dcerpc_pipe *p, 
639                               struct policy_handle *handle)
640 {
641         NTSTATUS status;
642         struct spoolss_ClosePrinter r;
643
644         r.in.handle = handle;
645         r.out.handle = handle;
646
647         torture_comment(tctx, "Testing ClosePrinter\n");
648
649         status = dcerpc_spoolss_ClosePrinter(p, tctx, &r);
650         torture_assert_ntstatus_ok(tctx, status, "ClosePrinter failed");
651
652         return true;
653 }
654
655 static bool test_GetForm(struct torture_context *tctx, 
656                          struct dcerpc_pipe *p, 
657                          struct policy_handle *handle, 
658                          const char *form_name)
659 {
660         NTSTATUS status;
661         struct spoolss_GetForm r;
662
663         r.in.handle = handle;
664         r.in.form_name = form_name;
665         r.in.level = 1;
666         r.in.buffer = NULL;
667         r.in.offered = 0;
668
669         torture_comment(tctx, "Testing GetForm\n");
670
671         status = dcerpc_spoolss_GetForm(p, tctx, &r);
672         torture_assert_ntstatus_ok(tctx, status, "GetForm failed");
673
674         if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
675                 DATA_BLOB blob = data_blob_talloc(tctx, NULL, r.out.needed);
676                 data_blob_clear(&blob);
677                 r.in.buffer = &blob;
678                 r.in.offered = r.out.needed;
679                 status = dcerpc_spoolss_GetForm(p, tctx, &r);
680                 torture_assert_ntstatus_ok(tctx, status, "GetForm failed");
681
682                 torture_assert_werr_ok(tctx, r.out.result, "GetForm failed");
683
684                 torture_assert(tctx, r.out.info, "No form info returned");
685         }
686
687         torture_assert_werr_ok(tctx, r.out.result, "GetForm failed");
688
689         return true;
690 }
691
692 static bool test_EnumForms(struct torture_context *tctx, 
693                            struct dcerpc_pipe *p, 
694                            struct policy_handle *handle, bool print_server)
695 {
696         NTSTATUS status;
697         struct spoolss_EnumForms r;
698         bool ret = true;
699
700         r.in.handle = handle;
701         r.in.level = 1;
702         r.in.buffer = NULL;
703         r.in.offered = 0;
704
705         torture_comment(tctx, "Testing EnumForms\n");
706
707         status = dcerpc_spoolss_EnumForms(p, tctx, &r);
708         torture_assert_ntstatus_ok(tctx, status, "EnumForms failed");
709
710         if (print_server && W_ERROR_EQUAL(r.out.result, WERR_BADFID))
711                 torture_fail(tctx, "EnumForms on the PrintServer isn't supported by test server (NT4)");
712
713         if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
714                 union spoolss_FormInfo *info;
715                 int j;
716                 DATA_BLOB blob = data_blob_talloc(tctx, NULL, r.out.needed);
717                 data_blob_clear(&blob);
718                 r.in.buffer = &blob;
719                 r.in.offered = r.out.needed;
720
721                 status = dcerpc_spoolss_EnumForms(p, tctx, &r);
722
723                 torture_assert(tctx, r.out.info, "No forms returned");
724
725                 info = r.out.info;
726
727                 for (j = 0; j < r.out.count; j++) {
728                         if (!print_server) 
729                                 ret &= test_GetForm(tctx, p, handle, info[j].info1.form_name);
730                 }
731         }
732
733         torture_assert_ntstatus_ok(tctx, status, "EnumForms failed");
734
735         torture_assert_werr_ok(tctx, r.out.result, "EnumForms failed");
736
737         return true;
738 }
739
740 static bool test_DeleteForm(struct torture_context *tctx, 
741                             struct dcerpc_pipe *p, 
742                             struct policy_handle *handle, 
743                             const char *form_name)
744 {
745         NTSTATUS status;
746         struct spoolss_DeleteForm r;
747
748         r.in.handle = handle;
749         r.in.form_name = form_name;
750
751         status = dcerpc_spoolss_DeleteForm(p, tctx, &r);
752
753         torture_assert_ntstatus_ok(tctx, status, "DeleteForm failed");
754
755         torture_assert_werr_ok(tctx, r.out.result, "DeleteForm failed");
756
757         return true;
758 }
759
760 static bool test_AddForm(struct torture_context *tctx, 
761                          struct dcerpc_pipe *p, 
762                          struct policy_handle *handle, bool print_server)
763 {
764         struct spoolss_AddForm r;
765         struct spoolss_AddFormInfo1 addform;
766         const char *form_name = "testform3";
767         NTSTATUS status;
768         bool ret = true;
769
770         r.in.handle     = handle;
771         r.in.level      = 1;
772         r.in.info.info1 = &addform;
773         addform.flags           = SPOOLSS_FORM_USER;
774         addform.form_name       = form_name;
775         addform.size.width      = 50;
776         addform.size.height     = 25;
777         addform.area.left       = 5;
778         addform.area.top        = 10;
779         addform.area.right      = 45;
780         addform.area.bottom     = 15;
781
782         status = dcerpc_spoolss_AddForm(p, tctx, &r);
783
784         torture_assert_ntstatus_ok(tctx, status, "AddForm failed");
785
786         torture_assert_werr_ok(tctx, r.out.result, "AddForm failed");
787
788         if (!print_server) ret &= test_GetForm(tctx, p, handle, form_name);
789
790         {
791                 struct spoolss_SetForm sf;
792                 struct spoolss_AddFormInfo1 setform;
793
794                 sf.in.handle    = handle;
795                 sf.in.form_name = form_name;
796                 sf.in.level     = 1;
797                 sf.in.info.info1= &setform;
798                 setform.flags           = addform.flags;
799                 setform.form_name       = addform.form_name;
800                 setform.size            = addform.size;
801                 setform.area            = addform.area;
802
803                 setform.size.width      = 1234;
804
805                 status = dcerpc_spoolss_SetForm(p, tctx, &sf);
806
807                 torture_assert_ntstatus_ok(tctx, status, "SetForm failed");
808
809                 torture_assert_werr_ok(tctx, r.out.result, "SetForm failed");
810         }
811
812         if (!print_server) ret &= test_GetForm(tctx, p, handle, form_name);
813
814         if (!test_DeleteForm(tctx, p, handle, form_name)) {
815                 ret = false;
816         }
817
818         return ret;
819 }
820
821 static bool test_EnumPorts_old(struct torture_context *tctx, 
822                                struct dcerpc_pipe *p)
823 {
824         NTSTATUS status;
825         struct spoolss_EnumPorts r;
826
827         r.in.servername = talloc_asprintf(tctx, "\\\\%s", 
828                                           dcerpc_server_name(p));
829         r.in.level = 2;
830         r.in.buffer = NULL;
831         r.in.offered = 0;
832
833         torture_comment(tctx, "Testing EnumPorts\n");
834
835         status = dcerpc_spoolss_EnumPorts(p, tctx, &r);
836
837         torture_assert_ntstatus_ok(tctx, status, "EnumPorts failed");
838
839         if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
840                 DATA_BLOB blob = data_blob_talloc(tctx, NULL, r.out.needed);
841                 data_blob_clear(&blob);
842                 r.in.buffer = &blob;
843                 r.in.offered = r.out.needed;
844
845                 status = dcerpc_spoolss_EnumPorts(p, tctx, &r);
846                 torture_assert_ntstatus_ok(tctx, status, "EnumPorts failed");
847
848                 torture_assert(tctx, r.out.info, "No ports returned");
849         }
850
851         return true;
852 }
853
854 static bool test_AddPort(struct torture_context *tctx, 
855                          struct dcerpc_pipe *p)
856 {
857         NTSTATUS status;
858         struct spoolss_AddPort r;
859
860         r.in.server_name = talloc_asprintf(tctx, "\\\\%s", 
861                                            dcerpc_server_name(p));
862         r.in.unknown = 0;
863         r.in.monitor_name = "foo";
864
865         torture_comment(tctx, "Testing AddPort\n");
866
867         status = dcerpc_spoolss_AddPort(p, tctx, &r);
868
869         torture_assert_ntstatus_ok(tctx, status, "AddPort failed");
870
871         /* win2k3 returns WERR_NOT_SUPPORTED */
872
873 #if 0
874
875         if (!W_ERROR_IS_OK(r.out.result)) {
876                 printf("AddPort failed - %s\n", win_errstr(r.out.result));
877                 return false;
878         }
879
880 #endif
881
882         return true;
883 }
884
885 static bool test_GetJob(struct torture_context *tctx, 
886                         struct dcerpc_pipe *p, 
887                         struct policy_handle *handle, uint32_t job_id)
888 {
889         NTSTATUS status;
890         struct spoolss_GetJob r;
891
892         r.in.handle = handle;
893         r.in.job_id = job_id;
894         r.in.level = 1;
895         r.in.buffer = NULL;
896         r.in.offered = 0;
897
898         torture_comment(tctx, "Testing GetJob\n");
899
900         status = dcerpc_spoolss_GetJob(p, tctx, &r);
901         torture_assert_ntstatus_ok(tctx, status, "GetJob failed");
902
903         if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
904                 DATA_BLOB blob = data_blob_talloc(tctx, NULL, r.out.needed);
905                 data_blob_clear(&blob);
906                 r.in.buffer = &blob;
907                 r.in.offered = r.out.needed;
908
909                 status = dcerpc_spoolss_GetJob(p, tctx, &r);
910
911                 torture_assert(tctx, r.out.info, "No job info returned");
912         }
913
914         return true;
915 }
916
917 static bool test_SetJob(struct torture_context *tctx, 
918                         struct dcerpc_pipe *p, 
919                         struct policy_handle *handle, uint32_t job_id, 
920                         enum spoolss_JobControl command)
921 {
922         NTSTATUS status;
923         struct spoolss_SetJob r;
924
925         r.in.handle     = handle;
926         r.in.job_id     = job_id;
927         r.in.ctr        = NULL;
928         r.in.command    = command;
929
930         torture_comment(tctx, "Testing SetJob\n");
931
932         status = dcerpc_spoolss_SetJob(p, tctx, &r);
933         torture_assert_ntstatus_ok(tctx, status, "SetJob failed");
934         torture_assert_werr_ok(tctx, r.out.result, "SetJob failed");
935
936         return true;
937 }
938
939 static bool test_EnumJobs(struct torture_context *tctx, 
940                           struct dcerpc_pipe *p, 
941                           struct policy_handle *handle)
942 {
943         NTSTATUS status;
944         struct spoolss_EnumJobs r;
945
946         r.in.handle = handle;
947         r.in.firstjob = 0;
948         r.in.numjobs = 0xffffffff;
949         r.in.level = 1;
950         r.in.buffer = NULL;
951         r.in.offered = 0;
952
953         torture_comment(tctx, "Testing EnumJobs\n");
954
955         status = dcerpc_spoolss_EnumJobs(p, tctx, &r);
956
957         torture_assert_ntstatus_ok(tctx, status, "EnumJobs failed");
958
959         if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
960                 union spoolss_JobInfo *info;
961                 int j;
962                 DATA_BLOB blob = data_blob_talloc(tctx, NULL, r.out.needed);
963                 data_blob_clear(&blob);
964                 r.in.buffer = &blob;
965                 r.in.offered = r.out.needed;
966
967                 status = dcerpc_spoolss_EnumJobs(p, tctx, &r);
968
969                 torture_assert(tctx, r.out.info, "No jobs returned");
970
971                 info = r.out.info;
972
973                 for (j = 0; j < r.out.count; j++) {
974                         test_GetJob(tctx, p, handle, info[j].info1.job_id);
975                         test_SetJob(tctx, p, handle, info[j].info1.job_id, SPOOLSS_JOB_CONTROL_PAUSE);
976                         test_SetJob(tctx, p, handle, info[j].info1.job_id, SPOOLSS_JOB_CONTROL_RESUME);
977                 }
978
979         } else {
980                 torture_assert_werr_ok(tctx, r.out.result, "EnumJobs failed");
981         }
982
983         return true;
984 }
985
986 static bool test_DoPrintTest(struct torture_context *tctx, 
987                              struct dcerpc_pipe *p, 
988                              struct policy_handle *handle)
989 {
990         bool ret = true;
991         NTSTATUS status;
992         struct spoolss_StartDocPrinter s;
993         struct spoolss_DocumentInfo1 info1;
994         struct spoolss_StartPagePrinter sp;
995         struct spoolss_WritePrinter w;
996         struct spoolss_EndPagePrinter ep;
997         struct spoolss_EndDocPrinter e;
998         int i;
999         uint32_t job_id;
1000
1001         torture_comment(tctx, "Testing StartDocPrinter\n");
1002
1003         s.in.handle             = handle;
1004         s.in.level              = 1;
1005         s.in.info.info1         = &info1;
1006         info1.document_name     = "TorturePrintJob";
1007         info1.output_file       = NULL;
1008         info1.datatype          = "RAW";
1009
1010         status = dcerpc_spoolss_StartDocPrinter(p, tctx, &s);
1011         torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_StartDocPrinter failed");
1012         torture_assert_werr_ok(tctx, s.out.result, "StartDocPrinter failed");
1013
1014         job_id = s.out.job_id;
1015
1016         for (i=1; i < 4; i++) {
1017                 torture_comment(tctx, "Testing StartPagePrinter: Page[%d]\n", i);
1018
1019                 sp.in.handle            = handle;
1020
1021                 status = dcerpc_spoolss_StartPagePrinter(p, tctx, &sp);
1022                 torture_assert_ntstatus_ok(tctx, status, 
1023                                            "dcerpc_spoolss_StartPagePrinter failed");
1024                 torture_assert_werr_ok(tctx, sp.out.result, "StartPagePrinter failed");
1025
1026                 torture_comment(tctx, "Testing WritePrinter: Page[%d]\n", i);
1027
1028                 w.in.handle             = handle;
1029                 w.in.data               = data_blob_string_const(talloc_asprintf(tctx,"TortureTestPage: %d\nData\n",i));
1030
1031                 status = dcerpc_spoolss_WritePrinter(p, tctx, &w);
1032                 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_WritePrinter failed");
1033                 torture_assert_werr_ok(tctx, w.out.result, "WritePrinter failed");
1034
1035                 torture_comment(tctx, "Testing EndPagePrinter: Page[%d]\n", i);
1036
1037                 ep.in.handle            = handle;
1038
1039                 status = dcerpc_spoolss_EndPagePrinter(p, tctx, &ep);
1040                 torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EndPagePrinter failed");
1041                 torture_assert_werr_ok(tctx, ep.out.result, "EndPagePrinter failed");
1042         }
1043
1044         torture_comment(tctx, "Testing EndDocPrinter\n");
1045
1046         e.in.handle = handle;
1047
1048         status = dcerpc_spoolss_EndDocPrinter(p, tctx, &e);
1049         torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EndDocPrinter failed");
1050         torture_assert_werr_ok(tctx, e.out.result, "EndDocPrinter failed");
1051
1052         ret &= test_EnumJobs(tctx, p, handle);
1053
1054         ret &= test_SetJob(tctx, p, handle, job_id, SPOOLSS_JOB_CONTROL_DELETE);
1055
1056         return ret;
1057 }
1058
1059 static bool test_PausePrinter(struct torture_context *tctx, 
1060                               struct dcerpc_pipe *p, 
1061                               struct policy_handle *handle)
1062 {
1063         NTSTATUS status;
1064         struct spoolss_SetPrinter r;
1065
1066         r.in.handle             = handle;
1067         r.in.level              = 0;
1068         r.in.info.info1         = NULL;
1069         r.in.devmode_ctr.devmode= NULL;
1070         r.in.secdesc_ctr.sd     = NULL;
1071         r.in.command            = SPOOLSS_PRINTER_CONTROL_PAUSE;
1072
1073         torture_comment(tctx, "Testing SetPrinter: SPOOLSS_PRINTER_CONTROL_PAUSE\n");
1074
1075         status = dcerpc_spoolss_SetPrinter(p, tctx, &r);
1076
1077         torture_assert_ntstatus_ok(tctx, status, "SetPrinter failed");
1078
1079         torture_assert_werr_ok(tctx, r.out.result, "SetPrinter failed");
1080
1081         return true;
1082 }
1083
1084 static bool test_ResumePrinter(struct torture_context *tctx, 
1085                                struct dcerpc_pipe *p, 
1086                                struct policy_handle *handle)
1087 {
1088         NTSTATUS status;
1089         struct spoolss_SetPrinter r;
1090
1091         r.in.handle             = handle;
1092         r.in.level              = 0;
1093         r.in.info.info1         = NULL;
1094         r.in.devmode_ctr.devmode= NULL;
1095         r.in.secdesc_ctr.sd     = NULL;
1096         r.in.command            = SPOOLSS_PRINTER_CONTROL_RESUME;
1097
1098         torture_comment(tctx, "Testing SetPrinter: SPOOLSS_PRINTER_CONTROL_RESUME\n");
1099
1100         status = dcerpc_spoolss_SetPrinter(p, tctx, &r);
1101
1102         torture_assert_ntstatus_ok(tctx, status, "SetPrinter failed");
1103
1104         torture_assert_werr_ok(tctx, r.out.result, "SetPrinter failed");
1105
1106         return true;
1107 }
1108
1109 static bool test_GetPrinterData(struct torture_context *tctx, 
1110                                 struct dcerpc_pipe *p, 
1111                                 struct policy_handle *handle, 
1112                                 const char *value_name)
1113 {
1114         NTSTATUS status;
1115         struct spoolss_GetPrinterData r;
1116
1117         r.in.handle = handle;
1118         r.in.value_name = value_name;
1119         r.in.offered = 0;
1120
1121         torture_comment(tctx, "Testing GetPrinterData\n");
1122
1123         status = dcerpc_spoolss_GetPrinterData(p, tctx, &r);
1124         torture_assert_ntstatus_ok(tctx, status, "GetPrinterData failed");
1125
1126         if (W_ERROR_EQUAL(r.out.result, WERR_MORE_DATA)) {
1127                 r.in.offered = r.out.needed;
1128
1129                 status = dcerpc_spoolss_GetPrinterData(p, tctx, &r);
1130                 torture_assert_ntstatus_ok(tctx, status, "GetPrinterData failed");
1131
1132                 torture_assert_werr_ok(tctx, r.out.result, "GetPrinterData failed");
1133         }
1134
1135         return true;
1136 }
1137
1138 static bool test_GetPrinterDataEx(struct torture_context *tctx, 
1139                                   struct dcerpc_pipe *p, 
1140                                   struct policy_handle *handle, 
1141                                   const char *key_name,
1142                                   const char *value_name)
1143 {
1144         NTSTATUS status;
1145         struct spoolss_GetPrinterDataEx r;
1146
1147         r.in.handle = handle;
1148         r.in.key_name = key_name;
1149         r.in.value_name = value_name;
1150         r.in.offered = 0;
1151
1152         torture_comment(tctx, "Testing GetPrinterDataEx\n");
1153
1154         status = dcerpc_spoolss_GetPrinterDataEx(p, tctx, &r);
1155         if (!NT_STATUS_IS_OK(status)) {
1156                 if (NT_STATUS_EQUAL(status,NT_STATUS_NET_WRITE_FAULT) &&
1157                     p->last_fault_code == DCERPC_FAULT_OP_RNG_ERROR) {
1158                         torture_skip(tctx, "GetPrinterDataEx not supported by server\n");
1159                 }
1160                 torture_assert_ntstatus_ok(tctx, status, "GetPrinterDataEx failed");
1161         }
1162
1163         if (W_ERROR_EQUAL(r.out.result, WERR_MORE_DATA)) {
1164                 r.in.offered = r.out.needed;
1165
1166                 status = dcerpc_spoolss_GetPrinterDataEx(p, tctx, &r);
1167                 torture_assert_ntstatus_ok(tctx, status, "GetPrinterDataEx failed");
1168
1169                 torture_assert_werr_ok(tctx, r.out.result,  "GetPrinterDataEx failed");
1170         }
1171
1172         return true;
1173 }
1174
1175 static bool test_EnumPrinterData(struct torture_context *tctx, struct dcerpc_pipe *p, 
1176                                  struct policy_handle *handle)
1177 {
1178         NTSTATUS status;
1179         struct spoolss_EnumPrinterData r;
1180
1181         r.in.handle = handle;
1182         r.in.enum_index = 0;
1183
1184         do {
1185                 uint32_t data_size;
1186                 
1187                 r.in.value_offered = 0;
1188                 data_size = 0;
1189                 r.in.data_size = &data_size;
1190                 r.out.data_size = &data_size;
1191
1192                 torture_comment(tctx, "Testing EnumPrinterData\n");
1193
1194                 status = dcerpc_spoolss_EnumPrinterData(p, tctx, &r);
1195
1196                 torture_assert_ntstatus_ok(tctx, status, "EnumPrinterData failed");
1197
1198                 r.in.value_offered = r.out.value_needed;
1199
1200                 status = dcerpc_spoolss_EnumPrinterData(p, tctx, &r);
1201
1202                 torture_assert_ntstatus_ok(tctx, status, "EnumPrinterData failed");
1203                 
1204                 test_GetPrinterData(tctx, p, handle, r.out.value_name);
1205
1206                 test_GetPrinterDataEx(tctx, 
1207                         p, handle, "PrinterDriverData", 
1208                         r.out.value_name);
1209
1210                 r.in.enum_index++;
1211
1212         } while (W_ERROR_IS_OK(r.out.result));
1213
1214         return true;
1215 }
1216
1217 static bool test_EnumPrinterDataEx(struct torture_context *tctx, 
1218                                    struct dcerpc_pipe *p, 
1219                                    struct policy_handle *handle)
1220 {
1221         NTSTATUS status;
1222         struct spoolss_EnumPrinterDataEx r;
1223
1224         r.in.handle = handle;
1225         r.in.key_name = "PrinterDriverData";
1226         r.in.offered = 0;
1227
1228         torture_comment(tctx, "Testing EnumPrinterDataEx\n");
1229
1230         status = dcerpc_spoolss_EnumPrinterDataEx(p, tctx, &r);
1231         torture_assert_ntstatus_ok(tctx, status, "EnumPrinterDataEx failed");
1232
1233         r.in.offered = r.out.needed;
1234
1235         status = dcerpc_spoolss_EnumPrinterDataEx(p, tctx, &r);
1236
1237         torture_assert_ntstatus_ok(tctx, status, "EnumPrinterDataEx failed");
1238
1239         return true;
1240 }
1241
1242
1243 static bool test_DeletePrinterData(struct torture_context *tctx, 
1244                                    struct dcerpc_pipe *p, 
1245                                    struct policy_handle *handle, 
1246                                    const char *value_name)
1247 {
1248         NTSTATUS status;
1249         struct spoolss_DeletePrinterData r;
1250
1251         r.in.handle = handle;
1252         r.in.value_name = value_name;
1253
1254         torture_comment(tctx, "Testing DeletePrinterData\n");
1255
1256         status = dcerpc_spoolss_DeletePrinterData(p, tctx, &r);
1257
1258         torture_assert_ntstatus_ok(tctx, status, "DeletePrinterData failed");
1259
1260         return true;
1261 }
1262
1263 static bool test_SetPrinterData(struct torture_context *tctx, 
1264                                 struct dcerpc_pipe *p, 
1265                                 struct policy_handle *handle)
1266 {
1267         NTSTATUS status;
1268         struct spoolss_SetPrinterData r;
1269         const char *value_name = "spottyfoot";
1270         
1271         r.in.handle = handle;
1272         r.in.value_name = value_name;
1273         r.in.type = SPOOLSS_PRINTER_DATA_TYPE_STRING;
1274         r.in.data.string = "dog";
1275
1276         torture_comment(tctx, "Testing SetPrinterData\n");
1277
1278         status = dcerpc_spoolss_SetPrinterData(p, tctx, &r);
1279
1280         torture_assert_ntstatus_ok(tctx, status, "SetPrinterData failed");
1281
1282         if (!test_GetPrinterData(tctx, p, handle, value_name)) {
1283                 return false;
1284         }
1285
1286         if (!test_DeletePrinterData(tctx, p, handle, value_name)) {
1287                 return false;
1288         }
1289
1290         return true;
1291 }
1292
1293 static bool test_SecondaryClosePrinter(struct torture_context *tctx, 
1294                                        struct dcerpc_pipe *p, 
1295                                        struct policy_handle *handle)
1296 {
1297         NTSTATUS status;
1298         struct dcerpc_binding *b;
1299         struct dcerpc_pipe *p2;
1300         bool ret = true;
1301
1302         /* only makes sense on SMB */
1303         if (p->conn->transport.transport != NCACN_NP) {
1304                 return true;
1305         }
1306
1307         torture_comment(tctx, "testing close on secondary pipe\n");
1308
1309         status = dcerpc_parse_binding(tctx, p->conn->binding_string, &b);
1310         torture_assert_ntstatus_ok(tctx, status, "Failed to parse dcerpc binding");
1311
1312         status = dcerpc_secondary_connection(p, &p2, b);
1313         torture_assert_ntstatus_ok(tctx, status, "Failed to create secondary connection");
1314
1315         status = dcerpc_bind_auth_none(p2, &ndr_table_spoolss);
1316         torture_assert_ntstatus_ok(tctx, status, "Failed to create bind on secondary connection");
1317
1318         if (test_ClosePrinter(tctx, p2, handle)) {
1319                 torture_comment(tctx, "ERROR: Allowed close on secondary connection!\n");
1320                 ret = false;
1321         }
1322
1323         torture_assert_int_equal(tctx, p2->last_fault_code, DCERPC_FAULT_CONTEXT_MISMATCH, 
1324                                  "Unexpected fault code");
1325
1326         talloc_free(p2);
1327
1328         return true;
1329 }
1330
1331 static bool test_OpenPrinter_badname(struct torture_context *tctx, 
1332                                      struct dcerpc_pipe *p, const char *name)
1333 {
1334         NTSTATUS status;
1335         struct spoolss_OpenPrinter op;
1336         struct spoolss_OpenPrinterEx opEx;
1337         struct policy_handle handle;
1338         bool ret = true;
1339
1340         op.in.printername       = name;
1341         op.in.datatype          = NULL;
1342         op.in.devmode_ctr.devmode= NULL;
1343         op.in.access_mask       = 0;
1344         op.out.handle           = &handle;
1345
1346         torture_comment(tctx, "\nTesting OpenPrinter(%s) with bad name\n", op.in.printername);
1347
1348         status = dcerpc_spoolss_OpenPrinter(p, tctx, &op);
1349         torture_assert_ntstatus_ok(tctx, status, "OpenPrinter failed");
1350         if (!W_ERROR_EQUAL(WERR_INVALID_PRINTER_NAME,op.out.result)) {
1351                 torture_comment(tctx, "OpenPrinter(%s) unexpected result[%s] should be WERR_INVALID_PRINTER_NAME\n",
1352                         name, win_errstr(op.out.result));
1353         }
1354
1355         if (W_ERROR_IS_OK(op.out.result)) {
1356                 ret &=test_ClosePrinter(tctx, p, &handle);
1357         }
1358
1359         opEx.in.printername             = name;
1360         opEx.in.datatype                = NULL;
1361         opEx.in.devmode_ctr.devmode     = NULL;
1362         opEx.in.access_mask             = 0;
1363         opEx.in.level                   = 1;
1364         opEx.in.userlevel.level1        = NULL;
1365         opEx.out.handle                 = &handle;
1366
1367         torture_comment(tctx, "Testing OpenPrinterEx(%s) with bad name\n", opEx.in.printername);
1368
1369         status = dcerpc_spoolss_OpenPrinterEx(p, tctx, &opEx);
1370         torture_assert_ntstatus_ok(tctx, status, "OpenPrinter failed");
1371         if (!W_ERROR_EQUAL(WERR_INVALID_PRINTER_NAME,opEx.out.result)) {
1372                 torture_comment(tctx, "OpenPrinterEx(%s) unexpected result[%s] should be WERR_INVALID_PRINTER_NAME\n",
1373                         name, win_errstr(opEx.out.result));
1374         }
1375
1376         if (W_ERROR_IS_OK(opEx.out.result)) {
1377                 ret &=test_ClosePrinter(tctx, p, &handle);
1378         }
1379
1380         return ret;
1381 }
1382
1383 static bool test_OpenPrinter(struct torture_context *tctx, 
1384                              struct dcerpc_pipe *p, 
1385                              const char *name)
1386 {
1387         NTSTATUS status;
1388         struct spoolss_OpenPrinter r;
1389         struct policy_handle handle;
1390         bool ret = true;
1391
1392         r.in.printername        = talloc_asprintf(tctx, "\\\\%s\\%s", dcerpc_server_name(p), name);
1393         r.in.datatype           = NULL;
1394         r.in.devmode_ctr.devmode= NULL;
1395         r.in.access_mask        = SEC_FLAG_MAXIMUM_ALLOWED;
1396         r.out.handle            = &handle;
1397
1398         torture_comment(tctx, "Testing OpenPrinter(%s)\n", r.in.printername);
1399
1400         status = dcerpc_spoolss_OpenPrinter(p, tctx, &r);
1401
1402         torture_assert_ntstatus_ok(tctx, status, "OpenPrinter failed");
1403
1404         torture_assert_werr_ok(tctx, r.out.result, "OpenPrinter failed");
1405
1406         if (!test_GetPrinter(tctx, p, &handle)) {
1407                 ret = false;
1408         }
1409
1410         if (!test_SecondaryClosePrinter(tctx, p, &handle)) {
1411                 ret = false;
1412         }
1413
1414         if (!test_ClosePrinter(tctx, p, &handle)) {
1415                 ret = false;
1416         }
1417
1418         return ret;
1419 }
1420
1421 static bool call_OpenPrinterEx(struct torture_context *tctx, 
1422                                struct dcerpc_pipe *p, 
1423                                const char *name, struct policy_handle *handle)
1424 {
1425         struct spoolss_OpenPrinterEx r;
1426         struct spoolss_UserLevel1 userlevel1;
1427         NTSTATUS status;
1428
1429         if (name && name[0]) {
1430                 r.in.printername = talloc_asprintf(tctx, "\\\\%s\\%s", 
1431                                                    dcerpc_server_name(p), name);
1432         } else {
1433                 r.in.printername = talloc_asprintf(tctx, "\\\\%s", 
1434                                                    dcerpc_server_name(p));
1435         }
1436
1437         r.in.datatype           = NULL;
1438         r.in.devmode_ctr.devmode= NULL;
1439         r.in.access_mask        = SEC_FLAG_MAXIMUM_ALLOWED;
1440         r.in.level              = 1;
1441         r.in.userlevel.level1   = &userlevel1;
1442         r.out.handle = handle;
1443
1444         userlevel1.size = 1234;
1445         userlevel1.client = "hello";
1446         userlevel1.user = "spottyfoot!";
1447         userlevel1.build = 1;
1448         userlevel1.major = 2;
1449         userlevel1.minor = 3;
1450         userlevel1.processor = 4;
1451
1452         torture_comment(tctx, "Testing OpenPrinterEx(%s)\n", r.in.printername);
1453
1454         status = dcerpc_spoolss_OpenPrinterEx(p, tctx, &r);
1455
1456         torture_assert_ntstatus_ok(tctx, status, "OpenPrinterEx failed");
1457         
1458         torture_assert_werr_ok(tctx, r.out.result, "OpenPrinterEx failed");
1459
1460         return true;
1461 }
1462
1463 static bool test_OpenPrinterEx(struct torture_context *tctx, 
1464                                struct dcerpc_pipe *p, 
1465                                const char *name)
1466 {
1467         struct policy_handle handle;
1468         bool ret = true;
1469
1470         if (!call_OpenPrinterEx(tctx, p, name, &handle)) {
1471                 return false;
1472         }
1473
1474         if (!test_GetPrinter(tctx, p, &handle)) {
1475                 ret = false;
1476         }
1477
1478         if (!test_EnumForms(tctx, p, &handle, false)) {
1479                 ret = false;
1480         }
1481
1482         if (!test_AddForm(tctx, p, &handle, false)) {
1483                 ret = false;
1484         }
1485
1486         if (!test_EnumPrinterData(tctx, p, &handle)) {
1487                 ret = false;
1488         }
1489
1490         if (!test_EnumPrinterDataEx(tctx, p, &handle)) {
1491                 ret = false;
1492         }
1493
1494         if (!test_PausePrinter(tctx, p, &handle)) {
1495                 ret = false;
1496         }
1497
1498         if (!test_DoPrintTest(tctx, p, &handle)) {
1499                 ret = false;
1500         }
1501
1502         if (!test_ResumePrinter(tctx, p, &handle)) {
1503                 ret = false;
1504         }
1505
1506         if (!test_SetPrinterData(tctx, p, &handle)) {
1507                 ret = false;
1508         }
1509
1510         if (!test_SecondaryClosePrinter(tctx, p, &handle)) {
1511                 ret = false;
1512         }
1513
1514         if (!test_ClosePrinter(tctx, p, &handle)) {
1515                 ret = false;
1516         }
1517         
1518         return ret;
1519 }
1520
1521 static bool test_EnumPrinters_old(struct torture_context *tctx, struct dcerpc_pipe *p)
1522 {
1523         struct spoolss_EnumPrinters r;
1524         NTSTATUS status;
1525         uint16_t levels[] = {1, 2, 4, 5};
1526         int i;
1527         bool ret = true;
1528
1529         for (i=0;i<ARRAY_SIZE(levels);i++) {
1530                 union spoolss_PrinterInfo *info;
1531                 int j;
1532
1533                 r.in.flags      = PRINTER_ENUM_LOCAL;
1534                 r.in.server     = "";
1535                 r.in.level      = levels[i];
1536                 r.in.buffer     = NULL;
1537                 r.in.offered    = 0;
1538
1539                 torture_comment(tctx, "Testing EnumPrinters level %u\n", r.in.level);
1540
1541                 status = dcerpc_spoolss_EnumPrinters(p, tctx, &r);
1542                 torture_assert_ntstatus_ok(tctx, status, "EnumPrinters failed");
1543
1544                 if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
1545                         DATA_BLOB blob = data_blob_talloc(tctx, NULL, r.out.needed);
1546                         data_blob_clear(&blob);
1547                         r.in.buffer = &blob;
1548                         r.in.offered = r.out.needed;
1549                         status = dcerpc_spoolss_EnumPrinters(p, tctx, &r);
1550                 }
1551
1552                 torture_assert_ntstatus_ok(tctx, status, "EnumPrinters failed");
1553
1554                 torture_assert_werr_ok(tctx, r.out.result, "EnumPrinters failed");
1555
1556                 if (!r.out.info) {
1557                         torture_comment(tctx, "No printers returned\n");
1558                         return true;
1559                 }
1560
1561                 info = r.out.info;
1562
1563                 for (j=0;j<r.out.count;j++) {
1564                         if (r.in.level == 1) {
1565                                 /* the names appear to be comma-separated name lists? */
1566                                 char *name = talloc_strdup(tctx, info[j].info1.name);
1567                                 char *comma = strchr(name, ',');
1568                                 if (comma) *comma = 0;
1569                                 if (!test_OpenPrinter(tctx, p, name)) {
1570                                         ret = false;
1571                                 }
1572                                 if (!test_OpenPrinterEx(tctx, p, name)) {
1573                                         ret = false;
1574                                 }
1575                         }
1576                 }
1577         }
1578
1579         return ret;
1580 }
1581
1582 #if 0
1583 static bool test_GetPrinterDriver2(struct dcerpc_pipe *p, 
1584                                    struct policy_handle *handle, 
1585                                    const char *driver_name)
1586 {
1587         NTSTATUS status;
1588         struct spoolss_GetPrinterDriver2 r;
1589
1590         r.in.handle = handle;
1591         r.in.architecture = "W32X86";
1592         r.in.level = 1;
1593         r.in.buffer = NULL;
1594         r.in.offered = 0;
1595         r.in.client_major_version = 0;
1596         r.in.client_minor_version = 0;
1597
1598         printf("Testing GetPrinterDriver2\n");
1599
1600         status = dcerpc_spoolss_GetPrinterDriver2(p, tctx, &r);
1601         if (!NT_STATUS_IS_OK(status)) {
1602                 printf("GetPrinterDriver2 failed - %s\n", nt_errstr(status));
1603                 return false;
1604         }
1605
1606         if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
1607                 r.in.offered = r.out.needed;
1608                 status = dcerpc_spoolss_GetPrinterDriver2(p, tctx, &r);
1609         }
1610                 
1611         if (!NT_STATUS_IS_OK(status)) {
1612                 printf("GetPrinterDriver2 failed - %s\n", 
1613                        nt_errstr(status));
1614                 return false;
1615         }
1616
1617         if (!W_ERROR_IS_OK(r.out.result)) {
1618                 printf("GetPrinterDriver2 failed - %s\n", 
1619                        win_errstr(r.out.result));
1620                 return false;
1621         }
1622
1623         return true;
1624 }
1625 #endif
1626
1627 static bool test_EnumPrinterDrivers_old(struct torture_context *tctx, 
1628                                         struct dcerpc_pipe *p)
1629 {
1630         struct spoolss_EnumPrinterDrivers r;
1631         NTSTATUS status;
1632         uint16_t levels[] = {1, 2, 3, 4, 5, 6};
1633         int i;
1634
1635         for (i=0;i<ARRAY_SIZE(levels);i++) {
1636
1637                 r.in.server = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
1638                 r.in.environment = "Windows NT x86";
1639                 r.in.level = levels[i];
1640                 r.in.buffer = NULL;
1641                 r.in.offered = 0;
1642
1643                 torture_comment(tctx, "Testing EnumPrinterDrivers level %u\n", r.in.level);
1644
1645                 status = dcerpc_spoolss_EnumPrinterDrivers(p, tctx, &r);
1646
1647                 torture_assert_ntstatus_ok(tctx, status, "EnumPrinterDrivers failed");
1648
1649                 if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
1650                         DATA_BLOB blob = data_blob_talloc(tctx, NULL, r.out.needed);
1651                         data_blob_clear(&blob);
1652                         r.in.buffer = &blob;
1653                         r.in.offered = r.out.needed;
1654                         status = dcerpc_spoolss_EnumPrinterDrivers(p, tctx, &r);
1655                 }
1656
1657                 torture_assert_ntstatus_ok(tctx, status, "EnumPrinterDrivers failed");
1658
1659                 torture_assert_werr_ok(tctx, r.out.result, "EnumPrinterDrivers failed");
1660
1661                 if (!r.out.info) {
1662                         torture_comment(tctx, "No printer drivers returned\n");
1663                         break;
1664                 }
1665         }
1666
1667         return true;
1668 }
1669
1670 /** Test that makes sure that calling ReplyOpenPrinter()
1671  * on Samba 4 will cause an irpc broadcast call.
1672  */
1673 static bool test_ReplyOpenPrinter(struct torture_context *tctx, 
1674                                   struct dcerpc_pipe *pipe)
1675 {
1676         struct spoolss_ReplyOpenPrinter r;
1677         struct spoolss_ReplyClosePrinter s;
1678         struct policy_handle h;
1679
1680         r.in.server_name = "earth";
1681         r.in.printer_local = 2;
1682         r.in.type = REG_DWORD;
1683         r.in.unknown1 = 0;
1684         r.in.unknown2 = 0;
1685         r.out.handle = &h;
1686
1687         torture_assert_ntstatus_ok(tctx, 
1688                         dcerpc_spoolss_ReplyOpenPrinter(pipe, tctx, &r),
1689                         "spoolss_ReplyOpenPrinter call failed");
1690
1691         torture_assert_werr_ok(tctx, r.out.result, "error return code");
1692
1693         s.in.handle = &h;
1694         s.out.handle = &h;
1695
1696         torture_assert_ntstatus_ok(tctx,
1697                         dcerpc_spoolss_ReplyClosePrinter(pipe, tctx, &s),
1698                         "spoolss_ReplyClosePrinter call failed");
1699
1700         torture_assert_werr_ok(tctx, r.out.result, "error return code");
1701
1702         return true;
1703 }
1704
1705 bool torture_rpc_spoolss(struct torture_context *torture)
1706 {
1707         NTSTATUS status;
1708         struct dcerpc_pipe *p;
1709         bool ret = true;
1710         struct test_spoolss_context *ctx;
1711
1712         status = torture_rpc_connection(torture, &p, &ndr_table_spoolss);
1713         if (!NT_STATUS_IS_OK(status)) {
1714                 return false;
1715         }
1716
1717         ctx = talloc_zero(torture, struct test_spoolss_context);
1718
1719         ret &= test_OpenPrinter_server(torture, p, ctx);
1720
1721         ret &= test_GetPrinterData(torture, p, &ctx->server_handle, "W3SvcInstalled");
1722         ret &= test_GetPrinterData(torture, p, &ctx->server_handle, "BeepEnabled");
1723         ret &= test_GetPrinterData(torture, p, &ctx->server_handle, "EventLog");
1724         ret &= test_GetPrinterData(torture, p, &ctx->server_handle, "NetPopup");
1725         ret &= test_GetPrinterData(torture, p, &ctx->server_handle, "NetPopupToComputer");
1726         ret &= test_GetPrinterData(torture, p, &ctx->server_handle, "MajorVersion");
1727         ret &= test_GetPrinterData(torture, p, &ctx->server_handle, "MinorVersion");
1728         ret &= test_GetPrinterData(torture, p, &ctx->server_handle, "DefaultSpoolDirectory");
1729         ret &= test_GetPrinterData(torture, p, &ctx->server_handle, "Architecture");
1730         ret &= test_GetPrinterData(torture, p, &ctx->server_handle, "DsPresent");
1731         ret &= test_GetPrinterData(torture, p, &ctx->server_handle, "OSVersion");
1732         ret &= test_GetPrinterData(torture, p, &ctx->server_handle, "OSVersionEx");
1733         ret &= test_GetPrinterData(torture, p, &ctx->server_handle, "DNSMachineName");
1734         ret &= test_EnumForms(torture, p, &ctx->server_handle, true);
1735         ret &= test_AddForm(torture, p, &ctx->server_handle, true);
1736         ret &= test_EnumPorts(torture, p, ctx);
1737         ret &= test_GetPrinterDriverDirectory(torture, p, ctx);
1738         ret &= test_EnumPrinterDrivers(torture, p, ctx);
1739         ret &= test_EnumMonitors(torture, p, ctx);
1740         ret &= test_EnumPrintProcessors(torture, p, ctx);
1741         ret &= test_EnumPrinters(torture, p, ctx);
1742         ret &= test_OpenPrinter_badname(torture, p, "__INVALID_PRINTER__");
1743         ret &= test_OpenPrinter_badname(torture, p, "\\\\__INVALID_HOST__");
1744         ret &= test_OpenPrinter_badname(torture, p, "");
1745         ret &= test_OpenPrinter_badname(torture, p, "\\\\\\");
1746         ret &= test_OpenPrinter_badname(torture, p, "\\\\\\__INVALID_PRINTER__");
1747         ret &= test_OpenPrinter_badname(torture, p, talloc_asprintf(torture, "\\\\%s\\", dcerpc_server_name(p)));
1748         ret &= test_OpenPrinter_badname(torture, p, 
1749                                         talloc_asprintf(torture, "\\\\%s\\__INVALID_PRINTER__", dcerpc_server_name(p)));
1750
1751
1752         ret &= test_AddPort(torture, p);
1753         ret &= test_EnumPorts_old(torture, p);
1754         ret &= test_EnumPrinters_old(torture, p);
1755         ret &= test_EnumPrinterDrivers_old(torture, p);
1756         ret &= test_ReplyOpenPrinter(torture, p);
1757
1758         return ret;
1759 }