s4-smbtorture: add RPC-SPOOLSS-DRIVER test.
authorGünther Deschner <gd@samba.org>
Thu, 2 Jul 2009 19:49:15 +0000 (21:49 +0200)
committerGünther Deschner <gd@samba.org>
Fri, 23 Apr 2010 00:16:09 +0000 (02:16 +0200)
Guenther

source4/torture/rpc/rpc.c
source4/torture/rpc/spoolss.c

index cfaeb5656d3474f944eacd1d76f024cf64382bc3..13855cdaf63d2cbd39a5d9cbb0f51c5f70718186 100644 (file)
@@ -445,6 +445,7 @@ NTSTATUS torture_rpc_init(void)
        torture_suite_add_suite(suite, torture_rpc_spoolss_notify(suite));
        torture_suite_add_suite(suite, torture_rpc_spoolss_win(suite));
        torture_suite_add_suite(suite, torture_rpc_spoolss_printer(suite));
+       torture_suite_add_suite(suite, torture_rpc_spoolss_driver(suite));
        torture_suite_add_simple_test(suite, "SAMR", torture_rpc_samr);
        torture_suite_add_simple_test(suite, "SAMR-USERS", torture_rpc_samr_users);
        torture_suite_add_simple_test(suite, "SAMR-PASSWORDS", torture_rpc_samr_passwords);
index 4ded8778cddc8ad04d61899176d6a0ea8b1e1b67..72bee6f1bd37b840cc60d265ed6dba48b2f17b91 100644 (file)
@@ -37,6 +37,8 @@
 #define TORTURE_PRINTER                        "torture_printer"
 #define TORTURE_WELLKNOWN_PRINTER_EX   "torture_wkn_printer_ex"
 #define TORTURE_PRINTER_EX             "torture_printer_ex"
+#define TORTURE_DRIVER                 "torture_driver"
+#define TORTURE_DRIVER_EX              "torture_driver_ex"
 
 #define TOP_LEVEL_PRINT_KEY "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Print"
 #define TOP_LEVEL_PRINT_PRINTERS_KEY TOP_LEVEL_PRINT_KEY "\\Printers"
@@ -70,6 +72,18 @@ struct test_spoolss_context {
        union spoolss_PrinterInfo *printers[6];
 };
 
+struct torture_driver_context {
+       struct {
+               const char *driver_directory;
+               const char *environment;
+       } local;
+       struct {
+               const char *driver_directory;
+               const char *environment;
+       } remote;
+       struct spoolss_AddDriverInfo8 info8;
+};
+
 #define COMPARE_STRING(tctx, c,r,e) \
        torture_assert_str_equal(tctx, c.e, r.e, "invalid value")
 
@@ -6430,3 +6444,740 @@ struct torture_suite *torture_rpc_spoolss_printer(TALLOC_CTX *mem_ctx)
 
        return suite;
 }
