1/* 2 Unix SMB/CIFS implementation. 3 test suite for spoolss rpc operations as performed by various win versions 4 5 Copyright (C) Kai Blin 2007 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 "torture/rpc/rpc.h" 24#include "librpc/gen_ndr/ndr_spoolss_c.h" 25#include "rpc_server/dcerpc_server.h" 26#include "librpc/gen_ndr/ndr_misc.h" 27#include "ntvfs/ntvfs.h" 28#include "param/param.h" 29 30struct test_spoolss_win_context { 31 /* EnumPrinters */ 32 uint32_t printer_count; 33 union spoolss_PrinterInfo *printer_info; 34 union spoolss_PrinterInfo *current_info; 35 36 /* EnumPrinterKeys */ 37 const char **printer_keys; 38 39 bool printer_has_driver; 40}; 41 42/* This is a convenience function for all OpenPrinterEx calls */ 43static bool test_OpenPrinterEx(struct torture_context *tctx, 44 struct dcerpc_pipe *p, 45 struct policy_handle *handle, 46 const char *printer_name, 47 uint32_t access_mask) 48{ 49 NTSTATUS status; 50 struct spoolss_OpenPrinterEx op; 51 struct spoolss_UserLevel1 ul_1; 52 53 torture_comment(tctx, "Opening printer '%s'\n", printer_name); 54 55 op.in.printername = talloc_strdup(tctx, printer_name); 56 op.in.datatype = NULL; 57 op.in.devmode_ctr.devmode = NULL; 58 op.in.access_mask = access_mask; 59 op.in.level = 1; 60 op.in.userlevel.level1 = &ul_1; 61 op.out.handle = handle; 62 63 ul_1.size = 1234; 64 ul_1.client = "\\clientname"; 65 ul_1.user = "username"; 66 ul_1.build = 1; 67 ul_1.major = 2; 68 ul_1.minor = 3; 69 ul_1.processor = 4567; 70 71 status = dcerpc_spoolss_OpenPrinterEx(p, tctx, &op); 72 torture_assert_ntstatus_ok(tctx, status, "OpenPrinterEx failed"); 73 torture_assert_werr_ok(tctx, op.out.result, "OpenPrinterEx failed"); 74 75 return true; 76} 77 78static bool test_OpenPrinterAsAdmin(struct torture_context *tctx, 79 struct dcerpc_pipe *p, 80 const char *printername) 81{ 82 NTSTATUS status; 83 struct spoolss_OpenPrinterEx op; 84 struct spoolss_ClosePrinter cp; 85 struct spoolss_UserLevel1 ul_1; 86 struct policy_handle handle; 87 88 ul_1.size = 1234; 89 ul_1.client = "\\clientname"; 90 ul_1.user = "username"; 91 ul_1.build = 1; 92 ul_1.major = 2; 93 ul_1.minor = 3; 94 ul_1.processor = 4567; 95 96 op.in.printername = talloc_strdup(tctx, printername); 97 op.in.datatype = NULL; 98 op.in.devmode_ctr.devmode = NULL; 99 op.in.access_mask = SERVER_ALL_ACCESS; 100 op.in.level = 1; 101 op.in.userlevel.level1 = &ul_1; 102 op.out.handle = &handle; 103 104 cp.in.handle = &handle; 105 cp.out.handle = &handle; 106 107 torture_comment(tctx, "Testing OpenPrinterEx(%s) with admin rights\n", 108 op.in.printername); 109 110 status = dcerpc_spoolss_OpenPrinterEx(p, tctx, &op); 111 112 if (NT_STATUS_IS_OK(status) && W_ERROR_IS_OK(op.out.result)) { 113 status = dcerpc_spoolss_ClosePrinter(p, tctx, &cp); 114 torture_assert_ntstatus_ok(tctx, status, "ClosePrinter failed"); 115 } 116 117 return true; 118} 119 120 121static bool test_ClosePrinter(struct torture_context *tctx, 122 struct dcerpc_pipe *p, 123 struct policy_handle *handle); 124 125/* This replicates the opening sequence of OpenPrinterEx calls XP does */ 126static bool test_OpenPrinterSequence(struct torture_context *tctx, 127 struct dcerpc_pipe *p, 128 struct policy_handle *handle) 129{ 130 bool ret; 131 char *printername = talloc_asprintf(tctx, "\\\\%s", 132 dcerpc_server_name(p)); 133 134 /* First, see if we can open the printer read_only */ 135 ret = test_OpenPrinterEx(tctx, p, handle, printername, 0); 136 torture_assert(tctx, ret == true, "OpenPrinterEx failed."); 137 138 ret = test_ClosePrinter(tctx, p, handle); 139 torture_assert(tctx, ret, "ClosePrinter failed"); 140 141 /* Now let's see if we have admin rights to it. */ 142 ret = test_OpenPrinterAsAdmin(tctx, p, printername); 143 torture_assert(tctx, ret == true, 144 "OpenPrinterEx as admin failed unexpectedly."); 145 146 ret = test_OpenPrinterEx(tctx, p, handle, printername, SERVER_EXECUTE); 147 torture_assert(tctx, ret == true, "OpenPrinterEx failed."); 148 149 return true; 150} 151 152static bool test_GetPrinterData(struct torture_context *tctx, 153 struct dcerpc_pipe *p, 154 struct policy_handle *handle, 155 const char *value_name, 156 WERROR expected_werr, 157 uint32_t expected_value) 158{ 159 NTSTATUS status; 160 struct spoolss_GetPrinterData gpd; 161 uint32_t needed; 162 enum winreg_Type type; 163 uint8_t *data = talloc_zero_array(tctx, uint8_t, 4); 164 165 torture_comment(tctx, "Testing GetPrinterData(%s).\n", value_name); 166 gpd.in.handle = handle; 167 gpd.in.value_name = value_name; 168 gpd.in.offered = 4; 169 gpd.out.needed = &needed; 170 gpd.out.type = &type; 171 gpd.out.data = data; 172 173 status = dcerpc_spoolss_GetPrinterData(p, tctx, &gpd); 174 torture_assert_ntstatus_ok(tctx, status, "GetPrinterData failed."); 175 torture_assert_werr_equal(tctx, gpd.out.result, expected_werr, 176 "GetPrinterData did not return expected error value."); 177 178 if (W_ERROR_IS_OK(expected_werr)) { 179 uint32_t value = IVAL(data, 0); 180 torture_assert_int_equal(tctx, value, 181 expected_value, 182 talloc_asprintf(tctx, "GetPrinterData for %s did not return expected value.", value_name)); 183 } 184 return true; 185} 186 187static bool test_EnumPrinters(struct torture_context *tctx, 188 struct dcerpc_pipe *p, 189 struct test_spoolss_win_context *ctx, 190 uint32_t initial_blob_size) 191{ 192 NTSTATUS status; 193 struct spoolss_EnumPrinters ep; 194 DATA_BLOB blob = data_blob_talloc_zero(ctx, initial_blob_size); 195 uint32_t needed; 196 uint32_t count; 197 union spoolss_PrinterInfo *info; 198 199 ep.in.flags = PRINTER_ENUM_NAME; 200 ep.in.server = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p)); 201 ep.in.level = 2; 202 ep.in.buffer = &blob; 203 ep.in.offered = initial_blob_size; 204 ep.out.needed = &needed; 205 ep.out.count = &count; 206 ep.out.info = &info; 207 208 status = dcerpc_spoolss_EnumPrinters(p, ctx, &ep); 209 torture_assert_ntstatus_ok(tctx, status, "EnumPrinters failed."); 210 211 if (W_ERROR_EQUAL(ep.out.result, WERR_INSUFFICIENT_BUFFER)) { 212 blob = data_blob_talloc_zero(ctx, needed); 213 ep.in.buffer = &blob; 214 ep.in.offered = needed; 215 status = dcerpc_spoolss_EnumPrinters(p, ctx, &ep); 216 torture_assert_ntstatus_ok(tctx, status,"EnumPrinters failed."); 217 } 218 219 torture_assert_werr_ok(tctx, ep.out.result, "EnumPrinters failed."); 220 221 ctx->printer_count = count; 222 ctx->printer_info = info; 223 224 torture_comment(tctx, "Found %d printer(s).\n", ctx->printer_count); 225 226 return true; 227} 228 229static bool test_GetPrinter(struct torture_context *tctx, 230 struct dcerpc_pipe *p, 231 struct policy_handle *handle, 232 struct test_spoolss_win_context *ctx, 233 uint32_t level, 234 uint32_t initial_blob_size) 235{ 236 NTSTATUS status; 237 struct spoolss_GetPrinter gp; 238 DATA_BLOB blob = data_blob_talloc_zero(ctx, initial_blob_size); 239 uint32_t needed; 240 241 torture_comment(tctx, "Test GetPrinter level %d\n", level); 242 243 gp.in.handle = handle; 244 gp.in.level = level; 245 gp.in.buffer = (initial_blob_size == 0)?NULL:&blob; 246 gp.in.offered = initial_blob_size; 247 gp.out.needed = &needed; 248 249 status = dcerpc_spoolss_GetPrinter(p, tctx, &gp); 250 torture_assert_ntstatus_ok(tctx, status, "GetPrinter failed"); 251 252 if (W_ERROR_EQUAL(gp.out.result, WERR_INSUFFICIENT_BUFFER)) { 253 blob = data_blob_talloc_zero(ctx, needed); 254 gp.in.buffer = &blob; 255 gp.in.offered = needed; 256 status = dcerpc_spoolss_GetPrinter(p, tctx, &gp); 257 torture_assert_ntstatus_ok(tctx, status, "GetPrinter failed"); 258 } 259 260 torture_assert_werr_ok(tctx, gp.out.result, "GetPrinter failed"); 261 262 ctx->current_info = gp.out.info; 263 264 if (level == 2 && gp.out.info) { 265 ctx->printer_has_driver = gp.out.info->info2.drivername && 266 strlen(gp.out.info->info2.drivername); 267 } 268 269 return true; 270} 271 272static bool test_EnumJobs(struct torture_context *tctx, 273 struct dcerpc_pipe *p, 274 struct policy_handle *handle) 275{ 276 NTSTATUS status; 277 struct spoolss_EnumJobs ej; 278 DATA_BLOB blob = data_blob_talloc_zero(tctx, 1024); 279 uint32_t needed; 280 uint32_t count; 281 union spoolss_JobInfo *info; 282 283 torture_comment(tctx, "Test EnumJobs\n"); 284 285 ej.in.handle = handle; 286 ej.in.level = 2; 287 ej.in.buffer = &blob; 288 ej.in.offered = 1024; 289 ej.out.needed = &needed; 290 ej.out.count = &count; 291 ej.out.info = &info; 292 293 status = dcerpc_spoolss_EnumJobs(p, tctx, &ej); 294 torture_assert_ntstatus_ok(tctx, status, "EnumJobs failed"); 295 if (W_ERROR_EQUAL(ej.out.result, WERR_INSUFFICIENT_BUFFER)) { 296 blob = data_blob_talloc_zero(tctx, needed); 297 ej.in.offered = needed; 298 ej.in.buffer = &blob; 299 status = dcerpc_spoolss_EnumJobs(p, tctx, &ej); 300 torture_assert_ntstatus_ok(tctx, status, "EnumJobs failed"); 301 } 302 torture_assert_werr_ok(tctx, ej.out.result, "EnumJobs failed"); 303 304 return true; 305} 306 307static bool test_GetPrinterDriver2(struct torture_context *tctx, 308 struct dcerpc_pipe *p, 309 struct test_spoolss_win_context *ctx, 310 struct policy_handle *handle) 311{ 312 NTSTATUS status; 313 struct spoolss_GetPrinterDriver2 gpd2; 314 DATA_BLOB blob = data_blob_talloc_zero(tctx, 87424); 315 uint32_t needed; 316 uint32_t server_major_version; 317 uint32_t server_minor_version; 318 319 torture_comment(tctx, "Testing GetPrinterDriver2\n"); 320 321 gpd2.in.handle = handle; 322 gpd2.in.architecture = "Windows NT x86"; 323 gpd2.in.level = 101; 324 gpd2.in.buffer = &blob; 325 gpd2.in.offered = 87424; 326 gpd2.in.client_major_version = 3; 327 gpd2.in.client_minor_version = 0; 328 gpd2.out.needed = &needed; 329 gpd2.out.server_major_version = &server_major_version; 330 gpd2.out.server_minor_version = &server_minor_version; 331 332 status = dcerpc_spoolss_GetPrinterDriver2(p, tctx, &gpd2); 333 torture_assert_ntstatus_ok(tctx, status, "GetPrinterDriver2 failed"); 334 335 if (ctx->printer_has_driver) { 336 torture_assert_werr_ok(tctx, gpd2.out.result, 337 "GetPrinterDriver2 failed."); 338 } 339 340 return true; 341} 342 343static bool test_EnumForms(struct torture_context *tctx, 344 struct dcerpc_pipe *p, 345 struct policy_handle *handle, 346 uint32_t initial_blob_size) 347{ 348 NTSTATUS status; 349 struct spoolss_EnumForms ef; 350 DATA_BLOB blob = data_blob_talloc_zero(tctx, initial_blob_size); 351 uint32_t needed; 352 uint32_t count; 353 union spoolss_FormInfo *info; 354 355 torture_comment(tctx, "Testing EnumForms\n"); 356 357 ef.in.handle = handle; 358 ef.in.level = 1; 359 ef.in.buffer = (initial_blob_size == 0)?NULL:&blob; 360 ef.in.offered = initial_blob_size; 361 ef.out.needed = &needed; 362 ef.out.count = &count; 363 ef.out.info = &info; 364 365 status = dcerpc_spoolss_EnumForms(p, tctx, &ef); 366 torture_assert_ntstatus_ok(tctx, status, "EnumForms failed"); 367 368 if (W_ERROR_EQUAL(ef.out.result, WERR_INSUFFICIENT_BUFFER)) { 369 blob = data_blob_talloc_zero(tctx, needed); 370 ef.in.buffer = &blob; 371 ef.in.offered = needed; 372 status = dcerpc_spoolss_EnumForms(p, tctx, &ef); 373 torture_assert_ntstatus_ok(tctx, status, "EnumForms failed"); 374 } 375 376 torture_assert_werr_ok(tctx, ef.out.result, "EnumForms failed"); 377 378 return true; 379} 380 381static bool test_EnumPrinterKey(struct torture_context *tctx, 382 struct dcerpc_pipe *p, 383 struct policy_handle *handle, 384 const char* key, 385 struct test_spoolss_win_context *ctx) 386{ 387 NTSTATUS status; 388 struct spoolss_EnumPrinterKey epk; 389 uint32_t needed = 0; 390 union spoolss_KeyNames key_buffer; 391 uint32_t _ndr_size; 392 393 torture_comment(tctx, "Testing EnumPrinterKey(%s)\n", key); 394 395 epk.in.handle = handle; 396 epk.in.key_name = talloc_strdup(tctx, key); 397 epk.in.offered = 0; 398 epk.out.needed = &needed; 399 epk.out.key_buffer = &key_buffer; 400 epk.out._ndr_size = &_ndr_size; 401 402 status = dcerpc_spoolss_EnumPrinterKey(p, tctx, &epk); 403 torture_assert_ntstatus_ok(tctx, status, "EnumPrinterKey failed"); 404 405 if (W_ERROR_EQUAL(epk.out.result, WERR_MORE_DATA)) { 406 epk.in.offered = needed; 407 status = dcerpc_spoolss_EnumPrinterKey(p, tctx, &epk); 408 torture_assert_ntstatus_ok(tctx, status, 409 "EnumPrinterKey failed"); 410 } 411 412 torture_assert_werr_ok(tctx, epk.out.result, "EnumPrinterKey failed"); 413 414 ctx->printer_keys = key_buffer.string_array; 415 416 return true; 417} 418 419static bool test_EnumPrinterDataEx(struct torture_context *tctx, 420 struct dcerpc_pipe *p, 421 struct policy_handle *handle, 422 const char *key, 423 uint32_t initial_blob_size, 424 WERROR expected_error) 425{ 426 NTSTATUS status; 427 struct spoolss_EnumPrinterDataEx epde; 428 struct spoolss_PrinterEnumValues *info; 429 uint32_t needed; 430 uint32_t count; 431 432 torture_comment(tctx, "Testing EnumPrinterDataEx(%s)\n", key); 433 434 epde.in.handle = handle; 435 epde.in.key_name = talloc_strdup(tctx, key); 436 epde.in.offered = 0; 437 epde.out.needed = &needed; 438 epde.out.count = &count; 439 epde.out.info = &info; 440 441 status = dcerpc_spoolss_EnumPrinterDataEx(p, tctx, &epde); 442 torture_assert_ntstatus_ok(tctx, status, "EnumPrinterDataEx failed."); 443 if (W_ERROR_EQUAL(epde.out.result, WERR_MORE_DATA)) { 444 epde.in.offered = needed; 445 status = dcerpc_spoolss_EnumPrinterDataEx(p, tctx, &epde); 446 torture_assert_ntstatus_ok(tctx, status, 447 "EnumPrinterDataEx failed."); 448 } 449 450 torture_assert_werr_equal(tctx, epde.out.result, expected_error, 451 "EnumPrinterDataEx failed."); 452 453 return true; 454} 455 456static bool test_ClosePrinter(struct torture_context *tctx, 457 struct dcerpc_pipe *p, 458 struct policy_handle *handle) 459{ 460 NTSTATUS status; 461 struct spoolss_ClosePrinter cp; 462 463 cp.in.handle = handle; 464 cp.out.handle = handle; 465 466 status = dcerpc_spoolss_ClosePrinter(p, tctx, &cp); 467 torture_assert_ntstatus_ok(tctx, status, "ClosePrinter failed"); 468 469 return true; 470} 471 472static bool test_WinXP(struct torture_context *tctx, struct dcerpc_pipe *p) 473{ 474 bool ret = true; 475 struct test_spoolss_win_context *ctx, *tmp_ctx; 476 struct policy_handle handle01, handle02, handle03, handle04; 477 /* Sometimes a handle stays unused. In order to make this clear in the 478 * code, the unused_handle structures are used for that. */ 479 struct policy_handle unused_handle1, unused_handle2; 480 char *server_name; 481 uint32_t i; 482 483 ntvfs_init(tctx->lp_ctx); 484 485 ctx = talloc_zero(tctx, struct test_spoolss_win_context); 486 tmp_ctx = talloc_zero(tctx, struct test_spoolss_win_context); 487 488 ret &= test_OpenPrinterSequence(tctx, p, &handle01); 489 ret &= test_GetPrinterData(tctx, p, &handle01,"UISingleJobStatusString", 490 WERR_INVALID_PARAM, 0); 491 torture_comment(tctx, "Skip RemoteFindNextPrinterChangeNotifyEx test\n"); 492 493 server_name = talloc_asprintf(ctx, "\\\\%s", dcerpc_server_name(p)); 494 ret &= test_OpenPrinterEx(tctx, p, &unused_handle1, server_name, 0); 495 496 ret &= test_EnumPrinters(tctx, p, ctx, 1024); 497 498 ret &= test_OpenPrinterEx(tctx, p, &handle02, server_name, 0); 499 ret &= test_GetPrinterData(tctx, p, &handle02, "MajorVersion", WERR_OK, 500 3); 501 ret &= test_ClosePrinter(tctx, p, &handle02); 502 503 /* If no printers were found, skip all tests that need a printer */ 504 if (ctx->printer_count == 0) { 505 goto end_testWinXP; 506 } 507 508 ret &= test_OpenPrinterEx(tctx, p, &handle02, 509 ctx->printer_info[0].info2.printername, 510 PRINTER_ACCESS_USE); 511 ret &= test_GetPrinter(tctx, p, &handle02, ctx, 2, 0); 512 513 torture_assert_str_equal(tctx, ctx->current_info->info2.printername, 514 ctx->printer_info[0].info2.printername, 515 "GetPrinter returned unexpected printername"); 516 /*FIXME: Test more components of the PrinterInfo2 struct */ 517 518 ret &= test_OpenPrinterEx(tctx, p, &handle03, 519 ctx->printer_info[0].info2.printername, 0); 520 ret &= test_GetPrinter(tctx, p, &handle03, ctx, 0, 1164); 521 ret &= test_GetPrinter(tctx, p, &handle03, ctx, 2, 0); 522 523 ret &= test_OpenPrinterEx(tctx, p, &handle04, 524 ctx->printer_info[0].info2.printername, 0); 525 ret &= test_GetPrinter(tctx, p, &handle04, ctx, 2, 0); 526 ret &= test_ClosePrinter(tctx, p, &handle04); 527 528 ret &= test_OpenPrinterEx(tctx, p, &handle04, 529 ctx->printer_info[0].info2.printername, 0); 530 ret &= test_GetPrinter(tctx, p, &handle04, ctx, 2, 4096); 531 ret &= test_ClosePrinter(tctx, p, &handle04); 532 533 ret &= test_OpenPrinterAsAdmin(tctx, p, 534 ctx->printer_info[0].info2.printername); 535 536 ret &= test_OpenPrinterEx(tctx, p, &handle04, 537 ctx->printer_info[0].info2.printername, PRINTER_READ); 538 ret &= test_GetPrinterData(tctx, p, &handle04,"UISingleJobStatusString", 539 WERR_BADFILE, 0); 540 torture_comment(tctx, "Skip RemoteFindNextPrinterChangeNotifyEx test\n"); 541 542 ret &= test_OpenPrinterEx(tctx, p, &unused_handle2, 543 ctx->printer_info[0].info2.printername, 0); 544 545 ret &= test_EnumJobs(tctx, p, &handle04); 546 ret &= test_GetPrinter(tctx, p, &handle04, ctx, 2, 4096); 547 548 ret &= test_ClosePrinter(tctx, p, &unused_handle2); 549 ret &= test_ClosePrinter(tctx, p, &handle04); 550 551 ret &= test_EnumPrinters(tctx, p, ctx, 1556); 552 ret &= test_GetPrinterDriver2(tctx, p, ctx, &handle03); 553 ret &= test_EnumForms(tctx, p, &handle03, 0); 554 555 ret &= test_EnumPrinterKey(tctx, p, &handle03, "", ctx); 556 557 for (i=0; ctx->printer_keys && ctx->printer_keys[i] != NULL; i++) { 558 559 ret &= test_EnumPrinterKey(tctx, p, &handle03, 560 ctx->printer_keys[i], 561 tmp_ctx); 562 ret &= test_EnumPrinterDataEx(tctx, p, &handle03, 563 ctx->printer_keys[i], 0, 564 WERR_OK); 565 } 566 567 ret &= test_EnumPrinterDataEx(tctx, p, &handle03, "", 0, 568 WERR_INVALID_PARAM); 569 570 ret &= test_GetPrinter(tctx, p, &handle03, tmp_ctx, 2, 0); 571 572 ret &= test_OpenPrinterEx(tctx, p, &unused_handle2, 573 ctx->printer_info[0].info2.printername, 0); 574 ret &= test_ClosePrinter(tctx, p, &unused_handle2); 575 576 ret &= test_GetPrinter(tctx, p, &handle03, tmp_ctx, 2, 2556); 577 578 ret &= test_OpenPrinterEx(tctx, p, &unused_handle2, 579 ctx->printer_info[0].info2.printername, 0); 580 ret &= test_ClosePrinter(tctx, p, &unused_handle2); 581 582 ret &= test_OpenPrinterEx(tctx, p, &unused_handle2, 583 ctx->printer_info[0].info2.printername, 0); 584 ret &= test_ClosePrinter(tctx, p, &unused_handle2); 585 586 ret &= test_GetPrinter(tctx, p, &handle03, tmp_ctx, 7, 0); 587 588 ret &= test_OpenPrinterEx(tctx, p, &unused_handle2, 589 ctx->printer_info[0].info2.printername, 0); 590 ret &= test_ClosePrinter(tctx, p, &unused_handle2); 591 592 ret &= test_ClosePrinter(tctx, p, &handle03); 593 594 ret &= test_OpenPrinterEx(tctx, p, &unused_handle2, 595 ctx->printer_info[0].info2.printername, 0); 596 ret &= test_ClosePrinter(tctx, p, &unused_handle2); 597 598 ret &= test_OpenPrinterEx(tctx, p, &handle03, server_name, 0); 599 ret &= test_GetPrinterData(tctx, p, &handle03, "W3SvcInstalled", 600 WERR_OK, 0); 601 ret &= test_ClosePrinter(tctx, p, &handle03); 602 603 ret &= test_ClosePrinter(tctx, p, &unused_handle1); 604 ret &= test_ClosePrinter(tctx, p, &handle02); 605 606 ret &= test_OpenPrinterEx(tctx, p, &handle02, 607 ctx->printer_info[0].info2.sharename, 0); 608 ret &= test_GetPrinter(tctx, p, &handle02, tmp_ctx, 2, 0); 609 ret &= test_ClosePrinter(tctx, p, &handle02); 610 611end_testWinXP: 612 ret &= test_ClosePrinter(tctx, p, &handle01); 613 614 talloc_free(tmp_ctx); 615 talloc_free(ctx); 616 return ret; 617} 618 619struct torture_suite *torture_rpc_spoolss_win(TALLOC_CTX *mem_ctx) 620{ 621 struct torture_suite *suite = torture_suite_create(mem_ctx, "SPOOLSS-WIN"); 622 623 struct torture_rpc_tcase *tcase = torture_suite_add_rpc_iface_tcase(suite, 624 "win", &ndr_table_spoolss); 625 626 torture_rpc_tcase_add_test(tcase, "testWinXP", test_WinXP); 627 628 return suite; 629} 630 631