iremotewinspool-tests: Add client os build number validation test
[samba.git] / source4 / torture / rpc / iremotewinspool.c
1 /*
2    Unix SMB/CIFS implementation.
3    test suite for iremotewinspool rpc operations
4
5    Copyright (C) Guenther Deschner 2013
6
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 3 of the License, or
10    (at your option) any later version.
11
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16
17    You should have received a copy of the GNU General Public License
18    along with this program.  If not, see <http://www.gnu.org/licenses/>.
19 */
20
21 #include "includes.h"
22 #include "torture/torture.h"
23 #include "librpc/gen_ndr/ndr_winspool.h"
24 #include "librpc/gen_ndr/ndr_winspool_c.h"
25 #include "librpc/gen_ndr/ndr_spoolss_c.h"
26 #include "torture/rpc/torture_rpc.h"
27 #include "libcli/registry/util_reg.h"
28
29 struct test_iremotewinspool_context {
30         struct GUID object_uuid;
31         struct dcerpc_pipe *iremotewinspool_pipe;
32         struct policy_handle server_handle;
33         const char *environment;
34 };
35
36 enum client_os_version
37 {
38         WIN_2000,
39         WIN_VISTA,
40         WIN_SERVER_2008,
41         WIN_7,
42         WIN_SERVER_2008R2,
43         WIN_8,
44         WIN_SERVER_2012,
45         WIN_10,
46         WIN_SERVER_2016
47 };
48
49 static struct spoolss_UserLevel1 test_get_client_info(struct torture_context *tctx,
50                                                       enum client_os_version os,
51                                                       enum spoolss_MajorVersion major_number,
52                                                       enum spoolss_MinorVersion minor_number)
53 {
54         struct spoolss_UserLevel1 level1;
55
56         level1.size     = 28;
57         level1.client   = talloc_asprintf(tctx, "\\\\%s", "mthelena");
58         level1.user     = "GD";
59         level1.processor = PROCESSOR_ARCHITECTURE_AMD64;
60         level1.major    = major_number;
61         level1.minor    = minor_number;
62
63         switch (os) {
64                 case WIN_SERVER_2016:
65                 case WIN_10:
66                         level1.build = 10586;
67                         break;
68                 case WIN_SERVER_2012:
69                 case WIN_8:
70                         level1.build = 9200;
71                         break;
72                 case WIN_SERVER_2008R2:
73                 case WIN_7:
74                         level1.build = 7007;
75                         break;
76                 case WIN_SERVER_2008:
77                 case WIN_VISTA:
78                         level1.build = 6000;
79                         break;
80                 case WIN_2000:
81                         level1.build = 1382;
82                         break;
83                 default:
84                         level1.build = 7007;
85         }
86
87         return level1;
88 }
89
90 static bool test_AsyncOpenPrinter_byprinter(struct torture_context *tctx,
91                                             struct test_iremotewinspool_context *ctx,
92                                             struct dcerpc_pipe *p,
93                                             const char *printer_name,
94                                             struct spoolss_UserLevel1 cinfo,
95                                             struct policy_handle *handle)
96 {
97         struct dcerpc_binding_handle *b = p->binding_handle;
98         struct spoolss_DevmodeContainer devmode_ctr;
99         struct spoolss_UserLevelCtr client_info_ctr;
100         uint32_t access_mask = SERVER_ALL_ACCESS;
101         struct winspool_AsyncOpenPrinter r;
102
103         ZERO_STRUCT(devmode_ctr);
104
105         client_info_ctr.level = 1;
106         client_info_ctr.user_info.level1 = &cinfo;
107
108         r.in.pPrinterName       = printer_name;
109         r.in.pDatatype          = NULL;
110         r.in.pDevModeContainer  = &devmode_ctr;
111         r.in.AccessRequired     = access_mask;
112         r.in.pClientInfo        = &client_info_ctr;
113         r.out.pHandle           = handle;
114
115         torture_assert_ntstatus_ok(tctx,
116                 dcerpc_winspool_AsyncOpenPrinter_r(b, tctx, &r),
117                 "AsyncOpenPrinter failed");
118         torture_assert_werr_ok(tctx, r.out.result,
119                 "AsyncOpenPrinter failed");
120
121         return true;
122 }
123
124 static bool test_AsyncClosePrinter_byhandle(struct torture_context *tctx,
125                                             struct test_iremotewinspool_context *ctx,
126                                             struct dcerpc_pipe *p,
127                                             struct policy_handle *handle)
128 {
129         struct dcerpc_binding_handle *b = p->binding_handle;
130
131         struct winspool_AsyncClosePrinter r;
132
133         r.in.phPrinter = handle;
134         r.out.phPrinter = handle;
135
136         torture_assert_ntstatus_ok(tctx,
137                 dcerpc_winspool_AsyncClosePrinter_r(b, tctx, &r),
138                 "AsyncClosePrinter failed");
139         torture_assert_werr_ok(tctx, r.out.result,
140                 "AsyncClosePrinter failed");
141
142         return true;
143 }
144
145 static bool test_AsyncGetPrinterData_checktype(struct torture_context *tctx,
146                                                struct dcerpc_binding_handle *b,
147                                                struct policy_handle *handle,
148                                                const char *value_name,
149                                                enum winreg_Type *expected_type,
150                                                enum winreg_Type *type_p,
151                                                uint8_t **data_p,
152                                                uint32_t *needed_p)
153 {
154         struct winspool_AsyncGetPrinterData r;
155         enum winreg_Type type;
156         uint32_t needed;
157
158         r.in.hPrinter = *handle;
159         r.in.pValueName = value_name;
160         r.in.nSize = 0;
161         r.out.pType = &type;
162         r.out.pData = talloc_zero_array(tctx, uint8_t, r.in.nSize);
163         r.out.pcbNeeded = &needed;
164
165         torture_comment(tctx, "Testing AsyncGetPrinterData(%s)\n",
166                 r.in.pValueName);
167
168         torture_assert_ntstatus_ok(tctx,
169                 dcerpc_winspool_AsyncGetPrinterData_r(b, tctx, &r),
170                 "AsyncGetPrinterData failed");
171
172         if (W_ERROR_EQUAL(r.out.result, WERR_MORE_DATA)) {
173                 if (expected_type) {
174                         torture_assert_int_equal(tctx, type, *expected_type, "unexpected type");
175                 }
176                 r.in.nSize = needed;
177                 r.out.pData = talloc_zero_array(tctx, uint8_t, r.in.nSize);
178
179                 torture_assert_ntstatus_ok(tctx,
180                         dcerpc_winspool_AsyncGetPrinterData_r(b, tctx, &r),
181                         "AsyncGetPrinterData failed");
182         }
183
184         torture_assert_werr_ok(tctx, r.out.result,
185                 "AsyncGetPrinterData failed");
186
187         if (type_p) {
188                 *type_p = type;
189         }
190
191         if (data_p) {
192                 *data_p = r.out.pData;
193         }
194
195         if (needed_p) {
196                 *needed_p = needed;
197         }
198
199         return true;
200 }
201
202 static bool test_AsyncGetPrinterData_args(struct torture_context *tctx,
203                                           struct dcerpc_binding_handle *b,
204                                           struct policy_handle *handle,
205                                           const char *value_name,
206                                           enum winreg_Type *type_p,
207                                           uint8_t **data_p,
208                                           uint32_t *needed_p)
209 {
210         return test_AsyncGetPrinterData_checktype(tctx, b, handle,
211                                                   value_name,
212                                                   NULL,
213                                                   type_p, data_p, needed_p);
214 }
215
216 static bool test_get_environment(struct torture_context *tctx,
217                                  struct dcerpc_binding_handle *b,
218                                  struct policy_handle *handle,
219                                  const char **architecture)
220 {
221         DATA_BLOB blob;
222         enum winreg_Type type;
223         uint8_t *data;
224         uint32_t needed;
225
226         torture_assert(tctx,
227                 test_AsyncGetPrinterData_args(tctx, b, handle, "Architecture", &type, &data, &needed),
228                 "failed to get Architecture");
229
230         torture_assert_int_equal(tctx, type, REG_SZ, "unexpected type");
231
232         blob = data_blob_const(data, needed);
233
234         torture_assert(tctx,
235                 pull_reg_sz(tctx, &blob, architecture),
236                 "failed to pull environment");
237
238         return true;
239 }
240
241 static bool torture_rpc_iremotewinspool_setup_common(struct torture_context *tctx,
242                                                      struct test_iremotewinspool_context *t)
243 {
244         const char *printer_name;
245         struct spoolss_UserLevel1 client_info;
246         struct dcerpc_binding *binding;
247
248         torture_assert_ntstatus_ok(tctx,
249                 GUID_from_string(IREMOTEWINSPOOL_OBJECT_GUID, &t->object_uuid),
250                 "failed to parse GUID");
251
252         torture_assert_ntstatus_ok(tctx,
253                 torture_rpc_binding(tctx, &binding),
254                 "failed to retrieve torture binding");
255
256         torture_assert_ntstatus_ok(tctx,
257                 dcerpc_binding_set_object(binding, t->object_uuid),
258                 "failed to set object_uuid");
259
260         torture_assert_ntstatus_ok(tctx,
261                 torture_rpc_connection_with_binding(tctx, binding, &t->iremotewinspool_pipe, &ndr_table_iremotewinspool),
262                 "Error connecting to server");
263
264         printer_name = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(t->iremotewinspool_pipe));
265
266         client_info = test_get_client_info(tctx, WIN_2000, 3, SPOOLSS_MINOR_VERSION_0);
267
268         torture_assert(tctx,
269                 test_AsyncOpenPrinter_byprinter(tctx, t,
270                                                 t->iremotewinspool_pipe, printer_name,
271                                                 client_info, &t->server_handle),
272                                                 "failed to open printserver");
273         torture_assert(tctx,
274                 test_get_environment(tctx,
275                                      t->iremotewinspool_pipe->binding_handle,
276                                      &t->server_handle, &t->environment),
277                                      "failed to get environment");
278
279         return true;
280 }
281
282 static bool torture_rpc_iremotewinspool_setup(struct torture_context *tctx,
283                                               void **data)
284 {
285         struct test_iremotewinspool_context *t;
286
287         *data = t = talloc_zero(tctx, struct test_iremotewinspool_context);
288
289         return torture_rpc_iremotewinspool_setup_common(tctx, t);
290 }
291
292 static bool torture_rpc_iremotewinspool_teardown_common(struct torture_context *tctx,
293                                                         struct test_iremotewinspool_context *t)
294 {
295
296         test_AsyncClosePrinter_byhandle(tctx, t, t->iremotewinspool_pipe, &t->server_handle);
297
298         return true;
299 }
300
301 static bool torture_rpc_iremotewinspool_teardown(struct torture_context *tctx,
302                                                  void *data)
303 {
304         struct test_iremotewinspool_context *t = talloc_get_type(data, struct test_iremotewinspool_context);
305         bool ret;
306
307         ret = torture_rpc_iremotewinspool_teardown_common(tctx, t);
308         talloc_free(t);
309
310         return ret;
311 }
312
313 static bool test_AsyncClosePrinter(struct torture_context *tctx,
314                                    void *private_data)
315 {
316         struct test_iremotewinspool_context *ctx =
317                 talloc_get_type_abort(private_data, struct test_iremotewinspool_context);
318
319         struct dcerpc_pipe *p = ctx->iremotewinspool_pipe;
320         const char *printer_name;
321         struct spoolss_UserLevel1 client_info;
322         struct policy_handle handle;
323
324         printer_name = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
325
326         client_info = test_get_client_info(tctx, WIN_2000, 3, SPOOLSS_MINOR_VERSION_0);
327
328         torture_assert(tctx,
329                 test_AsyncOpenPrinter_byprinter(tctx, ctx, p, printer_name, client_info, &handle),
330                 "failed to test AsyncOpenPrinter");
331
332         torture_assert(tctx,
333                 test_AsyncClosePrinter_byhandle(tctx, ctx, p, &handle),
334                 "failed to test AsyncClosePrinter");
335
336         return true;
337 }
338
339 static bool test_AsyncOpenPrinter(struct torture_context *tctx,
340                                   void *private_data)
341 {
342         struct test_iremotewinspool_context *ctx =
343                 talloc_get_type_abort(private_data, struct test_iremotewinspool_context);
344
345         struct dcerpc_pipe *p = ctx->iremotewinspool_pipe;
346         const char *printer_name;
347         struct spoolss_UserLevel1 client_info;
348         struct policy_handle handle;
349
350         printer_name = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
351
352         client_info = test_get_client_info(tctx, WIN_2000, 3, SPOOLSS_MINOR_VERSION_0);
353
354         torture_assert(tctx,
355                 test_AsyncOpenPrinter_byprinter(tctx, ctx, p, printer_name, client_info, &handle),
356                 "failed to test AsyncOpenPrinter");
357
358         test_AsyncClosePrinter_byhandle(tctx, ctx, p, &handle);
359
360         return true;
361 }
362
363 /*
364  * Validate the result of AsyncOpenPrinter calls based on client info
365  * build number. Windows Server 2016 rejects an advertised build
366  * number less than 6000(Windows Vista and Windows Server 2008, or older)
367  */
368 static bool test_AsyncOpenPrinterValidateBuildNumber(struct torture_context *tctx,
369                                                      void *private_data)
370 {
371         struct test_iremotewinspool_context *ctx =
372                 talloc_get_type_abort(private_data, struct test_iremotewinspool_context);
373
374         struct dcerpc_pipe *p = ctx->iremotewinspool_pipe;
375         const char *printer_name;
376         struct spoolss_UserLevel1 client_info;
377         struct policy_handle handle;
378         struct dcerpc_binding_handle *b = p->binding_handle;
379         struct spoolss_DevmodeContainer devmode_ctr;
380         struct spoolss_UserLevelCtr client_info_ctr = {
381                 .level = 1,
382         };
383         uint32_t access_mask = SERVER_ALL_ACCESS;
384         struct winspool_AsyncOpenPrinter r;
385         NTSTATUS status;
386         bool ok = false;
387
388         printer_name = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
389         torture_assert_not_null(tctx, printer_name, "Cannot allocate memory");
390
391         /* fail with Windows 2000 build number */
392         client_info = test_get_client_info(tctx, WIN_2000, 3, SPOOLSS_MINOR_VERSION_0);
393
394         ZERO_STRUCT(devmode_ctr);
395
396         client_info_ctr.user_info.level1 = &client_info;
397
398         r.in.pPrinterName       = printer_name;
399         r.in.pDatatype          = NULL;
400         r.in.pDevModeContainer  = &devmode_ctr;
401         r.in.AccessRequired     = access_mask;
402         r.in.pClientInfo        = &client_info_ctr;
403         r.out.pHandle           = &handle;
404
405         status = dcerpc_winspool_AsyncOpenPrinter_r(b, tctx, &r);
406         torture_assert_ntstatus_ok(tctx, status, "AsyncOpenPrinter failed");
407         torture_assert_werr_equal(tctx, r.out.result, WERR_ACCESS_DENIED,
408                 "AsyncOpenPrinter should have failed");
409
410         /* succeed with Windows 7 build number */
411         client_info = test_get_client_info(tctx, WIN_7, 3, SPOOLSS_MINOR_VERSION_0);
412         client_info_ctr.user_info.level1 = &client_info;
413         r.in.pClientInfo        = &client_info_ctr;
414
415         status = dcerpc_winspool_AsyncOpenPrinter_r(b, tctx, &r);
416         torture_assert_ntstatus_ok(tctx, status, "AsyncOpenPrinter failed");
417         torture_assert_werr_ok(tctx, r.out.result,
418                 "AsyncOpenPrinter failed");
419
420         ok = test_AsyncClosePrinter_byhandle(tctx, ctx, p, &handle);
421         torture_assert(tctx, ok, "failed to AsyncClosePrinter handle");
422
423         return true;
424
425 }
426
427 static struct spoolss_NotifyOption *setup_printserver_NotifyOption(struct torture_context *tctx)
428 {
429         struct spoolss_NotifyOption *o;
430
431         o = talloc_zero(tctx, struct spoolss_NotifyOption);
432         if (o == NULL) {
433                 return NULL;
434         }
435
436         o->version = 2;
437         o->flags = PRINTER_NOTIFY_OPTIONS_REFRESH;
438
439         o->count = 2;
440         o->types = talloc_zero_array(o, struct spoolss_NotifyOptionType, o->count);
441         if (o->types == NULL) {
442                 talloc_free(o);
443                 return NULL;
444         }
445
446         o->types[0].type = PRINTER_NOTIFY_TYPE;
447         o->types[0].count = 1;
448         o->types[0].fields = talloc_array(o->types, union spoolss_Field, o->types[0].count);
449         if (o->types[0].fields == NULL) {
450                 talloc_free(o);
451                 return NULL;
452         }
453         o->types[0].fields[0].field = PRINTER_NOTIFY_FIELD_SERVER_NAME;
454
455         o->types[1].type = JOB_NOTIFY_TYPE;
456         o->types[1].count = 1;
457         o->types[1].fields = talloc_array(o->types, union spoolss_Field, o->types[1].count);
458         if (o->types[1].fields == NULL) {
459                 talloc_free(o);
460                 return NULL;
461         }
462         o->types[1].fields[0].field = JOB_NOTIFY_FIELD_MACHINE_NAME;
463
464         return o;
465 }
466
467 static bool test_SyncUnRegisterForRemoteNotifications_args(struct torture_context *tctx,
468                                                            struct dcerpc_pipe *p,
469                                                            struct policy_handle *notify_handle)
470 {
471         struct winspool_SyncUnRegisterForRemoteNotifications r;
472         struct dcerpc_binding_handle *b = p->binding_handle;
473
474         r.in.phRpcHandle = notify_handle;
475         r.out.phRpcHandle = notify_handle;
476
477         torture_assert_ntstatus_ok(tctx,
478                 dcerpc_winspool_SyncUnRegisterForRemoteNotifications_r(b, tctx, &r),
479                 "SyncUnRegisterForRemoteNotifications failed");
480         torture_assert_hresult_ok(tctx, r.out.result,
481                 "SyncUnRegisterForRemoteNotifications failed");
482
483         return true;
484 }
485
486 static bool test_SyncRegisterForRemoteNotifications_args(struct torture_context *tctx,
487                                                          struct dcerpc_pipe *p,
488                                                          struct policy_handle *server_handle,
489                                                          struct policy_handle *notify_handle);
490
491 static bool test_SyncUnRegisterForRemoteNotifications(struct torture_context *tctx,
492                                                       void *private_data)
493 {
494         struct test_iremotewinspool_context *ctx =
495                 talloc_get_type_abort(private_data, struct test_iremotewinspool_context);
496         struct policy_handle notify_handle;
497
498         torture_assert(tctx,
499                 test_SyncRegisterForRemoteNotifications_args(tctx,
500                                                              ctx->iremotewinspool_pipe,
501                                                              &ctx->server_handle,
502                                                              &notify_handle),
503                 "failed to test SyncRegisterForRemoteNotifications");
504
505         torture_assert(tctx,
506                 test_SyncUnRegisterForRemoteNotifications_args(tctx,
507                                                                ctx->iremotewinspool_pipe,
508                                                                &notify_handle),
509                 "failed to test UnSyncRegisterForRemoteNotifications");
510
511         return true;
512 }
513
514 static bool test_SyncRegisterForRemoteNotifications_args(struct torture_context *tctx,
515                                                          struct dcerpc_pipe *p,
516                                                          struct policy_handle *server_handle,
517                                                          struct policy_handle *notify_handle)
518 {
519         struct dcerpc_binding_handle *b = p->binding_handle;
520
521         struct winspool_SyncRegisterForRemoteNotifications r;
522         struct winspool_PrintPropertiesCollection NotifyFilter;
523         struct winspool_PrintNamedProperty *c;
524         struct spoolss_NotifyOption *options;
525
526         ZERO_STRUCT(NotifyFilter);
527
528         options = setup_printserver_NotifyOption(tctx);
529         torture_assert(tctx, options, "out of memory");
530
531         c = talloc_zero_array(tctx, struct winspool_PrintNamedProperty, 4);
532         torture_assert(tctx, c, "out of memory");
533
534         c[0].propertyName = "RemoteNotifyFilter Flags";
535         c[0].propertyValue.PropertyType = winspool_PropertyTypeInt32;
536         c[0].propertyValue.value.propertyInt32 = 0xff;
537
538         c[1].propertyName = "RemoteNotifyFilter Options";
539         c[1].propertyValue.PropertyType = winspool_PropertyTypeInt32;
540         c[1].propertyValue.value.propertyInt32 = 0;
541
542         c[2].propertyName = "RemoteNotifyFilter Color";
543         c[2].propertyValue.PropertyType = winspool_PropertyTypeInt32;
544         c[2].propertyValue.value.propertyInt32 = 0;
545
546         c[3].propertyName = "RemoteNotifyFilter NotifyOptions";
547         c[3].propertyValue.PropertyType = winspool_PropertyTypeNotificationOptions;
548         c[3].propertyValue.value.propertyOptionsContainer.pOptions = options;
549
550         NotifyFilter.numberOfProperties = 4;
551         NotifyFilter.propertiesCollection = c;
552
553         r.in.hPrinter = *server_handle;
554         r.in.pNotifyFilter = &NotifyFilter;
555         r.out.phRpcHandle = notify_handle;
556
557         torture_assert_ntstatus_ok(tctx,
558                 dcerpc_winspool_SyncRegisterForRemoteNotifications_r(b, tctx, &r),
559                 "SyncRegisterForRemoteNotifications failed");
560         torture_assert_hresult_ok(tctx, r.out.result,
561                 "SyncRegisterForRemoteNotifications failed");
562
563         return true;
564 }
565
566 static bool test_SyncRegisterForRemoteNotifications(struct torture_context *tctx,
567                                                     void *private_data)
568 {
569         struct test_iremotewinspool_context *ctx =
570                 talloc_get_type_abort(private_data, struct test_iremotewinspool_context);
571         struct policy_handle notify_handle;
572
573         torture_assert(tctx,
574                 test_SyncRegisterForRemoteNotifications_args(tctx,
575                                                              ctx->iremotewinspool_pipe,
576                                                              &ctx->server_handle,
577                                                              &notify_handle),
578                 "failed to test SyncRegisterForRemoteNotifications");
579
580         test_SyncUnRegisterForRemoteNotifications_args(tctx, ctx->iremotewinspool_pipe, &notify_handle);
581
582         return true;
583 }
584
585 static bool test_AsyncUploadPrinterDriverPackage(struct torture_context *tctx,
586                                                  void *private_data)
587 {
588         struct test_iremotewinspool_context *ctx =
589                 talloc_get_type_abort(private_data, struct test_iremotewinspool_context);
590
591         struct dcerpc_pipe *p = ctx->iremotewinspool_pipe;
592         struct dcerpc_binding_handle *b = p->binding_handle;
593
594         struct winspool_AsyncUploadPrinterDriverPackage r;
595         uint32_t pcchDestInfPath = 0;
596
597         r.in.pszServer = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
598         r.in.pszInfPath = "";
599         r.in.pszEnvironment = "";
600         r.in.dwFlags = 0;
601         r.in.pszDestInfPath = NULL;
602         r.in.pcchDestInfPath = &pcchDestInfPath;
603         r.out.pszDestInfPath = NULL;
604         r.out.pcchDestInfPath = &pcchDestInfPath;
605
606         torture_assert_ntstatus_ok(tctx,
607                 dcerpc_winspool_AsyncUploadPrinterDriverPackage_r(b, tctx, &r),
608                 "AsyncUploadPrinterDriverPackage failed");
609         torture_assert_hresult_equal(tctx, r.out.result, HRES_E_INVALIDARG,
610                 "AsyncUploadPrinterDriverPackage failed");
611
612         pcchDestInfPath = 260;
613         r.in.pszDestInfPath = talloc_zero_array(tctx, uint16_t, pcchDestInfPath);
614         r.out.pszDestInfPath = talloc_zero_array(tctx, uint16_t, pcchDestInfPath);
615
616         torture_assert_ntstatus_ok(tctx,
617                 dcerpc_winspool_AsyncUploadPrinterDriverPackage_r(b, tctx, &r),
618                 "AsyncUploadPrinterDriverPackage failed");
619         torture_assert_werr_equal(tctx,
620                 W_ERROR(WIN32_FROM_HRESULT(r.out.result)), WERR_INVALID_ENVIRONMENT,
621                 "AsyncUploadPrinterDriverPackage failed");
622
623         r.in.pszEnvironment = SPOOLSS_ARCHITECTURE_x64;
624
625         torture_assert_ntstatus_ok(tctx,
626                 dcerpc_winspool_AsyncUploadPrinterDriverPackage_r(b, tctx, &r),
627                 "AsyncUploadPrinterDriverPackage failed");
628         torture_assert_werr_equal(tctx,
629                 W_ERROR(WIN32_FROM_HRESULT(r.out.result)), WERR_FILE_NOT_FOUND,
630                 "AsyncUploadPrinterDriverPackage failed");
631
632         r.in.pszInfPath = "\\\\mthelena\\print$\\x64\\{BD443844-ED00-4D96-8CAE-95E49492312A}\\prnbrcl1.inf";
633
634         torture_assert_ntstatus_ok(tctx,
635                 dcerpc_winspool_AsyncUploadPrinterDriverPackage_r(b, tctx, &r),
636                 "AsyncUploadPrinterDriverPackage failed");
637         torture_assert_werr_equal(tctx,
638                 W_ERROR(WIN32_FROM_HRESULT(r.out.result)), WERR_FILE_NOT_FOUND,
639                 "AsyncUploadPrinterDriverPackage failed");
640
641         return true;
642 }
643
644 static bool test_AsyncEnumPrinters(struct torture_context *tctx,
645                                    void *private_data)
646 {
647         struct test_iremotewinspool_context *ctx =
648                 talloc_get_type_abort(private_data, struct test_iremotewinspool_context);
649
650         struct dcerpc_pipe *p = ctx->iremotewinspool_pipe;
651         struct dcerpc_binding_handle *b = p->binding_handle;
652
653         struct winspool_AsyncEnumPrinters r;
654         uint32_t levels[] = { 1, 2, /*3,*/ 4, 5 };
655         int i;
656
657         uint32_t needed;
658         uint32_t returned;
659
660         for (i = 0; i < ARRAY_SIZE(levels); i++) {
661
662                 r.in.Flags = PRINTER_ENUM_LOCAL;
663                 r.in.pName = NULL;
664                 r.in.Level = levels[i];
665                 r.in.cbBuf = 0;
666                 r.in.pPrinterEnum = NULL;
667                 r.out.pcbNeeded = &needed;
668                 r.out.pcReturned = &returned;
669                 r.out.pPrinterEnum = NULL;
670
671                 torture_assert_ntstatus_ok(tctx,
672                         dcerpc_winspool_AsyncEnumPrinters_r(b, tctx, &r),
673                         "AsyncEnumPrinters failed");
674                 torture_assert_werr_equal(tctx, r.out.result, WERR_INSUFFICIENT_BUFFER,
675                         "AsyncEnumPrinters failed");
676
677                 r.in.cbBuf = needed;
678                 r.in.pPrinterEnum = talloc_zero_array(tctx, uint8_t, r.in.cbBuf);
679                 r.out.pPrinterEnum = r.in.pPrinterEnum;
680
681                 torture_assert_ntstatus_ok(tctx,
682                         dcerpc_winspool_AsyncEnumPrinters_r(b, tctx, &r),
683                         "AsyncEnumPrinters failed");
684                 torture_assert_werr_ok(tctx, r.out.result,
685                         "AsyncEnumPrinters failed");
686         }
687
688         return true;
689 }
690
691 static bool test_AsyncGetPrinterData(struct torture_context *tctx,
692                                      void *private_data)
693 {
694         struct test_iremotewinspool_context *ctx =
695                 talloc_get_type_abort(private_data, struct test_iremotewinspool_context);
696
697         struct dcerpc_pipe *p = ctx->iremotewinspool_pipe;
698         struct dcerpc_binding_handle *b = p->binding_handle;
699         DATA_BLOB blob;
700         const char *s;
701         bool ok;
702
703         uint32_t pType;
704         uint32_t pcbNeeded;
705         uint8_t *pData;
706
707         torture_assert(tctx,
708                 test_AsyncGetPrinterData_args(tctx, b, &ctx->server_handle,
709                                               "MajorVersion",
710                                               &pType, &pData, &pcbNeeded),
711                 "failed to check for MajorVersion");
712
713         torture_assert_int_equal(tctx, pcbNeeded, 4, "pcbNeeded");
714         torture_assert_int_equal(tctx, pType, REG_DWORD, "pType");
715         torture_assert_int_equal(tctx, IVAL(pData, 0), 3, "pData");
716
717         torture_assert(tctx,
718                 test_AsyncGetPrinterData_args(tctx, b, &ctx->server_handle,
719                                               "Architecture",
720                                               &pType, &pData, &pcbNeeded),
721                 "failed to check for Architecture");
722
723         blob = data_blob_const(pData, pcbNeeded);
724
725         torture_assert_int_equal(tctx, pType, REG_SZ, "pType");
726         torture_assert(tctx, pull_reg_sz(tctx, &blob, &s), "");
727         ok = strequal(s, SPOOLSS_ARCHITECTURE_x64) || strequal(s, SPOOLSS_ARCHITECTURE_NT_X86);
728         torture_assert(tctx, ok, "unexpected architecture returned");
729
730         return true;
731 }
732
733 static bool test_AsyncCorePrinterDriverInstalled(struct torture_context *tctx,
734                                                  void *private_data)
735 {
736         struct test_iremotewinspool_context *ctx =
737                 talloc_get_type_abort(private_data, struct test_iremotewinspool_context);
738
739         struct dcerpc_pipe *p = ctx->iremotewinspool_pipe;
740         struct dcerpc_binding_handle *b = p->binding_handle;
741
742         struct winspool_AsyncCorePrinterDriverInstalled r;
743         int32_t pbDriverInstalled;
744         struct GUID guid;
745
746         r.in.pszServer = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
747         r.in.pszEnvironment = "";
748         r.in.CoreDriverGUID = GUID_zero();
749         r.in.ftDriverDate = 0;
750         r.in.dwlDriverVersion = 0;
751         r.out.pbDriverInstalled = &pbDriverInstalled;
752
753         torture_assert_ntstatus_ok(tctx,
754                 dcerpc_winspool_AsyncCorePrinterDriverInstalled_r(b, tctx, &r),
755                 "AsyncCorePrinterDriverInstalled failed");
756         torture_assert_werr_equal(tctx,
757                 W_ERROR(WIN32_FROM_HRESULT(r.out.result)), WERR_INVALID_ENVIRONMENT,
758                 "AsyncCorePrinterDriverInstalled failed");
759
760         r.in.pszEnvironment = SPOOLSS_ARCHITECTURE_x64;
761
762         torture_assert_ntstatus_ok(tctx,
763                 dcerpc_winspool_AsyncCorePrinterDriverInstalled_r(b, tctx, &r),
764                 "AsyncCorePrinterDriverInstalled failed");
765         torture_assert_hresult_ok(tctx, r.out.result,
766                 "AsyncCorePrinterDriverInstalled failed");
767         torture_assert_int_equal(tctx, *r.out.pbDriverInstalled, false,
768                                 "unexpected driver installed");
769
770         r.in.CoreDriverGUID = GUID_random();
771
772         torture_assert_ntstatus_ok(tctx,
773                 dcerpc_winspool_AsyncCorePrinterDriverInstalled_r(b, tctx, &r),
774                 "AsyncCorePrinterDriverInstalled failed");
775         torture_assert_hresult_ok(tctx, r.out.result,
776                 "AsyncCorePrinterDriverInstalled failed");
777         torture_assert_int_equal(tctx, *r.out.pbDriverInstalled, false,
778                                 "unexpected driver installed");
779
780         torture_assert_ntstatus_ok(tctx,
781                 GUID_from_string(SPOOLSS_CORE_PRINT_PACKAGE_FILES_XPSDRV, &guid), "");
782
783         r.in.CoreDriverGUID = guid;
784
785         torture_assert_ntstatus_ok(tctx,
786                 dcerpc_winspool_AsyncCorePrinterDriverInstalled_r(b, tctx, &r),
787                 "AsyncCorePrinterDriverInstalled failed");
788         torture_assert_hresult_ok(tctx, r.out.result,
789                 "AsyncCorePrinterDriverInstalled failed");
790         torture_assert_int_equal(tctx, *r.out.pbDriverInstalled, true,
791                                 "xps core driver not installed?");
792
793         r.in.dwlDriverVersion = 0xffffffff;
794
795         torture_assert_ntstatus_ok(tctx,
796                 dcerpc_winspool_AsyncCorePrinterDriverInstalled_r(b, tctx, &r),
797                 "AsyncCorePrinterDriverInstalled failed");
798         torture_assert_hresult_ok(tctx, r.out.result,
799                 "AsyncCorePrinterDriverInstalled failed");
800         torture_assert_int_equal(tctx, *r.out.pbDriverInstalled, true,
801                                 "xps core driver not installed?");
802
803         r.in.dwlDriverVersion = 1234;
804
805         torture_assert_ntstatus_ok(tctx,
806                 dcerpc_winspool_AsyncCorePrinterDriverInstalled_r(b, tctx, &r),
807                 "AsyncCorePrinterDriverInstalled failed");
808         torture_assert_hresult_ok(tctx, r.out.result,
809                 "AsyncCorePrinterDriverInstalled failed");
810         torture_assert_int_equal(tctx, *r.out.pbDriverInstalled, true,
811                                 "xps core driver not installed?");
812
813         r.in.ftDriverDate = unix_timespec_to_nt_time(timespec_current());
814
815         torture_assert_ntstatus_ok(tctx,
816                 dcerpc_winspool_AsyncCorePrinterDriverInstalled_r(b, tctx, &r),
817                 "AsyncCorePrinterDriverInstalled failed");
818         torture_assert_hresult_ok(tctx, r.out.result,
819                 "AsyncCorePrinterDriverInstalled failed");
820         torture_assert_int_equal(tctx, *r.out.pbDriverInstalled, false,
821                                 "driver too old ?");
822
823         r.in.dwlDriverVersion = 0;
824
825         torture_assert_ntstatus_ok(tctx,
826                 dcerpc_winspool_AsyncCorePrinterDriverInstalled_r(b, tctx, &r),
827                 "AsyncCorePrinterDriverInstalled failed");
828         torture_assert_hresult_ok(tctx, r.out.result,
829                 "AsyncCorePrinterDriverInstalled failed");
830         torture_assert_int_equal(tctx, *r.out.pbDriverInstalled, false,
831                                 "unexpected driver installed");
832
833         return true;
834 }
835
836 static bool test_get_core_printer_drivers_arch_guid(struct torture_context *tctx,
837                                                     struct dcerpc_pipe *p,
838                                                     const char *architecture,
839                                                     const char *guid_str,
840                                                     const char **package_id)
841 {
842         struct winspool_AsyncGetCorePrinterDrivers r;
843         DATA_BLOB blob;
844         const char **s;
845         struct dcerpc_binding_handle *b = p->binding_handle;
846
847         s = talloc_zero_array(tctx, const char *, 2);
848         s[0] = guid_str;
849
850         torture_assert(tctx,
851                 push_reg_multi_sz(tctx, &blob, s),
852                 "push_reg_multi_sz failed");
853
854         r.in.pszServer = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
855         r.in.pszEnvironment = architecture;
856         r.in.cchCoreDrivers = blob.length/2;
857         r.in.pszzCoreDriverDependencies = (uint16_t *)blob.data;
858         r.in.cCorePrinterDrivers = 1;
859         r.out.pCorePrinterDrivers = talloc_zero_array(tctx, struct spoolss_CorePrinterDriver, r.in.cCorePrinterDrivers);
860
861         torture_assert_ntstatus_ok(tctx,
862                 dcerpc_winspool_AsyncGetCorePrinterDrivers_r(b, tctx, &r),
863                 "winspool_AsyncCorePrinterDrivers failed");
864         torture_assert_hresult_ok(tctx, r.out.result,
865                 "winspool_AsyncCorePrinterDrivers failed");
866
867         if (package_id) {
868                 *package_id = r.out.pCorePrinterDrivers[0].szPackageID;
869         }
870
871         return true;
872 }
873
874 static bool test_AsyncDeletePrintDriverPackage(struct torture_context *tctx,
875                                                void *private_data)
876 {
877         struct test_iremotewinspool_context *ctx =
878                 talloc_get_type_abort(private_data, struct test_iremotewinspool_context);
879
880         struct dcerpc_pipe *p = ctx->iremotewinspool_pipe;
881         struct dcerpc_binding_handle *b = p->binding_handle;
882         struct winspool_AsyncDeletePrinterDriverPackage r;
883
884         const char *architectures[] = {
885 /*              SPOOLSS_ARCHITECTURE_NT_X86, */
886                 SPOOLSS_ARCHITECTURE_x64
887         };
888         int i;
889
890         for (i=0; i < ARRAY_SIZE(architectures); i++) {
891
892                 const char *package_id;
893
894                 torture_assert(tctx,
895                         test_get_core_printer_drivers_arch_guid(tctx, p,
896                                                                 architectures[i],
897                                                                 SPOOLSS_CORE_PRINT_PACKAGE_FILES_XPSDRV,
898                                                                 &package_id),
899                         "failed to get core printer driver");
900
901                 r.in.pszServer = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
902                 r.in.pszEnvironment = "";
903                 r.in.pszInfPath = "";
904
905                 torture_comment(tctx, "Testing AsyncDeletePrinterDriverPackage(%s, %s, %s)\n",
906                         r.in.pszServer, architectures[i], package_id);
907
908                 torture_assert_ntstatus_ok(tctx,
909                         dcerpc_winspool_AsyncDeletePrinterDriverPackage_r(b, tctx, &r),
910                         "AsyncDeletePrinterDriverPackage failed");
911                 torture_assert_werr_equal(tctx,
912                         W_ERROR(WIN32_FROM_HRESULT(r.out.result)), WERR_NOT_FOUND,
913                         "AsyncDeletePrinterDriverPackage failed");
914
915                 r.in.pszInfPath = package_id;
916
917                 torture_assert_ntstatus_ok(tctx,
918                         dcerpc_winspool_AsyncDeletePrinterDriverPackage_r(b, tctx, &r),
919                         "AsyncDeletePrinterDriverPackage failed");
920                 torture_assert_werr_equal(tctx,
921                         W_ERROR(WIN32_FROM_HRESULT(r.out.result)), WERR_INVALID_ENVIRONMENT,
922                         "AsyncDeletePrinterDriverPackage failed");
923
924                 r.in.pszEnvironment = architectures[i];
925
926                 torture_assert_ntstatus_ok(tctx,
927                         dcerpc_winspool_AsyncDeletePrinterDriverPackage_r(b, tctx, &r),
928                         "AsyncDeletePrinterDriverPackage failed");
929                 torture_assert_hresult_equal(tctx, r.out.result, HRES_E_ACCESSDENIED,
930                         "AsyncDeletePrinterDriverPackage failed");
931         }
932
933         return true;
934 }
935
936 static bool test_AsyncGetPrinterDriverDirectory(struct torture_context *tctx,
937                                                 void *private_data)
938 {
939         struct test_iremotewinspool_context *ctx =
940                 talloc_get_type_abort(private_data, struct test_iremotewinspool_context);
941
942         struct dcerpc_pipe *p = ctx->iremotewinspool_pipe;
943         struct dcerpc_binding_handle *b = p->binding_handle;
944         struct winspool_AsyncGetPrinterDriverDirectory r;
945         uint32_t pcbNeeded;
946         DATA_BLOB blob;
947         const char *s;
948
949         r.in.pName = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
950         r.in.pEnvironment = ctx->environment;
951         r.in.Level = 1;
952         r.in.cbBuf = 0x200;
953         r.in.pDriverDirectory = talloc_zero_array(tctx, uint8_t, r.in.cbBuf);
954         r.out.pcbNeeded = &pcbNeeded;
955         r.out.pDriverDirectory = r.in.pDriverDirectory;
956
957         torture_comment(tctx, "Testing AsyncGetPrinterDriverDirectory(%s, %s)\n",
958                 r.in.pName, r.in.pEnvironment);
959
960         torture_assert_ntstatus_ok(tctx,
961                 dcerpc_winspool_AsyncGetPrinterDriverDirectory_r(b, tctx, &r),
962                 "AsyncGetPrinterDriverDirectory failed");
963         torture_assert_werr_ok(tctx, r.out.result,
964                 "AsyncGetPrinterDriverDirectory failed");
965
966         blob = data_blob_const(r.out.pDriverDirectory, pcbNeeded);
967
968         torture_assert(tctx,
969                 pull_reg_sz(tctx, &blob, &s),
970                 "failed to pull reg_sz");
971
972         torture_comment(tctx, "got: %s\n", s);
973
974         return true;
975 }
976
977 /*
978  * Test if one can close a printserver handle that has been acquired via
979  * winspool_AsyncOpenPrinter with a spoolss_ClosePrinter operation.
980  */
981
982 static bool test_OpenPrinter(struct torture_context *tctx,
983                              void *private_data)
984 {
985         struct test_iremotewinspool_context *ctx =
986                 talloc_get_type_abort(private_data, struct test_iremotewinspool_context);
987
988         struct dcerpc_pipe *p = ctx->iremotewinspool_pipe;
989         const char *printer_name;
990         struct policy_handle handle;
991         struct dcerpc_pipe *s;
992         struct dcerpc_binding *binding;
993         struct spoolss_UserLevel1 client_info;
994         struct spoolss_ClosePrinter r;
995
996         torture_assert_ntstatus_ok(tctx,
997                 torture_rpc_binding(tctx, &binding),
998                 "failed to get binding");
999
1000         torture_assert_ntstatus_ok(tctx,
1001                 dcerpc_binding_set_transport(binding, NCACN_NP),
1002                 "failed to set ncacn_np transport");
1003
1004         torture_assert_ntstatus_ok(tctx,
1005                 dcerpc_binding_set_object(binding, GUID_zero()),
1006                 "failed to set object uuid to zero");
1007
1008         torture_assert_ntstatus_ok(tctx,
1009                 torture_rpc_connection_with_binding(tctx, binding, &s, &ndr_table_spoolss),
1010                 "failed to connect to spoolss");
1011
1012         printer_name = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
1013
1014         client_info = test_get_client_info(tctx, WIN_2000, 3, SPOOLSS_MINOR_VERSION_0);
1015
1016         torture_assert(tctx,
1017                 test_AsyncOpenPrinter_byprinter(tctx, ctx, p, printer_name, client_info, &handle),
1018                 "failed to open printserver via winspool");
1019
1020
1021         r.in.handle = &handle;
1022         r.out.handle = &handle;
1023
1024         torture_assert_ntstatus_equal(tctx,
1025                 dcerpc_spoolss_ClosePrinter_r(s->binding_handle, tctx, &r),
1026                 NT_STATUS_RPC_SS_CONTEXT_MISMATCH,
1027                 "ClosePrinter failed");
1028
1029         talloc_free(s);
1030
1031         return true;
1032 }
1033
1034 struct torture_suite *torture_rpc_iremotewinspool(TALLOC_CTX *mem_ctx)
1035 {
1036         struct torture_suite *suite = torture_suite_create(mem_ctx, "iremotewinspool");
1037         struct torture_tcase *tcase = torture_suite_add_tcase(suite, "printserver");
1038
1039         torture_tcase_set_fixture(tcase,
1040                                   torture_rpc_iremotewinspool_setup,
1041                                   torture_rpc_iremotewinspool_teardown);
1042
1043         torture_tcase_add_simple_test(tcase, "AsyncOpenPrinter", test_AsyncOpenPrinter);
1044         torture_tcase_add_simple_test(tcase, "SyncRegisterForRemoteNotifications", test_SyncRegisterForRemoteNotifications);
1045         torture_tcase_add_simple_test(tcase, "SyncUnRegisterForRemoteNotifications", test_SyncUnRegisterForRemoteNotifications);
1046         torture_tcase_add_simple_test(tcase, "AsyncClosePrinter", test_AsyncClosePrinter);
1047         torture_tcase_add_simple_test(tcase, "AsyncUploadPrinterDriverPackage", test_AsyncUploadPrinterDriverPackage);
1048         torture_tcase_add_simple_test(tcase, "AsyncEnumPrinters", test_AsyncEnumPrinters);
1049         torture_tcase_add_simple_test(tcase, "AsyncGetPrinterData", test_AsyncGetPrinterData);
1050         torture_tcase_add_simple_test(tcase, "AsyncCorePrinterDriverInstalled", test_AsyncCorePrinterDriverInstalled);
1051         torture_tcase_add_simple_test(tcase, "AsyncDeletePrintDriverPackage", test_AsyncDeletePrintDriverPackage);
1052         torture_tcase_add_simple_test(tcase, "AsyncGetPrinterDriverDirectory", test_AsyncGetPrinterDriverDirectory);
1053         torture_tcase_add_simple_test(tcase, "AsyncOpenPrinterValidateBuildNumber", test_AsyncOpenPrinterValidateBuildNumber);
1054
1055         tcase = torture_suite_add_tcase(suite, "handles");
1056
1057         torture_tcase_set_fixture(tcase,
1058                                   torture_rpc_iremotewinspool_setup,
1059                                   torture_rpc_iremotewinspool_teardown);
1060
1061         torture_tcase_add_simple_test(tcase, "OpenPrinter", test_OpenPrinter);
1062
1063         return suite;
1064 }