+
+static bool test_GetPrinterDriverDirectory_getdir(struct torture_context *tctx,
+                                                 struct dcerpc_binding_handle *b,
+                                                 const char *server,
+                                                 const char *environment,
+                                                 const char **dir_p)
+{
+       struct spoolss_GetPrinterDriverDirectory r;
+       uint32_t needed;
+
+       r.in.server             = server;
+       r.in.environment        = environment;
+       r.in.level              = 1;
+       r.in.buffer             = NULL;
+       r.in.offered            = 0;
+       r.out.needed            = &needed;
+
+       torture_assert_ntstatus_ok(tctx,
+               dcerpc_spoolss_GetPrinterDriverDirectory_r(b, tctx, &r),
+               "failed to query driver directory");
+
+       if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
+               DATA_BLOB blob = data_blob_talloc_zero(tctx, needed);
+               r.in.buffer = &blob;
+               r.in.offered = needed;
+
+               torture_assert_ntstatus_ok(tctx,
+                       dcerpc_spoolss_GetPrinterDriverDirectory_r(b, tctx, &r),
+                       "failed to query driver directory");
+       }
+
+       torture_assert_werr_ok(tctx, r.out.result,
+               "failed to query driver directory");
+
+       if (dir_p) {
+               *dir_p = r.out.info->info1.directory_name;
+       }
+
+       return true;
+}
+
+static const char *get_driver_from_info(struct spoolss_AddDriverInfoCtr *info_ctr)
+{
+       if (info_ctr == NULL) {
+               return NULL;
+       }
+
+       switch (info_ctr->level) {
+       case 1:
+               return info_ctr->info.info1->driver_name;
+       case 2:
+               return info_ctr->info.info2->driver_name;
+       case 3:
+               return info_ctr->info.info3->driver_name;
+       case 4:
+               return info_ctr->info.info4->driver_name;
+       case 6:
+               return info_ctr->info.info6->driver_name;
+       case 8:
+               return info_ctr->info.info8->driver_name;
+       default:
+               return NULL;
+       }
+}
+
+static bool test_AddPrinterDriver_exp(struct torture_context *tctx,
+                                     struct dcerpc_binding_handle *b,
+                                     const char *servername,
+                                     struct spoolss_AddDriverInfoCtr *info_ctr,
+                                     WERROR expected_result)
+{
+       struct spoolss_AddPrinterDriver r;
+       const char *drivername = get_driver_from_info(info_ctr);
+
+       r.in.servername = servername;
+       r.in.info_ctr = info_ctr;
+
+       torture_comment(tctx, "Testing AddPrinterDriver(%s) level %d\n",
+               drivername, info_ctr->level);
+
+       torture_assert_ntstatus_ok(tctx,
+               dcerpc_spoolss_AddPrinterDriver_r(b, tctx, &r),
+               "spoolss_AddPrinterDriver failed");
+       torture_assert_werr_equal(tctx, r.out.result, expected_result,
+               "spoolss_AddPrinterDriver failed with unexpected result");
+
+       return true;
+
+}
+
+static bool test_AddPrinterDriverEx_exp(struct torture_context *tctx,
+                                       struct dcerpc_binding_handle *b,
+                                       const char *servername,
+                                       struct spoolss_AddDriverInfoCtr *info_ctr,
+                                       uint32_t flags,
+                                       WERROR expected_result)
+{
+       struct spoolss_AddPrinterDriverEx r;
+       const char *drivername = get_driver_from_info(info_ctr);
+
+       r.in.servername = servername;
+       r.in.info_ctr = info_ctr;
+       r.in.flags = flags;
+
+       torture_comment(tctx, "Testing AddPrinterDriverEx(%s) level %d\n",
+               drivername, info_ctr->level);
+
+       torture_assert_ntstatus_ok(tctx,
+               dcerpc_spoolss_AddPrinterDriverEx_r(b, tctx, &r),
+               "AddPrinterDriverEx failed");
+       torture_assert_werr_equal(tctx, r.out.result, expected_result,
+               "AddPrinterDriverEx failed with unexpected result");
+
+       return true;
+}
+
+static bool test_AddPrinterDriver_args_level_1(struct torture_context *tctx,
+                                              struct dcerpc_binding_handle *b,
+                                              const char *server_name,
+                                              struct spoolss_AddDriverInfo8 *r,
+                                              uint32_t flags,
+                                              bool ex)
+{
+       struct spoolss_AddDriverInfoCtr info_ctr;
+       struct spoolss_AddDriverInfo1 info1;
+
+       ZERO_STRUCT(info1);
+
+       info_ctr.level = 1;
+       info_ctr.info.info1 = &info1;
+
+       if (ex) {
+               torture_assert(tctx,
+                       test_AddPrinterDriverEx_exp(tctx, b, server_name, &info_ctr, flags, WERR_UNKNOWN_LEVEL),
+                       "failed to test AddPrinterDriverEx level 1");
+       } else {
+               torture_assert(tctx,
+                       test_AddPrinterDriver_exp(tctx, b, server_name, &info_ctr, WERR_UNKNOWN_LEVEL),
+                       "failed to test AddPrinterDriver level 1");
+       }
+
+       info1.driver_name = r->driver_name;
+
+       if (ex) {
+               torture_assert(tctx,
+                       test_AddPrinterDriverEx_exp(tctx, b, server_name, &info_ctr, flags, WERR_UNKNOWN_LEVEL),
+                       "failed to test AddPrinterDriverEx level 1");
+       } else {
+               torture_assert(tctx,
+                       test_AddPrinterDriver_exp(tctx, b, server_name, &info_ctr, WERR_UNKNOWN_LEVEL),
+                       "failed to test AddPrinterDriver level 1");
+       }
+
+       return true;
+}
+
+static bool test_AddPrinterDriver_args_level_2(struct torture_context *tctx,
+                                              struct dcerpc_binding_handle *b,
+                                              const char *server_name,
+                                              struct spoolss_AddDriverInfo8 *r,
+                                              uint32_t flags,
+                                              bool ex)
+{
+       struct spoolss_AddDriverInfoCtr info_ctr;
+       struct spoolss_AddDriverInfo2 info2;
+
+       ZERO_STRUCT(info2);
+
+       info_ctr.level = 2;
+       info_ctr.info.info2 = &info2;
+
+       if (ex) {
+               torture_assert(tctx,
+                       test_AddPrinterDriverEx_exp(tctx, b, server_name, &info_ctr, flags, WERR_INVALID_PARAM),
+                       "failed to test AddPrinterDriverEx level 2");
+       } else {
+               torture_assert(tctx,
+                       test_AddPrinterDriver_exp(tctx, b, server_name, &info_ctr, WERR_INVALID_PARAM),
+                       "failed to test AddPrinterDriver level 2");
+       }
+
+       info2.driver_name = r->driver_name;
+
+       if (ex) {
+               torture_assert(tctx,
+                       test_AddPrinterDriverEx_exp(tctx, b, server_name, &info_ctr, flags, WERR_INVALID_PARAM),
+                       "failed to test AddPrinterDriverEx level 2");
+       } else {
+               torture_assert(tctx,
+                       test_AddPrinterDriver_exp(tctx, b, server_name, &info_ctr, WERR_INVALID_PARAM),
+                       "failed to test AddPrinterDriver level 2");
+       }
+
+       info2.version = r->version;
+
+       if (ex) {
+               torture_assert(tctx,
+                       test_AddPrinterDriverEx_exp(tctx, b, server_name, &info_ctr, flags, WERR_INVALID_PARAM),
+                       "failed to test AddPrinterDriverEx level 2");
+       } else {
+               torture_assert(tctx,
+                       test_AddPrinterDriver_exp(tctx, b, server_name, &info_ctr, WERR_INVALID_PARAM),
+                       "failed to test AddPrinterDriver level 2");
+       }
+
+       info2.architecture = r->architecture;
+
+       if (ex) {
+               torture_assert(tctx,
+                       test_AddPrinterDriverEx_exp(tctx, b, server_name, &info_ctr, flags, WERR_INVALID_PARAM),
+                       "failed to test AddPrinterDriverEx level 2");
+       } else {
+               torture_assert(tctx,
+                       test_AddPrinterDriver_exp(tctx, b, server_name, &info_ctr, WERR_INVALID_PARAM),
+                       "failed to test AddPrinterDriver level 2");
+       }
+
+       info2.driver_path = r->driver_path;
+
+       if (ex) {
+               torture_assert(tctx,
+                       test_AddPrinterDriverEx_exp(tctx, b, server_name, &info_ctr, flags, WERR_INVALID_PARAM),
+                       "failed to test AddPrinterDriverEx level 2");
+       } else {
+               torture_assert(tctx,
+                       test_AddPrinterDriver_exp(tctx, b, server_name, &info_ctr, WERR_INVALID_PARAM),
+                       "failed to test AddPrinterDriver level 2");
+       }
+
+       info2.data_file = r->data_file;
+
+       if (ex) {
+               torture_assert(tctx,
+                       test_AddPrinterDriverEx_exp(tctx, b, server_name, &info_ctr, flags, WERR_INVALID_PARAM),
+                       "failed to test AddPrinterDriverEx level 2");
+       } else {
+               torture_assert(tctx,
+                       test_AddPrinterDriver_exp(tctx, b, server_name, &info_ctr, WERR_INVALID_PARAM),
+                       "failed to test AddPrinterDriver level 2");
+       }
+
+       info2.config_file = r->config_file;
+
+       if (ex) {
+               torture_assert(tctx,
+                       test_AddPrinterDriverEx_exp(tctx, b, server_name, &info_ctr, 0, WERR_INVALID_PARAM),
+                       "failed to test AddPrinterDriverEx");
+       }
+
+       if (ex) {
+               torture_assert(tctx,
+                       test_AddPrinterDriverEx_exp(tctx, b, server_name, &info_ctr, flags, WERR_OK),
+                       "failed to test AddPrinterDriverEx level 2");
+       } else {
+               torture_assert(tctx,
+                       test_AddPrinterDriver_exp(tctx, b, server_name, &info_ctr, WERR_OK),
+                       "failed to test AddPrinterDriver level 2");
+       }
+
+       torture_assert(tctx,
+               test_EnumPrinterDrivers_findone(tctx, b, server_name, r->architecture, 2, r->driver_name),
+               "failed to find added printer driver");
+
+       return true;
+}
+
+static bool test_AddPrinterDriver_args_level_3(struct torture_context *tctx,
+                                              struct dcerpc_binding_handle *b,
+                                              const char *server_name,
+                                              struct spoolss_AddDriverInfo8 *r,
+                                              uint32_t flags,
+                                              bool ex)
+{
+       struct spoolss_AddDriverInfoCtr info_ctr;
+       struct spoolss_AddDriverInfo3 info3;
+
+       ZERO_STRUCT(info3);
+
+       info3.driver_name       = r->driver_name;
+       info3.version           = r->version;
+       info3.architecture      = r->architecture;
+       info3.driver_path       = r->driver_path;
+       info3.data_file         = r->data_file;
+       info3.config_file       = r->config_file;
+
+       info_ctr.level = 3;
+       info_ctr.info.info3 = &info3;
+
+       if (ex) {
+               torture_assert(tctx,
+                       test_AddPrinterDriverEx_exp(tctx, b, server_name, &info_ctr, flags, WERR_OK),
+                       "failed to test AddPrinterDriverEx level 3");
+       } else {
+               torture_assert(tctx,
+                       test_AddPrinterDriver_exp(tctx, b, server_name, &info_ctr, WERR_OK),
+                       "failed to test AddPrinterDriver level 3");
+       }
+
+       torture_assert(tctx,
+               test_EnumPrinterDrivers_findone(tctx, b, server_name, r->architecture, 3, r->driver_name),
+               "failed to find added printer driver");
+
+       return true;
+}
+
+static bool test_AddPrinterDriver_args_level_4(struct torture_context *tctx,
+                                              struct dcerpc_binding_handle *b,
+                                              const char *server_name,
+                                              struct spoolss_AddDriverInfo8 *r,
+                                              uint32_t flags,
+                                              bool ex)
+{
+       struct spoolss_AddDriverInfoCtr info_ctr;
+       struct spoolss_AddDriverInfo4 info4;
+
+       ZERO_STRUCT(info4);
+
+       info4.driver_name       = r->driver_name;
+       info4.version           = r->version;
+       info4.architecture      = r->architecture;
+       info4.driver_path       = r->driver_path;
+       info4.data_file         = r->data_file;
+       info4.config_file       = r->config_file;
+
+       info_ctr.level = 4;
+       info_ctr.info.info4 = &info4;
+
+       if (ex) {
+               torture_assert(tctx,
+                       test_AddPrinterDriverEx_exp(tctx, b, server_name, &info_ctr, flags, WERR_OK),
+                       "failed to test AddPrinterDriverEx level 4");
+       } else {
+               torture_assert(tctx,
+                       test_AddPrinterDriver_exp(tctx, b, server_name, &info_ctr, WERR_OK),
+                       "failed to test AddPrinterDriver level 4");
+       }
+
+       torture_assert(tctx,
+               test_EnumPrinterDrivers_findone(tctx, b, server_name, r->architecture, 4, r->driver_name),
+               "failed to find added printer driver");
+
+       return true;
+}
+
+static bool test_AddPrinterDriver_args_level_6(struct torture_context *tctx,
+                                              struct dcerpc_binding_handle *b,
+                                              const char *server_name,
+                                              struct spoolss_AddDriverInfo8 *r,
+                                              uint32_t flags,
+                                              bool ex)
+{
+       struct spoolss_AddDriverInfoCtr info_ctr;
+       struct spoolss_AddDriverInfo6 info6;
+
+       ZERO_STRUCT(info6);
+
+       info6.driver_name       = r->driver_name;
+       info6.version           = r->version;
+       info6.architecture      = r->architecture;
+       info6.driver_path       = r->driver_path;
+       info6.data_file         = r->data_file;
+       info6.config_file       = r->config_file;
+
+       info_ctr.level = 6;
+       info_ctr.info.info6 = &info6;
+
+       if (ex) {
+               torture_assert(tctx,
+                       test_AddPrinterDriverEx_exp(tctx, b, server_name, &info_ctr, flags, WERR_OK),
+                       "failed to test AddPrinterDriverEx level 6");
+       } else {
+               torture_assert(tctx,
+                       test_AddPrinterDriver_exp(tctx, b, server_name, &info_ctr, WERR_UNKNOWN_LEVEL),
+                       "failed to test AddPrinterDriver level 6");
+       }
+
+       /* spoolss_AddPrinterDriver does not deal with level 6 or 8 - gd */
+
+       if (!ex) {
+               return true;
+       }
+
+       torture_assert(tctx,
+               test_EnumPrinterDrivers_findone(tctx, b, server_name, r->architecture, 6, r->driver_name),
+               "failed to find added printer driver");
+
+       return true;
+}
+
+static bool test_AddPrinterDriver_args_level_8(struct torture_context *tctx,
+                                              struct dcerpc_binding_handle *b,
+                                              const char *server_name,
+                                              struct spoolss_AddDriverInfo8 *r,
+                                              uint32_t flags,
+                                              bool ex)
+{
+       struct spoolss_AddDriverInfoCtr info_ctr;
+       struct spoolss_AddDriverInfo8 info8;
+
+       ZERO_STRUCT(info8);
+
+       info8.driver_name       = r->driver_name;
+       info8.version           = r->version;
+       info8.architecture      = r->architecture;
+       info8.driver_path       = r->driver_path;
+       info8.data_file         = r->data_file;
+       info8.config_file       = r->config_file;
+
+       info_ctr.level = 8;
+       info_ctr.info.info8 = &info8;
+
+       if (ex) {
+               torture_assert(tctx,
+                       test_AddPrinterDriverEx_exp(tctx, b, server_name, &info_ctr, flags, WERR_OK),
+                       "failed to test AddPrinterDriverEx level 8");
+       } else {
+               torture_assert(tctx,
+                       test_AddPrinterDriver_exp(tctx, b, server_name, &info_ctr, WERR_UNKNOWN_LEVEL),
+                       "failed to test AddPrinterDriver level 8");
+       }
+
+       /* spoolss_AddPrinterDriver does not deal with level 6 or 8 - gd */
+
+       if (!ex) {
+               return true;
+       }
+
+       torture_assert(tctx,
+               test_EnumPrinterDrivers_findone(tctx, b, server_name, r->architecture, 8, r->driver_name),
+               "failed to find added printer driver");
+
+       return true;
+}
+
+static bool test_DeletePrinterDriver_exp(struct torture_context *tctx,
+                                        struct dcerpc_binding_handle *b,
+                                        const char *driver,
+                                        const char *environment,
+                                        WERROR expected_result)
+{
+       struct spoolss_DeletePrinterDriver r;
+
+       r.in.server = NULL;
+       r.in.architecture = environment;
+       r.in.driver = driver;
+
+       torture_comment(tctx, "Testing DeletePrinterDriver(%s)\n", driver);
+
+       torture_assert_ntstatus_ok(tctx,
+               dcerpc_spoolss_DeletePrinterDriver_r(b, tctx, &r),
+               "DeletePrinterDriver failed");
+       torture_assert_werr_equal(tctx, r.out.result, expected_result,
+               "DeletePrinterDriver failed with unexpected result");
+
+       return true;
+}
+
+static bool test_DeletePrinterDriverEx_exp(struct torture_context *tctx,
+                                          struct dcerpc_binding_handle *b,
+                                          const char *driver,
+                                          const char *environment,
+                                          uint32_t delete_flags,
+                                          uint32_t version,
+                                          WERROR expected_result)
+{
+       struct spoolss_DeletePrinterDriverEx r;
+
+       r.in.server = NULL;
+       r.in.architecture = environment;
+       r.in.driver = driver;
+       r.in.delete_flags = delete_flags;
+       r.in.version = version;
+
+       torture_comment(tctx, "Testing DeletePrinterDriverEx(%s)\n", driver);
+
+       torture_assert_ntstatus_ok(tctx,
+               dcerpc_spoolss_DeletePrinterDriverEx_r(b, tctx, &r),
+               "DeletePrinterDriverEx failed");
+       torture_assert_werr_equal(tctx, r.out.result, expected_result,
+               "DeletePrinterDriverEx failed with unexpected result");
+
+       return true;
+}
+
+static bool test_DeletePrinterDriver(struct torture_context *tctx,
+                                    struct dcerpc_binding_handle *b,
+                                    const char *driver,
+                                    const char *environment)
+{
+       torture_assert(tctx,
+               test_DeletePrinterDriver_exp(tctx, b, driver, "FOOBAR", WERR_INVALID_ENVIRONMENT),
+               "failed to delete driver");
+
+       torture_assert(tctx,
+               test_DeletePrinterDriver_exp(tctx, b, driver, environment, WERR_OK),
+               "failed to delete driver");
+
+       if (test_EnumPrinterDrivers_findone(tctx, b, NULL, environment, 1, driver)) {
+               torture_fail(tctx, "deleted driver still enumerated");
+       }
+
+       torture_assert(tctx,
+               test_DeletePrinterDriver_exp(tctx, b, driver, environment, WERR_UNKNOWN_PRINTER_DRIVER),
+               "2nd delete failed");
+
+       return true;
+}
+
+static bool test_DeletePrinterDriverEx(struct torture_context *tctx,
+                                      struct dcerpc_binding_handle *b,
+                                      const char *driver,
+                                      const char *environment,
+                                      uint32_t delete_flags,
+                                      uint32_t version)
+{
+       torture_assert(tctx,
+               test_DeletePrinterDriverEx_exp(tctx, b, driver, "FOOBAR", delete_flags, version, WERR_INVALID_ENVIRONMENT),
+               "failed to delete driver");
+
+       torture_assert(tctx,
+               test_DeletePrinterDriverEx_exp(tctx, b, driver, environment, delete_flags, version, WERR_OK),
+               "failed to delete driver");
+
+       if (test_EnumPrinterDrivers_findone(tctx, b, NULL, environment, 1, driver)) {
+               torture_fail(tctx, "deleted driver still enumerated");
+       }
+
+       torture_assert(tctx,
+               test_DeletePrinterDriverEx_exp(tctx, b, driver, environment, delete_flags, version, WERR_UNKNOWN_PRINTER_DRIVER),
+               "2nd delete failed");
+
+       return true;
+}
+
+static bool test_PrinterDriver_args(struct torture_context *tctx,
+                                   struct dcerpc_binding_handle *b,
+                                   const char *server_name,
+                                   uint32_t level,
+                                   struct spoolss_AddDriverInfo8 *r,
+                                   uint32_t add_flags,
+                                   uint32_t delete_flags,
+                                   uint32_t delete_version,
+                                   bool ex)
+{
+       bool ret = true;
+
+       switch (level) {
+       case 1:
+               ret = test_AddPrinterDriver_args_level_1(tctx, b, server_name, r, add_flags, ex);
+               break;
+       case 2:
+               ret = test_AddPrinterDriver_args_level_2(tctx, b, server_name, r, add_flags, ex);
+               break;
+       case 3:
+               ret = test_AddPrinterDriver_args_level_3(tctx, b, server_name, r, add_flags, ex);
+               break;
+       case 4:
+               ret = test_AddPrinterDriver_args_level_4(tctx, b, server_name, r, add_flags, ex);
+               break;
+       case 6:
+               ret = test_AddPrinterDriver_args_level_6(tctx, b, server_name, r, add_flags, ex);
+               break;
+       case 8:
+               ret = test_AddPrinterDriver_args_level_8(tctx, b, server_name, r, add_flags, ex);
+               break;
+       default:
+               return false;
+       }
+
+       if (ret == false) {
+               return ret;
+       }
+
+       if (level == 1) {
+               return ret;
+       }
+
+       /* spoolss_AddPrinterDriver does not deal with level 6 or 8 - gd */
+
+       if (!ex && (level == 6 || level == 8)) {
+               return ret;
+       }
+
+       if (ex) {
+               return test_DeletePrinterDriverEx(tctx, b, r->driver_name, r->architecture, delete_flags, r->version);
+       } else {
+               return test_DeletePrinterDriver(tctx, b, r->driver_name, r->architecture);
+       }
+}
+
+static bool fillup_printserver_info(struct torture_context *tctx,
+                                   struct dcerpc_pipe *p,
+                                   struct torture_driver_context *d)
+{
+       struct policy_handle server_handle;
+       struct dcerpc_binding_handle *b = p->binding_handle;
+       const char *server_name_slash = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
+
+       torture_assert(tctx,
+               test_OpenPrinter_server(tctx, p, &server_handle),
+               "failed to open printserver");
+       torture_assert(tctx,
+               test_get_environment(tctx, b, &server_handle, &d->remote.environment),
+               "failed to get environment");
+       torture_assert(tctx,
+               test_ClosePrinter(tctx, b, &server_handle),
+               "failed to close printserver");
+
+       torture_assert(tctx,
+               test_GetPrinterDriverDirectory_getdir(tctx, b, server_name_slash, d->remote.environment, &d->remote.driver_directory),
+               "failed to get driver directory");
+
+       return true;
+}
+
+static bool test_add_driver(struct torture_context *tctx,
+                           struct dcerpc_pipe *p,
+                           void *private_data)
+{
+       struct torture_driver_context *d =
+               (struct torture_driver_context *)talloc_get_type_abort(private_data, struct torture_driver_context);
+       bool ret = true;
+       struct dcerpc_binding_handle *b = p->binding_handle;
+       const char *server_name_slash = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
+       uint32_t levels[] = { 1, 2, 3, 4, 6, 8 };
+       int i;
+       struct spoolss_AddDriverInfo8 info8;
+
+       torture_assert(tctx,
+               fillup_printserver_info(tctx, p, d),
+               "failed to fillup printserver info");
+
+       info8.version           = d->info8.version;
+       info8.driver_name       = TORTURE_DRIVER;
+       info8.architecture      = d->remote.environment;
+       info8.driver_path       = d->info8.driver_path;
+       info8.data_file         = d->info8.data_file;
+       info8.config_file       = d->info8.config_file;
+
+       for (i=0; i < ARRAY_SIZE(levels); i++) {
+
+               torture_comment(tctx,
+                       "Testing PrinterDriver '%s' add & delete level %d\n",
+                               info8.driver_name, levels[i]);
+
+               ret &= test_PrinterDriver_args(tctx, b, server_name_slash, levels[i], &info8, 0, 0, 0, false);
+       }
+
+       info8.driver_path       = talloc_asprintf(tctx, "%s\\%s", d->remote.driver_directory, d->info8.driver_path);
+       info8.data_file         = talloc_asprintf(tctx, "%s\\%s", d->remote.driver_directory, d->info8.data_file);
+       info8.config_file       = talloc_asprintf(tctx, "%s\\%s", d->remote.driver_directory, d->info8.config_file);
+
+       for (i=0; i < ARRAY_SIZE(levels); i++) {
+
+               torture_comment(tctx,
+                       "Testing PrinterDriver '%s' add & delete level %d (full unc paths)\n",
+                               info8.driver_name, levels[i]);
+
+               ret &= test_PrinterDriver_args(tctx, b, server_name_slash, levels[i], &info8, 0, 0, 0, false);
+       }
+
+       return ret;
+}
+
+static bool test_add_driver_ex(struct torture_context *tctx,
+                              struct dcerpc_pipe *p,
+                              void *private_data)
+{
+       struct torture_driver_context *d =
+               (struct torture_driver_context *)talloc_get_type_abort(private_data, struct torture_driver_context);
+       bool ret = true;
+       struct dcerpc_binding_handle *b = p->binding_handle;
+       const char *server_name_slash = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
+       uint32_t levels[] = { 1, 2, 3, 4, 6, 8 };
+       int i;
+       struct spoolss_AddDriverInfo8 info8;
+       uint32_t add_flags = APD_COPY_NEW_FILES;
+       uint32_t delete_flags = 0;
+
+       torture_assert(tctx,
+               fillup_printserver_info(tctx, p, d),
+               "failed to fillup printserver info");
+
+       info8.version           = d->info8.version;
+       info8.driver_name       = TORTURE_DRIVER_EX;
+       info8.architecture      = d->remote.environment;
+       info8.driver_path       = d->info8.driver_path;
+       info8.data_file         = d->info8.data_file;
+       info8.config_file       = d->info8.config_file;
+
+       for (i=0; i < ARRAY_SIZE(levels); i++) {
+
+               torture_comment(tctx,
+                       "Testing PrinterDriverEx '%s' add & delete level %d\n",
+                               info8.driver_name, levels[i]);
+
+               ret &= test_PrinterDriver_args(tctx, b, server_name_slash, levels[i], &info8, add_flags, delete_flags, d->info8.version, true);
+       }
+
+       info8.driver_path       = talloc_asprintf(tctx, "%s\\%s", d->remote.driver_directory, d->info8.driver_path);
+       info8.data_file         = talloc_asprintf(tctx, "%s\\%s", d->remote.driver_directory, d->info8.data_file);
+       info8.config_file       = talloc_asprintf(tctx, "%s\\%s", d->remote.driver_directory, d->info8.config_file);
+
+       for (i=0; i < ARRAY_SIZE(levels); i++) {
+
+               torture_comment(tctx,
+                       "Testing PrinterDriverEx '%s' add & delete level %d (full unc paths)\n",
+                               info8.driver_name, levels[i]);
+
+               ret &= test_PrinterDriver_args(tctx, b, server_name_slash, levels[i], &info8, add_flags, delete_flags, d->info8.version, true);
+       }
+
+       return ret;
+}
+
+struct torture_suite *torture_rpc_spoolss_driver(TALLOC_CTX *mem_ctx)
+{
+       struct torture_suite *suite = torture_suite_create(mem_ctx, "SPOOLSS-DRIVER");
+
+       struct torture_rpc_tcase *tcase = torture_suite_add_rpc_iface_tcase(suite,
+                                                       "driver", &ndr_table_spoolss);
+       struct torture_driver_context *t;
+
+       t = talloc_zero(mem_ctx, struct torture_driver_context);
+
+       t->info8.version        = SPOOLSS_DRIVER_VERSION_200X;
+       t->info8.driver_name    = NULL;
+       t->info8.architecture   = NULL;
+       t->info8.driver_path    = talloc_strdup(t, "pscript5.dll");
+       t->info8.data_file      = talloc_strdup(t, "cups6.ppd");
+       t->info8.config_file    = talloc_strdup(t, "cupsui6.dll");
+
+       torture_rpc_tcase_add_test_ex(tcase, "add_driver", test_add_driver, t);
+       torture_rpc_tcase_add_test_ex(tcase, "add_driver_ex", test_add_driver_ex, t);
+
+       return suite;
+}