s4-smbtorture: only run the cupsaddsmb adobe driver test against s3.
[kai/samba.git] / source4 / torture / rpc / spoolss.c
index a797e2450bbf45bf7fa47bf5a36ac072ef4bf81b..dfd1c7ee33b99dc8c1ef7c2a35a35539533db31b 100644 (file)
@@ -37,6 +37,7 @@
 #include "libcli/resolve/resolve.h"
 #include "lib/cmdline/popt_common.h"
 #include "system/filesys.h"
+#include "torture/ndr/ndr.h"
 
 #define TORTURE_WELLKNOWN_PRINTER      "torture_wkn_printer"
 #define TORTURE_PRINTER                        "torture_printer"
@@ -44,6 +45,9 @@
 #define TORTURE_PRINTER_EX             "torture_printer_ex"
 #define TORTURE_DRIVER                 "torture_driver"
 #define TORTURE_DRIVER_EX              "torture_driver_ex"
+#define TORTURE_DRIVER_ADOBE           "torture_driver_adobe"
+#define TORTURE_DRIVER_EX_ADOBE                "torture_driver_ex_adobe"
+#define TORTURE_DRIVER_ADOBE_CUPSADDSMB        "torture_driver_adobe_cupsaddsmb"
 
 #define TOP_LEVEL_PRINT_KEY "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Print"
 #define TOP_LEVEL_PRINT_PRINTERS_KEY TOP_LEVEL_PRINT_KEY "\\Printers"
@@ -819,7 +823,8 @@ static bool test_EnumPrintProcessors_level(struct torture_context *tctx,
                                           const char *environment,
                                           uint32_t level,
                                           uint32_t *count_p,
-                                          union spoolss_PrintProcessorInfo **info_p)
+                                          union spoolss_PrintProcessorInfo **info_p,
+                                          WERROR expected_result)
 {
        struct spoolss_EnumPrintProcessors r;
        DATA_BLOB blob;
@@ -836,7 +841,8 @@ static bool test_EnumPrintProcessors_level(struct torture_context *tctx,
        r.out.count = &count;
        r.out.info = &info;
 
-       torture_comment(tctx, "Testing EnumPrintProcessors level %u\n", r.in.level);
+       torture_comment(tctx, "Testing EnumPrintProcessors(%s) level %u\n",
+               r.in.environment, r.in.level);
 
        torture_assert_ntstatus_ok(tctx,
                dcerpc_spoolss_EnumPrintProcessors_r(b, tctx, &r),
@@ -849,7 +855,7 @@ static bool test_EnumPrintProcessors_level(struct torture_context *tctx,
                        dcerpc_spoolss_EnumPrintProcessors_r(b, tctx, &r),
                        "EnumPrintProcessors failed");
        }
-       torture_assert_werr_ok(tctx, r.out.result,
+       torture_assert_werr_equal(tctx, r.out.result, expected_result,
                "EnumPrintProcessors failed");
 
        CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumPrintProcessors, info, level, count, needed, 4);
@@ -870,44 +876,76 @@ static bool test_EnumPrintProcessors(struct torture_context *tctx,
        struct test_spoolss_context *ctx =
                talloc_get_type_abort(private_data, struct test_spoolss_context);
 
-       uint16_t levels[] = { 1 };
-       int i, j;
+       uint16_t levels[] = {0, 1, 2, 3, 32, 256 };
+       uint16_t     ok[] = {0, 1, 0, 0, 0, 0 };
+       int i;
        struct dcerpc_pipe *p = ctx->spoolss_pipe;
        struct dcerpc_binding_handle *b = p->binding_handle;
 
+       torture_assert(tctx,
+               test_EnumPrintProcessors_level(tctx, b, "phantasy", 1, NULL, NULL, WERR_INVALID_ENVIRONMENT),
+               "test_EnumPrintProcessors_level failed");
+
        for (i=0;i<ARRAY_SIZE(levels);i++) {
-               int level = levels[i];
                union spoolss_PrintProcessorInfo *info;
                uint32_t count;
+               WERROR expected_result = ok[i] ? WERR_OK : WERR_INVALID_LEVEL;
 
                torture_assert(tctx,
-                       test_EnumPrintProcessors_level(tctx, b, ctx->environment, level, &count, &info),
+                       test_EnumPrintProcessors_level(tctx, b, ctx->environment, levels[i], &count, &info, expected_result),
                        "test_EnumPrintProcessors_level failed");
-
-               ctx->print_processor_count[level]       = count;
-               ctx->print_processors[level]            = info;
        }
 
-       for (i=1;i<ARRAY_SIZE(levels);i++) {
-               int level = levels[i];
-               int old_level = levels[i-1];
-               torture_assert_int_equal(tctx, ctx->print_processor_count[level], ctx->print_processor_count[old_level],
-                       "EnumPrintProcessors failed");
+       return true;
+}
+
+static bool test_EnumPrintProcDataTypes_level(struct torture_context *tctx,
+                                             struct dcerpc_binding_handle *b,
+                                             const char *print_processor_name,
+                                             uint32_t level,
+                                             uint32_t *count_p,
+                                             union spoolss_PrintProcDataTypesInfo **info_p,
+                                             WERROR expected_result)
+{
+       struct spoolss_EnumPrintProcDataTypes r;
+       DATA_BLOB blob;
+       uint32_t needed;
+       uint32_t count;
+       union spoolss_PrintProcDataTypesInfo *info;
+
+       r.in.servername = "";
+       r.in.print_processor_name = print_processor_name;
+       r.in.level = level;
+       r.in.buffer = NULL;
+       r.in.offered = 0;
+       r.out.needed = &needed;
+       r.out.count = &count;
+       r.out.info = &info;
+
+       torture_comment(tctx, "Testing EnumPrintProcDataTypes(%s) level %u\n",
+               r.in.print_processor_name, r.in.level);
+
+       torture_assert_ntstatus_ok(tctx,
+               dcerpc_spoolss_EnumPrintProcDataTypes_r(b, tctx, &r),
+               "EnumPrintProcDataTypes failed");
+       if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
+               blob = data_blob_talloc_zero(tctx, needed);
+               r.in.buffer = &blob;
+               r.in.offered = needed;
+               torture_assert_ntstatus_ok(tctx,
+                       dcerpc_spoolss_EnumPrintProcDataTypes_r(b, tctx, &r),
+                       "EnumPrintProcDataTypes failed");
        }
+       torture_assert_werr_equal(tctx, r.out.result, expected_result,
+               "EnumPrintProcDataTypes failed");
 
-       for (i=0;i<ARRAY_SIZE(levels);i++) {
-               int level = levels[i];
-               for (j=0;j<ctx->print_processor_count[level];j++) {
-#if 0
-                       union spoolss_PrintProcessorInfo *cur = &ctx->print_processors[level][j];
-                       union spoolss_PrintProcessorInfo *ref = &ctx->print_processors[1][j];
-#endif
-                       switch (level) {
-                       case 1:
-                               /* level 1 is our reference, and it makes no sense to compare it to itself */
-                               break;
-                       }
-               }
+       CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumPrintProcDataTypes, info, level, count, needed, 4);
+
+       if (count_p) {
+               *count_p = count;
+       }
+       if (info_p) {
+               *info_p = info;
        }
 
        return true;
@@ -919,57 +957,50 @@ static bool test_EnumPrintProcDataTypes(struct torture_context *tctx,
        struct test_spoolss_context *ctx =
                talloc_get_type_abort(private_data, struct test_spoolss_context);
 
-       NTSTATUS status;
-       struct spoolss_EnumPrintProcDataTypes r;
-       uint16_t levels[] = { 1 };
+       uint16_t levels[] = {0, 1, 2, 3, 32, 256 };
+       uint16_t     ok[] = {0, 1, 0, 0, 0, 0 };
        int i;
        struct dcerpc_pipe *p = ctx->spoolss_pipe;
        struct dcerpc_binding_handle *b = p->binding_handle;
 
+       torture_assert(tctx,
+               test_EnumPrintProcDataTypes_level(tctx, b, NULL, 1, NULL, NULL, WERR_UNKNOWN_PRINTPROCESSOR),
+               "test_EnumPrintProcDataTypes_level failed");
+
+       torture_assert(tctx,
+               test_EnumPrintProcDataTypes_level(tctx, b, "nonexisting", 1, NULL, NULL, WERR_UNKNOWN_PRINTPROCESSOR),
+               "test_EnumPrintProcDataTypes_level failed");
+
        for (i=0;i<ARRAY_SIZE(levels);i++) {
                int level = levels[i];
-               DATA_BLOB blob;
-               uint32_t needed;
                uint32_t count;
                union spoolss_PrintProcDataTypesInfo *info;
+               WERROR expected_result = ok[i] ? WERR_OK : WERR_INVALID_LEVEL;
 
-               r.in.servername = "";
-               r.in.print_processor_name = "winprint";
-               r.in.level = level;
-               r.in.buffer = NULL;
-               r.in.offered = 0;
-               r.out.needed = &needed;
-               r.out.count = &count;
-               r.out.info = &info;
-
-               torture_comment(tctx, "Testing EnumPrintProcDataTypes level %u\n", r.in.level);
-
-               status = dcerpc_spoolss_EnumPrintProcDataTypes_r(b, tctx, &r);
-               torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EnumPrintProcDataType failed");
-               if (W_ERROR_IS_OK(r.out.result)) {
-                       /* TODO: do some more checks here */
-                       continue;
-               }
-               torture_assert_werr_equal(tctx, r.out.result, WERR_INSUFFICIENT_BUFFER,
-                       "EnumPrintProcDataTypes unexpected return code");
-
-               blob = data_blob_talloc_zero(tctx, needed);
-               r.in.buffer = &blob;
-               r.in.offered = needed;
-
-               status = dcerpc_spoolss_EnumPrintProcDataTypes_r(b, tctx, &r);
-               torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EnumPrintProcDataTypes failed");
+               torture_assert(tctx,
+                       test_EnumPrintProcDataTypes_level(tctx, b, "winprint", level, &count, &info, expected_result),
+                       "test_EnumPrintProcDataTypes_level failed");
+       }
 
-               torture_assert_werr_ok(tctx, r.out.result, "EnumPrintProcDataTypes failed");
+       {
+               union spoolss_PrintProcessorInfo *info;
+               uint32_t count;
 
-               CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumPrintProcDataTypes, info, r.in.level, count, needed, 4);
+               torture_assert(tctx,
+                       test_EnumPrintProcessors_level(tctx, b, ctx->environment, 1, &count, &info, WERR_OK),
+                       "test_EnumPrintProcessors_level failed");
 
+               for (i=0; i < count; i++) {
+                       torture_assert(tctx,
+                               test_EnumPrintProcDataTypes_level(tctx, b, info[i].info1.print_processor_name, 1, NULL, NULL, WERR_OK),
+                               "test_EnumPrintProcDataTypes_level failed");
+               }
        }
 
+
        return true;
 }
 
-
 static bool test_EnumPrinters(struct torture_context *tctx,
                              void *private_data)
 {
@@ -1767,16 +1798,6 @@ static bool test_PrinterInfo(struct torture_context *tctx,
        return ret;
 }
 
-#define torture_assert_sid_equal(torture_ctx,got,expected,cmt)\
-       do { struct dom_sid *__got = (got), *__expected = (expected); \
-       if (!dom_sid_equal(__got, __expected)) { \
-               torture_result(torture_ctx, TORTURE_FAIL, \
-                                          __location__": "#got" was %s, expected %s: %s", \
-                                          dom_sid_string(torture_ctx, __got), dom_sid_string(torture_ctx, __expected), cmt); \
-               return false; \
-       } \
-       } while(0)
-
 static bool test_security_descriptor_equal(struct torture_context *tctx,
                                           const struct security_descriptor *sd1,
                                           const struct security_descriptor *sd2)
@@ -2690,21 +2711,31 @@ static bool test_Forms_args(struct torture_context *tctx,
 
        if (winreg_handle && hive_handle && W_ERROR_IS_OK(expected_add_result)) {
 
+               struct spoolss_FormInfo1 i1;
+
                torture_assert(tctx,
                        test_GetForm_winreg(tctx, winreg_handle, hive_handle, TOP_LEVEL_CONTROL_FORMS_KEY, form_name, &w_type, &w_size, &w_length, &w_data),
                        "failed to get form via winreg");
 
+               i1.size.width   = IVAL(w_data, 0);
+               i1.size.height  = IVAL(w_data, 4);
+               i1.area.left    = IVAL(w_data, 8);
+               i1.area.top     = IVAL(w_data, 12);
+               i1.area.right   = IVAL(w_data, 16);
+               i1.area.bottom  = IVAL(w_data, 20);
+               /* skip index here */
+               i1.flags        = IVAL(w_data, 28);
+
                torture_assert_int_equal(tctx, w_type, REG_BINARY, "unexpected type");
                torture_assert_int_equal(tctx, w_size, 0x20, "unexpected size");
                torture_assert_int_equal(tctx, w_length, 0x20, "unexpected length");
-               torture_assert_mem_equal(tctx, &w_data[0], &add_info.info1->size.width, 4, "width mismatch");
-               torture_assert_mem_equal(tctx, &w_data[4], &add_info.info1->size.height, 4, "height mismatch");
-               torture_assert_mem_equal(tctx, &w_data[8], &add_info.info1->area.left, 4, "left mismatch");
-               torture_assert_mem_equal(tctx, &w_data[12], &add_info.info1->area.top, 4, "top mismatch");
-               torture_assert_mem_equal(tctx, &w_data[16], &add_info.info1->area.right, 4, "right mismatch");
-               torture_assert_mem_equal(tctx, &w_data[20], &add_info.info1->area.bottom, 4, "bottom mismatch");
-               /* skip index here */
-               torture_assert_mem_equal(tctx, &w_data[28], &add_info.info1->flags, 4, "flags mismatch");
+               torture_assert_int_equal(tctx, i1.size.width, add_info.info1->size.width, "width mismatch");
+               torture_assert_int_equal(tctx, i1.size.height, add_info.info1->size.height, "height mismatch");
+               torture_assert_int_equal(tctx, i1.area.left, add_info.info1->area.left, "left mismatch");
+               torture_assert_int_equal(tctx, i1.area.top, add_info.info1->area.top, "top mismatch");
+               torture_assert_int_equal(tctx, i1.area.right, add_info.info1->area.right, "right mismatch");
+               torture_assert_int_equal(tctx, i1.area.bottom, add_info.info1->area.bottom, "bottom mismatch");
+               torture_assert_int_equal(tctx, i1.flags, add_info.info1->flags, "flags mismatch");
        }
 
        if (!print_server && W_ERROR_IS_OK(expected_add_result)) {
@@ -2721,14 +2752,25 @@ static bool test_Forms_args(struct torture_context *tctx,
                torture_assert_int_equal(tctx, info.info1.flags, add_info.info1->flags, "flags mismatch");
 
                if (winreg_handle && hive_handle) {
-                       torture_assert_mem_equal(tctx, &w_data[0], &info.info1.size.width, 4, "width mismatch");
-                       torture_assert_mem_equal(tctx, &w_data[4], &info.info1.size.height, 4, "height mismatch");
-                       torture_assert_mem_equal(tctx, &w_data[8], &info.info1.area.left, 4, "left mismatch");
-                       torture_assert_mem_equal(tctx, &w_data[12], &info.info1.area.top, 4, "top mismatch");
-                       torture_assert_mem_equal(tctx, &w_data[16], &info.info1.area.right, 4, "right mismatch");
-                       torture_assert_mem_equal(tctx, &w_data[20], &info.info1.area.bottom, 4, "bottom mismatch");
+
+                       struct spoolss_FormInfo1 i1;
+
+                       i1.size.width   = IVAL(w_data, 0);
+                       i1.size.height  = IVAL(w_data, 4);
+                       i1.area.left    = IVAL(w_data, 8);
+                       i1.area.top     = IVAL(w_data, 12);
+                       i1.area.right   = IVAL(w_data, 16);
+                       i1.area.bottom  = IVAL(w_data, 20);
                        /* skip index here */
-                       torture_assert_mem_equal(tctx, &w_data[28], &info.info1.flags, 4, "flags mismatch");
+                       i1.flags        = IVAL(w_data, 28);
+
+                       torture_assert_int_equal(tctx, i1.size.width, info.info1.size.width, "width mismatch");
+                       torture_assert_int_equal(tctx, i1.size.height, info.info1.size.height, "height mismatch");
+                       torture_assert_int_equal(tctx, i1.area.left, info.info1.area.left, "left mismatch");
+                       torture_assert_int_equal(tctx, i1.area.top, info.info1.area.top, "top mismatch");
+                       torture_assert_int_equal(tctx, i1.area.right, info.info1.area.right, "right mismatch");
+                       torture_assert_int_equal(tctx, i1.area.bottom, info.info1.area.bottom, "bottom mismatch");
+                       torture_assert_int_equal(tctx, i1.flags, info.info1.flags, "flags mismatch");
                }
 
                add_info.info1->size.width = 1234;
@@ -3295,8 +3337,8 @@ static bool test_DoPrintTest_check_jobs(struct torture_context *tctx,
 
                if (strequal(ginfo.info1.document_name, document_name)) {
                        torture_warning(tctx,
-                               talloc_asprintf(tctx, "document_name did *NOT* change from '%s' to '%s'\n",
-                                       document_name, new_document_name));
+                                       "document_name did *NOT* change from '%s' to '%s'\n",
+                                       document_name, new_document_name);
                }
        }
 
@@ -3435,13 +3477,14 @@ static bool test_ResumePrinter(struct torture_context *tctx,
        return true;
 }
 
-static bool test_GetPrinterData(struct torture_context *tctx,
-                               struct dcerpc_binding_handle *b,
-                               struct policy_handle *handle,
-                               const char *value_name,
-                               enum winreg_Type *type_p,
-                               uint8_t **data_p,
-                               uint32_t *needed_p)
+static bool test_GetPrinterData_checktype(struct torture_context *tctx,
+                                         struct dcerpc_binding_handle *b,
+                                         struct policy_handle *handle,
+                                         const char *value_name,
+                                         enum winreg_Type *expected_type,
+                                         enum winreg_Type *type_p,
+                                         uint8_t **data_p,
+                                         uint32_t *needed_p)
 {
        NTSTATUS status;
        struct spoolss_GetPrinterData r;
@@ -3462,6 +3505,9 @@ static bool test_GetPrinterData(struct torture_context *tctx,
        torture_assert_ntstatus_ok(tctx, status, "GetPrinterData failed");
 
        if (W_ERROR_EQUAL(r.out.result, WERR_MORE_DATA)) {
+               if (expected_type) {
+                       torture_assert_int_equal(tctx, type, *expected_type, "unexpected type");
+               }
                r.in.offered = needed;
                r.out.data = talloc_zero_array(tctx, uint8_t, r.in.offered);
                status = dcerpc_spoolss_GetPrinterData_r(b, tctx, &r);
@@ -3488,14 +3534,27 @@ static bool test_GetPrinterData(struct torture_context *tctx,
        return true;
 }
 
-static bool test_GetPrinterDataEx(struct torture_context *tctx,
-                                 struct dcerpc_pipe *p,
-                                 struct policy_handle *handle,
-                                 const char *key_name,
-                                 const char *value_name,
-                                 enum winreg_Type *type_p,
-                                 uint8_t **data_p,
-                                 uint32_t *needed_p)
+static bool test_GetPrinterData(struct torture_context *tctx,
+                               struct dcerpc_binding_handle *b,
+                               struct policy_handle *handle,
+                               const char *value_name,
+                               enum winreg_Type *type_p,
+                               uint8_t **data_p,
+                               uint32_t *needed_p)
+{
+       return test_GetPrinterData_checktype(tctx, b, handle, value_name,
+                                            NULL, type_p, data_p, needed_p);
+}
+
+static bool test_GetPrinterDataEx_checktype(struct torture_context *tctx,
+                                           struct dcerpc_pipe *p,
+                                           struct policy_handle *handle,
+                                           const char *key_name,
+                                           const char *value_name,
+                                           enum winreg_Type *expected_type,
+                                           enum winreg_Type *type_p,
+                                           uint8_t **data_p,
+                                           uint32_t *needed_p)
 {
        NTSTATUS status;
        struct spoolss_GetPrinterDataEx r;
@@ -3524,6 +3583,9 @@ static bool test_GetPrinterDataEx(struct torture_context *tctx,
        }
 
        if (W_ERROR_EQUAL(r.out.result, WERR_MORE_DATA)) {
+               if (expected_type) {
+                       torture_assert_int_equal(tctx, type, *expected_type, "unexpected type");
+               }
                r.in.offered = needed;
                r.out.data = talloc_zero_array(tctx, uint8_t, r.in.offered);
                status = dcerpc_spoolss_GetPrinterDataEx_r(b, tctx, &r);
@@ -3550,6 +3612,19 @@ static bool test_GetPrinterDataEx(struct torture_context *tctx,
        return true;
 }
 
+static bool test_GetPrinterDataEx(struct torture_context *tctx,
+                                 struct dcerpc_pipe *p,
+                                 struct policy_handle *handle,
+                                 const char *key_name,
+                                 const char *value_name,
+                                 enum winreg_Type *type_p,
+                                 uint8_t **data_p,
+                                 uint32_t *needed_p)
+{
+       return test_GetPrinterDataEx_checktype(tctx, p, handle, key_name, value_name,
+                                              NULL, type_p, data_p, needed_p);
+}
+
 static bool test_get_environment(struct torture_context *tctx,
                                 struct dcerpc_binding_handle *b,
                                 struct policy_handle *handle,
@@ -4347,7 +4422,6 @@ do {\
        }\
 } while(0);
 
-
        if (!test_winreg_symbolic_link(tctx, winreg_handle, hive_handle,
                                       TOP_LEVEL_CONTROL_PRINTERS_KEY,
                                       "\\Registry\\Machine\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Print\\Printers"))
@@ -4355,7 +4429,6 @@ do {\
                torture_warning(tctx, "failed to check for winreg symlink");
        }
 
-
        for (i=0; i < ARRAY_SIZE(keys); i++) {
 
                const char *printer_key;
@@ -4414,7 +4487,7 @@ static bool test_PrintProcessors(struct torture_context *tctx,
        torture_comment(tctx, "Testing Print Processor Info and winreg consistency\n");
 
        torture_assert(tctx,
-               test_EnumPrintProcessors_level(tctx, b, environment, 1, &count, &info),
+               test_EnumPrintProcessors_level(tctx, b, environment, 1, &count, &info, WERR_OK),
                "failed to enum print processors level 1");
 
        for (i=0; i < count; i++) {
@@ -4714,7 +4787,7 @@ static bool test_SetPrinterData_matrix(struct torture_context *tctx,
 
        for (i=0; i < ARRAY_SIZE(values); i++) {
 
-               enum winreg_Type type;
+               enum winreg_Type type, expected_type = REG_SZ;
                DATA_BLOB blob;
                uint8_t *data;
                uint32_t needed;
@@ -4727,7 +4800,7 @@ static bool test_SetPrinterData_matrix(struct torture_context *tctx,
                        "SetPrinterData failed");
 
                torture_assert(tctx,
-                       test_GetPrinterData(tctx, b, handle, values[i], &type, &data, &needed),
+                       test_GetPrinterData_checktype(tctx, b, handle, values[i], &expected_type, &type, &data, &needed),
                        "GetPrinterData failed");
 
                torture_assert_int_equal(tctx, type, REG_SZ, "type mismatch");
@@ -4837,16 +4910,6 @@ static bool test_SetPrinterDataEx_keys(struct torture_context *tctx,
                struct spoolss_PrinterEnumValues *einfo;
                uint32_t needed;
 
-               if (torture_setting_bool(tctx, "samba3", false)) {
-                       char *q;
-                       q = strrchr(keys[i], '\\');
-                       if (q) {
-                               torture_skip(tctx,
-                                       talloc_asprintf(tctx, "skipping keyname '%s' including '\\' character against Samba3\n",
-                                               keys[i]));
-                       }
-               }
-
                blob_in = data_blob_talloc(tctx, NULL, 42);
 
                generate_random_buffer(blob_in.data, blob_in.length);
@@ -4946,9 +5009,9 @@ static bool test_SetPrinterDataEx_values(struct torture_context *tctx,
                        char *q;
                        q = strrchr(values[i], ',');
                        if (q) {
-                               torture_skip(tctx,
-                                       talloc_asprintf(tctx, "skipping valuename '%s' including ',' character against Samba3\n",
-                                               values[i]));
+                               torture_comment(tctx, "skipping valuename '%s' including ',' character against Samba3\n",
+                                               values[i]);
+                               continue;
                        }
                }
 
@@ -5030,13 +5093,6 @@ static bool test_SetPrinterDataEx_matrix(struct torture_context *tctx,
                        s = 0xffff;
                }
 
-               if (torture_setting_bool(tctx, "samba3", false)) {
-                       if ((types[t] == REG_MULTI_SZ) && s == 0) {
-                               torture_warning(tctx, "samba3 does not handle 4 byte emtpy REG_MULTI_SZ buffers");
-                               continue;
-                       }
-               }
-
                switch (types[t]) {
                case REG_BINARY:
                        data = blob;
@@ -5067,7 +5123,7 @@ static bool test_SetPrinterDataEx_matrix(struct torture_context *tctx,
                        "failed to call SetPrinterDataEx");
 
                torture_assert(tctx,
-                       test_GetPrinterDataEx(tctx, p, handle, key_name, value_name, &type, &data_out, &needed),
+                       test_GetPrinterDataEx_checktype(tctx, p, handle, key_name, value_name, &types[t], &type, &data_out, &needed),
                        "failed to call GetPrinterDataEx");
 
                torture_assert(tctx,
@@ -5348,7 +5404,7 @@ do {\
                "failed to query Printer level 2");
 
        TEST_SZ("description", info.info2.comment);
-/*     TEST_SZ("driverName", info.info2.drivername); */
+       TEST_SZ("driverName", info.info2.drivername);
        TEST_SZ("location", info.info2.location);
 
        pname = strrchr(info.info2.printername, '\\');
@@ -5357,7 +5413,7 @@ do {\
        } else {
                pname++;
        }
-/*     TEST_SZ("printerName", pname); */
+       TEST_SZ("printerName", pname);
        /* TEST_SZ("printSeparatorFile", info.info2.sepfile); */
        /* TEST_SZ("printShareName", info.info2.sharename); */
 
@@ -5673,7 +5729,8 @@ static bool test_OpenPrinter_badname_list(struct torture_context *tctx,
 static bool test_OpenPrinter(struct torture_context *tctx,
                             struct dcerpc_pipe *p,
                             const char *name,
-                            const char *environment)
+                            const char *environment,
+                            bool open_only)
 {
        NTSTATUS status;
        struct spoolss_OpenPrinter r;
@@ -5681,7 +5738,7 @@ static bool test_OpenPrinter(struct torture_context *tctx,
        bool ret = true;
        struct dcerpc_binding_handle *b = p->binding_handle;
 
-       r.in.printername        = talloc_asprintf(tctx, "\\\\%s\\%s", dcerpc_server_name(p), name);
+       r.in.printername        = name;
        r.in.datatype           = NULL;
        r.in.devmode_ctr.devmode= NULL;
        r.in.access_mask        = SEC_FLAG_MAXIMUM_ALLOWED;
@@ -5695,6 +5752,10 @@ static bool test_OpenPrinter(struct torture_context *tctx,
 
        torture_assert_werr_ok(tctx, r.out.result, "OpenPrinter failed");
 
+       if (open_only) {
+               goto close_printer;
+       }
+
        if (!test_GetPrinter(tctx, b, &handle, environment)) {
                ret = false;
        }
@@ -5705,6 +5766,7 @@ static bool test_OpenPrinter(struct torture_context *tctx,
                }
        }
 
+ close_printer:
        if (!test_ClosePrinter(tctx, b, &handle)) {
                ret = false;
        }
@@ -5712,32 +5774,49 @@ static bool test_OpenPrinter(struct torture_context *tctx,
        return ret;
 }
 
+static bool test_OpenPrinterEx(struct torture_context *tctx,
+                              struct dcerpc_binding_handle *b,
+                              const char *printername,
+                              const char *datatype,
+                              struct spoolss_DeviceMode *devmode,
+                              uint32_t access_mask,
+                              uint32_t level,
+                              union spoolss_UserLevel *userlevel,
+                              struct policy_handle *handle,
+                              WERROR expected_result)
+{
+       struct spoolss_OpenPrinterEx r;
+
+       r.in.printername        = printername;
+       r.in.datatype           = datatype;
+       r.in.devmode_ctr.devmode= devmode;
+       r.in.access_mask        = access_mask;
+       r.in.level              = level;
+       r.in.userlevel          = *userlevel;
+       r.out.handle            = handle;
+
+       torture_comment(tctx, "Testing OpenPrinterEx(%s)\n", r.in.printername);
+
+       torture_assert_ntstatus_ok(tctx,
+               dcerpc_spoolss_OpenPrinterEx_r(b, tctx, &r),
+               "OpenPrinterEx failed");
+
+       torture_assert_werr_equal(tctx, r.out.result, expected_result,
+               "OpenPrinterEx failed");
+
+       return true;
+}
+
 static bool call_OpenPrinterEx(struct torture_context *tctx,
                               struct dcerpc_pipe *p,
                               const char *name,
                               struct spoolss_DeviceMode *devmode,
                               struct policy_handle *handle)
 {
-       struct spoolss_OpenPrinterEx r;
+       union spoolss_UserLevel userlevel;
        struct spoolss_UserLevel1 userlevel1;
-       NTSTATUS status;
        struct dcerpc_binding_handle *b = p->binding_handle;
 
-       if (name && name[0]) {
-               r.in.printername = talloc_asprintf(tctx, "\\\\%s\\%s",
-                                                  dcerpc_server_name(p), name);
-       } else {
-               r.in.printername = talloc_asprintf(tctx, "\\\\%s",
-                                                  dcerpc_server_name(p));
-       }
-
-       r.in.datatype           = NULL;
-       r.in.devmode_ctr.devmode= devmode;
-       r.in.access_mask        = SEC_FLAG_MAXIMUM_ALLOWED;
-       r.in.level              = 1;
-       r.in.userlevel.level1   = &userlevel1;
-       r.out.handle = handle;
-
        userlevel1.size = 1234;
        userlevel1.client = "hello";
        userlevel1.user = "spottyfoot!";
@@ -5746,15 +5825,14 @@ static bool call_OpenPrinterEx(struct torture_context *tctx,
        userlevel1.minor = 3;
        userlevel1.processor = 4;
 
-       torture_comment(tctx, "Testing OpenPrinterEx(%s)\n", r.in.printername);
-
-       status = dcerpc_spoolss_OpenPrinterEx_r(b, tctx, &r);
-
-       torture_assert_ntstatus_ok(tctx, status, "OpenPrinterEx failed");
-
-       torture_assert_werr_ok(tctx, r.out.result, "OpenPrinterEx failed");
+       userlevel.level1 = &userlevel1;
 
-       return true;
+       return test_OpenPrinterEx(tctx, b, name, NULL, devmode,
+                                 SEC_FLAG_MAXIMUM_ALLOWED,
+                                 1,
+                                 &userlevel,
+                                 handle,
+                                 WERR_OK);
 }
 
 static bool test_printer_rename(struct torture_context *tctx,
@@ -5840,11 +5918,7 @@ static bool test_printer_rename(struct torture_context *tctx,
                test_GetPrinter_level(tctx, b, &new_handle, 2, &info),
                "failed to call GetPrinter level 2");
 
-       /* FIXME: we openend with servername! */
-       printer_name = talloc_asprintf(tctx, "\\\\%s\\%s",
-               dcerpc_server_name(p), printer_name_new);
-
-       torture_assert_str_equal(tctx, info.info2.printername, printer_name,
+       torture_assert_str_equal(tctx, info.info2.printername, printer_name_new,
                "new printer name was not set");
 
        torture_assert(tctx,
@@ -5856,16 +5930,132 @@ static bool test_printer_rename(struct torture_context *tctx,
        return ret;
 }
 
+static bool test_openprinter(struct torture_context *tctx,
+                            struct dcerpc_binding_handle *b,
+                            const char *real_printername)
+{
+       union spoolss_UserLevel userlevel;
+       struct policy_handle handle;
+       struct spoolss_UserLevel1 userlevel1;
+       const char *printername = NULL;
+       int i;
 
-static bool test_OpenPrinterEx(struct torture_context *tctx,
-                              struct dcerpc_pipe *p,
-                              const char *name,
-                              const char *environment)
+       struct {
+               const char *suffix;
+               WERROR expected_result;
+       } tests[] = {
+               {
+                       .suffix                 = "rubbish",
+                       .expected_result        = WERR_INVALID_PRINTER_NAME
+               },{
+                       .suffix                 = ", LocalOnl",
+                       .expected_result        = WERR_INVALID_PRINTER_NAME
+               },{
+                       .suffix                 = ", localOnly",
+                       .expected_result        = WERR_INVALID_PRINTER_NAME
+               },{
+                       .suffix                 = ", localonl",
+                       .expected_result        = WERR_INVALID_PRINTER_NAME
+               },{
+                       .suffix                 = ",LocalOnl",
+                       .expected_result        = WERR_INVALID_PRINTER_NAME
+               },{
+                       .suffix                 = ",localOnl2",
+                       .expected_result        = WERR_INVALID_PRINTER_NAME
+               },{
+                       .suffix                 = ", DrvConver2t",
+                       .expected_result        = WERR_INVALID_PRINTER_NAME
+               },{
+                       .suffix                 = ", drvconvert",
+                       .expected_result        = WERR_INVALID_PRINTER_NAME
+               },{
+                       .suffix                 = ",drvconvert",
+                       .expected_result        = WERR_INVALID_PRINTER_NAME
+               },{
+                       .suffix                 = ", DrvConvert",
+                       .expected_result        = WERR_OK
+               },{
+                       .suffix                 = " , DrvConvert",
+                       .expected_result        = WERR_INVALID_PRINTER_NAME
+               },{
+                       .suffix                 = ",DrvConvert",
+                       .expected_result        = WERR_OK
+               },{
+                       .suffix                 = ", DrvConvertsadfasdf",
+                       .expected_result        = WERR_OK
+               },{
+                       .suffix                 = ",DrvConvertasdfasd",
+                       .expected_result        = WERR_OK
+               },{
+                       .suffix                 = ", LocalOnly",
+                       .expected_result        = WERR_OK
+               },{
+                       .suffix                 = " , LocalOnly",
+                       .expected_result        = WERR_INVALID_PRINTER_NAME
+               },{
+                       .suffix                 = ",LocalOnly",
+                       .expected_result        = WERR_OK
+               },{
+                       .suffix                 = ", LocalOnlysagi4gjfkd",
+                       .expected_result        = WERR_OK
+               },{
+                       .suffix                 = ",LocalOnlysagi4gjfkd",
+                       .expected_result        = WERR_OK
+               }
+       };
+
+       userlevel1.size = 1234;
+       userlevel1.client = "hello";
+       userlevel1.user = "spottyfoot!";
+       userlevel1.build = 1;
+       userlevel1.major = 2;
+       userlevel1.minor = 3;
+       userlevel1.processor = 4;
+
+       userlevel.level1 = &userlevel1;
+
+       torture_comment(tctx, "Testing openprinterex printername pattern\n");
+
+       torture_assert(tctx,
+               test_OpenPrinterEx(tctx, b, real_printername, NULL, NULL, 0, 1,
+                                  &userlevel, &handle,
+                                  WERR_OK),
+               "OpenPrinterEx failed");
+       test_ClosePrinter(tctx, b, &handle);
+
+       for (i=0; i < ARRAY_SIZE(tests); i++) {
+
+               printername = talloc_asprintf(tctx, "%s%s",
+                                             real_printername,
+                                             tests[i].suffix);
+
+               torture_assert(tctx,
+                       test_OpenPrinterEx(tctx, b, printername, NULL, NULL, 0, 1,
+                                          &userlevel, &handle,
+                                          tests[i].expected_result),
+                       "OpenPrinterEx failed");
+               if (W_ERROR_IS_OK(tests[i].expected_result)) {
+                       test_ClosePrinter(tctx, b, &handle);
+               }
+       }
+
+       return true;
+}
+
+
+static bool test_existing_printer_openprinterex(struct torture_context *tctx,
+                                               struct dcerpc_pipe *p,
+                                               const char *name,
+                                               const char *environment)
 {
        struct policy_handle handle;
        bool ret = true;
        struct dcerpc_binding_handle *b = p->binding_handle;
 
+       if (!test_openprinter(tctx, b, name)) {
+               return false;
+       }
+
        if (!call_OpenPrinterEx(tctx, p, name, NULL, &handle)) {
                return false;
        }
@@ -5993,7 +6183,7 @@ static bool test_EnumPrinters_old(struct torture_context *tctx,
                for (j=0;j<count;j++) {
                        if (r.in.level == 1) {
                                char *unc = talloc_strdup(tctx, info[j].info1.name);
-                               char *slash, *name;
+                               char *slash, *name, *full_name;
                                name = unc;
                                if (unc[0] == '\\' && unc[1] == '\\') {
                                        unc +=2;
@@ -6003,10 +6193,18 @@ static bool test_EnumPrinters_old(struct torture_context *tctx,
                                        slash++;
                                        name = slash;
                                }
-                               if (!test_OpenPrinter(tctx, p, name, ctx->environment)) {
+                               full_name = talloc_asprintf(tctx, "\\\\%s\\%s",
+                                                           dcerpc_server_name(p), name);
+                               if (!test_OpenPrinter(tctx, p, name, ctx->environment, true)) {
                                        ret = false;
                                }
-                               if (!test_OpenPrinterEx(tctx, p, name, ctx->environment)) {
+                               if (!test_OpenPrinter(tctx, p, full_name, ctx->environment, true)) {
+                                       ret = false;
+                               }
+                               if (!test_OpenPrinter(tctx, p, name, ctx->environment, false)) {
+                                       ret = false;
+                               }
+                               if (!test_existing_printer_openprinterex(tctx, p, name, ctx->environment)) {
                                        ret = false;
                                }
                        }
@@ -6016,6 +6214,210 @@ static bool test_EnumPrinters_old(struct torture_context *tctx,
        return ret;
 }
 
+static bool test_EnumPrinters_level(struct torture_context *tctx,
+                                   struct dcerpc_binding_handle *b,
+                                   uint32_t flags,
+                                   const char *servername,
+                                   uint32_t level,
+                                   uint32_t *count_p,
+                                   union spoolss_PrinterInfo **info_p)
+{
+       struct spoolss_EnumPrinters r;
+       union spoolss_PrinterInfo *info;
+       uint32_t needed;
+       uint32_t count;
+
+       r.in.flags      = flags;
+       r.in.server     = servername;
+       r.in.level      = level;
+       r.in.buffer     = NULL;
+       r.in.offered    = 0;
+       r.out.needed    = &needed;
+       r.out.count     = &count;
+       r.out.info      = &info;
+
+       torture_comment(tctx, "Testing EnumPrinters(%s) level %u\n",
+               r.in.server, r.in.level);
+
+       torture_assert_ntstatus_ok(tctx,
+               dcerpc_spoolss_EnumPrinters_r(b, tctx, &r),
+               "EnumPrinters failed");
+       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_EnumPrinters_r(b, tctx, &r),
+                       "EnumPrinters failed");
+       }
+
+       torture_assert_werr_ok(tctx, r.out.result, "EnumPrinters failed");
+
+       CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumPrinters, info, r.in.level, count, needed, 4);
+
+       if (count_p) {
+               *count_p = count;
+       }
+       if (info_p) {
+               *info_p = info;
+       }
+
+       return true;
+}
+
+static const char *get_short_printername(struct torture_context *tctx,
+                                        const char *name)
+{
+       const char *short_name;
+
+       if (name[0] == '\\' && name[1] == '\\') {
+               name += 2;
+               short_name = strchr(name, '\\');
+               if (short_name) {
+                       return talloc_strdup(tctx, short_name+1);
+               }
+       }
+
+       return name;
+}
+
+static const char *get_full_printername(struct torture_context *tctx,
+                                       const char *name)
+{
+       const char *full_name = talloc_strdup(tctx, name);
+       char *p;
+
+       if (name && name[0] == '\\' && name[1] == '\\') {
+               name += 2;
+               p = strchr(name, '\\');
+               if (p) {
+                       return full_name;
+               }
+       }
+
+       return NULL;
+}
+
+static bool test_OnePrinter_servername(struct torture_context *tctx,
+                                      struct dcerpc_pipe *p,
+                                      struct dcerpc_binding_handle *b,
+                                      const char *servername,
+                                      const char *printername)
+{
+       union spoolss_PrinterInfo info;
+       const char *short_name = get_short_printername(tctx, printername);
+       const char *full_name = get_full_printername(tctx, printername);
+
+       if (short_name) {
+               struct policy_handle handle;
+               torture_assert(tctx,
+                       call_OpenPrinterEx(tctx, p, short_name, NULL, &handle),
+                       "failed to open printer");
+
+               torture_assert(tctx,
+                       test_GetPrinter_level(tctx, b, &handle, 2, &info),
+                       "failed to get printer info");
+
+               torture_assert_casestr_equal(tctx, info.info2.servername, NULL,
+                       "unexpected servername");
+               torture_assert_casestr_equal(tctx, info.info2.printername, short_name,
+                       "unexpected printername");
+
+               if (info.info2.devmode) {
+                       const char *expected_devicename;
+                       expected_devicename = talloc_strndup(tctx, short_name, MIN(strlen(short_name), 31));
+                       torture_assert_casestr_equal(tctx, info.info2.devmode->devicename, expected_devicename,
+                               "unexpected devicemode devicename");
+               }
+
+               torture_assert(tctx,
+                       test_ClosePrinter(tctx, b, &handle),
+                       "failed to close printer");
+       }
+
+       if (full_name) {
+               struct policy_handle handle;
+
+               torture_assert(tctx,
+                       call_OpenPrinterEx(tctx, p, full_name, NULL, &handle),
+                       "failed to open printer");
+
+               torture_assert(tctx,
+                       test_GetPrinter_level(tctx, b, &handle, 2, &info),
+                       "failed to get printer info");
+
+               torture_assert_casestr_equal(tctx, info.info2.servername, servername,
+                       "unexpected servername");
+               torture_assert_casestr_equal(tctx, info.info2.printername, full_name,
+                       "unexpected printername");
+
+               if (info.info2.devmode) {
+                       const char *expected_devicename;
+                       expected_devicename = talloc_strndup(tctx, full_name, MIN(strlen(full_name), 31));
+                       torture_assert_casestr_equal(tctx, info.info2.devmode->devicename, expected_devicename,
+                               "unexpected devicemode devicename");
+               }
+
+               torture_assert(tctx,
+                       test_ClosePrinter(tctx, b, &handle),
+                       "failed to close printer");
+       }
+
+       return true;
+}
+
+static bool test_EnumPrinters_servername(struct torture_context *tctx,
+                                        void *private_data)
+{
+       struct test_spoolss_context *ctx =
+               talloc_get_type_abort(private_data, struct test_spoolss_context);
+       int i;
+       struct dcerpc_pipe *p = ctx->spoolss_pipe;
+       struct dcerpc_binding_handle *b = p->binding_handle;
+       uint32_t count;
+       union spoolss_PrinterInfo *info;
+       const char *servername;
+       uint32_t flags = PRINTER_ENUM_NAME|PRINTER_ENUM_LOCAL;
+
+       torture_comment(tctx, "Testing servername behaviour in EnumPrinters and GetPrinters\n");
+
+       servername = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
+
+       torture_assert(tctx,
+               test_EnumPrinters_level(tctx, b, flags, servername, 2, &count, &info),
+               "failed to enumerate printers");
+
+       for (i=0; i < count; i++) {
+
+               torture_assert_casestr_equal(tctx, info[i].info2.servername, servername,
+                       "unexpected servername");
+
+               torture_assert(tctx,
+                       test_OnePrinter_servername(tctx, p, b, servername, info[i].info2.printername),
+                       "failed to check printer");
+       }
+
+       servername = "";
+
+       torture_assert(tctx,
+               test_EnumPrinters_level(tctx, b, flags, servername, 2, &count, &info),
+               "failed to enumerate printers");
+
+       for (i=0; i < count; i++) {
+
+               torture_assert_casestr_equal(tctx, info[i].info2.servername, NULL,
+                       "unexpected servername");
+
+               torture_assert(tctx,
+                       test_OnePrinter_servername(tctx, p, b, servername, info[i].info2.printername),
+                       "failed to check printer");
+       }
+
+
+       return true;
+}
+
+
 static bool test_GetPrinterDriver(struct torture_context *tctx,
                                  struct dcerpc_binding_handle *b,
                                  struct policy_handle *handle,
@@ -6643,6 +7045,18 @@ bool test_printer_all_keys(struct torture_context *tctx,
        return true;
 }
 
+static bool test_openprinter_wrap(struct torture_context *tctx,
+                                 void *private_data)
+{
+       struct torture_printer_context *t =
+               (struct torture_printer_context *)talloc_get_type_abort(private_data, struct torture_printer_context);
+       struct dcerpc_pipe *p = t->spoolss_pipe;
+       struct dcerpc_binding_handle *b = p->binding_handle;
+       const char *printername = t->info2.printername;
+
+       return test_openprinter(tctx, b, printername);
+}
+
 static bool test_csetprinter(struct torture_context *tctx,
                             void *private_data)
 {
@@ -7384,6 +7798,7 @@ static bool test_driver_info_winreg(struct torture_context *tctx,
 
 void torture_tcase_printer(struct torture_tcase *tcase)
 {
+       torture_tcase_add_simple_test(tcase, "openprinter", test_openprinter_wrap);
        torture_tcase_add_simple_test(tcase, "csetprinter", test_csetprinter);
        torture_tcase_add_simple_test(tcase, "print_test", test_print_test);
        torture_tcase_add_simple_test(tcase, "print_test_extended", test_print_test_extended);
@@ -7475,6 +7890,7 @@ struct torture_suite *torture_rpc_spoolss(TALLOC_CTX *mem_ctx)
        torture_tcase_add_simple_test(tcase, "enum_printers", test_EnumPrinters);
        torture_tcase_add_simple_test(tcase, "enum_ports_old", test_EnumPorts_old);
        torture_tcase_add_simple_test(tcase, "enum_printers_old", test_EnumPrinters_old);
+       torture_tcase_add_simple_test(tcase, "enum_printers_servername", test_EnumPrinters_servername);
        torture_tcase_add_simple_test(tcase, "enum_printer_drivers_old", test_EnumPrinterDrivers_old);
        torture_tcase_add_simple_test(tcase, "architecture_buffer", test_architecture_buffer);
 
@@ -8186,7 +8602,7 @@ static bool upload_printer_driver_file(struct torture_context *tctx,
        const char *local_name = talloc_asprintf(tctx, "%s/%s", d->local.driver_directory, file_name);
        const char *remote_name = talloc_asprintf(tctx, "%s\\%s", remote_dir, file_name);
 
-       if (!file_name) {
+       if (!file_name || strlen(file_name) == 0) {
                return true;
        }
 
@@ -8251,20 +8667,20 @@ static bool connect_printer_driver_share(struct torture_context *tctx,
        torture_comment(tctx, "Connecting printer driver share '%s' on '%s'\n",
                share_name, server_name);
 
-       lp_smbcli_options(tctx->lp_ctx, &smb_options);
-       lp_smbcli_session_options(tctx->lp_ctx, &smb_session_options);
+       lpcfg_smbcli_options(tctx->lp_ctx, &smb_options);
+       lpcfg_smbcli_session_options(tctx->lp_ctx, &smb_session_options);
 
        torture_assert_ntstatus_ok(tctx,
                smbcli_full_connection(tctx, cli, server_name,
-                                       lp_smb_ports(tctx->lp_ctx),
+                                       lpcfg_smb_ports(tctx->lp_ctx),
                                        share_name, NULL,
-                                       lp_socket_options(tctx->lp_ctx),
+                                       lpcfg_socket_options(tctx->lp_ctx),
                                        cmdline_credentials,
-                                       lp_resolve_context(tctx->lp_ctx),
+                                       lpcfg_resolve_context(tctx->lp_ctx),
                                        tctx->ev,
                                        &smb_options,
                                        &smb_session_options,
-                                       lp_gensec_settings(tctx, tctx->lp_ctx)),
+                                       lpcfg_gensec_settings(tctx, tctx->lp_ctx)),
                "failed to open driver share");
 
        return true;
@@ -8318,7 +8734,7 @@ static bool remove_printer_driver_file(struct torture_context *tctx,
        const char *remote_name;
        const char *remote_dir =  driver_directory_dir(d->remote.driver_directory);
 
-       if (!file_name) {
+       if (!file_name || strlen(file_name) == 0) {
                return true;
        }
 
@@ -8354,9 +8770,11 @@ static bool remove_printer_driver(struct torture_context *tctx,
        torture_assert(tctx,
                remove_printer_driver_file(tctx, cli, d, d->info8.data_file),
                "failed to remove data_file");
-       torture_assert(tctx,
-               remove_printer_driver_file(tctx, cli, d, d->info8.config_file),
-               "failed to remove config_file");
+       if (!strequal(d->info8.config_file, d->info8.driver_path)) {
+               torture_assert(tctx,
+                       remove_printer_driver_file(tctx, cli, d, d->info8.config_file),
+                       "failed to remove config_file");
+       }
        torture_assert(tctx,
                remove_printer_driver_file(tctx, cli, d, d->info8.help_file),
                "failed to remove help_file");
@@ -8440,7 +8858,9 @@ static bool test_add_driver_arg(struct torture_context *tctx,
 
        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);
+       if (d->info8.config_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++) {
 
@@ -8474,60 +8894,143 @@ static bool test_add_driver_arg(struct torture_context *tctx,
 }
 
 static bool test_add_driver_ex_64(struct torture_context *tctx,
-                                 struct dcerpc_pipe *p,
-                                 void *private_data)
+                                 struct dcerpc_pipe *p)
 {
-       struct torture_driver_context *d =
-               (struct torture_driver_context *)talloc_get_type_abort(private_data, struct torture_driver_context);
+       struct torture_driver_context *d;
+
+       d = talloc_zero(tctx, struct torture_driver_context);
 
+       d->info8.version                = SPOOLSS_DRIVER_VERSION_200X;
+       d->info8.driver_name            = TORTURE_DRIVER_EX;
+       d->info8.architecture           = NULL;
+       d->info8.driver_path            = talloc_strdup(d, "pscript5.dll");
+       d->info8.data_file              = talloc_strdup(d, "cups6.ppd");
+       d->info8.config_file            = talloc_strdup(d, "cupsui6.dll");
        d->local.environment            = talloc_strdup(d, "Windows x64");
        d->local.driver_directory       = talloc_strdup(d, "/usr/share/cups/drivers/x64");
-       d->info8.driver_name            = TORTURE_DRIVER_EX;
        d->ex                           = true;
 
        return test_add_driver_arg(tctx, p, d);
 }
 
 static bool test_add_driver_ex_32(struct torture_context *tctx,
-                                 struct dcerpc_pipe *p,
-                                 void *private_data)
+                                 struct dcerpc_pipe *p)
 {
-       struct torture_driver_context *d =
-               (struct torture_driver_context *)talloc_get_type_abort(private_data, struct torture_driver_context);
+       struct torture_driver_context *d;
+
+       d = talloc_zero(tctx, struct torture_driver_context);
 
+       d->info8.version                = SPOOLSS_DRIVER_VERSION_200X;
+       d->info8.driver_name            = TORTURE_DRIVER_EX;
+       d->info8.architecture           = NULL;
+       d->info8.driver_path            = talloc_strdup(d, "pscript5.dll");
+       d->info8.data_file              = talloc_strdup(d, "cups6.ppd");
+       d->info8.config_file            = talloc_strdup(d, "cupsui6.dll");
        d->local.environment            = talloc_strdup(d, "Windows NT x86");
        d->local.driver_directory       = talloc_strdup(d, "/usr/share/cups/drivers/i386");
-       d->info8.driver_name            = TORTURE_DRIVER_EX;
        d->ex                           = true;
 
        return test_add_driver_arg(tctx, p, d);
 }
 
 static bool test_add_driver_64(struct torture_context *tctx,
-                              struct dcerpc_pipe *p,
-                              void *private_data)
+                              struct dcerpc_pipe *p)
 {
-       struct torture_driver_context *d =
-               (struct torture_driver_context *)talloc_get_type_abort(private_data, struct torture_driver_context);
+       struct torture_driver_context *d;
+
+       d = talloc_zero(tctx, struct torture_driver_context);
 
+       d->info8.version                = SPOOLSS_DRIVER_VERSION_200X;
+       d->info8.driver_name            = TORTURE_DRIVER;
+       d->info8.architecture           = NULL;
+       d->info8.driver_path            = talloc_strdup(d, "pscript5.dll");
+       d->info8.data_file              = talloc_strdup(d, "cups6.ppd");
+       d->info8.config_file            = talloc_strdup(d, "cupsui6.dll");
        d->local.environment            = talloc_strdup(d, "Windows x64");
        d->local.driver_directory       = talloc_strdup(d, "/usr/share/cups/drivers/x64");
-       d->info8.driver_name            = TORTURE_DRIVER;
        d->ex                           = false;
 
        return test_add_driver_arg(tctx, p, d);
 }
 
 static bool test_add_driver_32(struct torture_context *tctx,
-                              struct dcerpc_pipe *p,
-                              void *private_data)
+                              struct dcerpc_pipe *p)
 {
-       struct torture_driver_context *d =
-               (struct torture_driver_context *)talloc_get_type_abort(private_data, struct torture_driver_context);
+       struct torture_driver_context *d;
+
+       d = talloc_zero(tctx, struct torture_driver_context);
 
+       d->info8.version                = SPOOLSS_DRIVER_VERSION_200X;
+       d->info8.driver_name            = TORTURE_DRIVER;
+       d->info8.architecture           = NULL;
+       d->info8.driver_path            = talloc_strdup(d, "pscript5.dll");
+       d->info8.data_file              = talloc_strdup(d, "cups6.ppd");
+       d->info8.config_file            = talloc_strdup(d, "cupsui6.dll");
        d->local.environment            = talloc_strdup(d, "Windows NT x86");
        d->local.driver_directory       = talloc_strdup(d, "/usr/share/cups/drivers/i386");
-       d->info8.driver_name            = TORTURE_DRIVER;
+       d->ex                           = false;
+
+       return test_add_driver_arg(tctx, p, d);
+}
+
+static bool test_add_driver_adobe(struct torture_context *tctx,
+                                 struct dcerpc_pipe *p)
+{
+       struct torture_driver_context *d;
+
+       d = talloc_zero(tctx, struct torture_driver_context);
+
+       d->info8.version                = SPOOLSS_DRIVER_VERSION_9X;
+       d->info8.driver_name            = TORTURE_DRIVER_ADOBE;
+       d->info8.architecture           = NULL;
+       d->info8.driver_path            = talloc_strdup(d, "ADOBEPS4.DRV");
+       d->info8.data_file              = talloc_strdup(d, "DEFPRTR2.PPD");
+       d->info8.config_file            = talloc_strdup(d, "ADOBEPS4.DRV");
+#if 0
+       d->info8.help_file              = talloc_strdup(d, "ADOBEPS4.HLP");
+       d->info8.monitor_name           = talloc_strdup(d, "PSMON.DLL");
+#endif
+       d->local.environment            = talloc_strdup(d, "Windows 4.0");
+       d->local.driver_directory       = talloc_strdup(d, "/usr/share/cups/drivers/adobe/");
+       d->ex                           = false;
+
+       return test_add_driver_arg(tctx, p, d);
+}
+
+static bool test_add_driver_adobe_cupsaddsmb(struct torture_context *tctx,
+                                            struct dcerpc_pipe *p)
+{
+       struct torture_driver_context *d;
+       struct spoolss_StringArray *a;
+
+       if (!torture_setting_bool(tctx, "samba3", false)) {
+               torture_skip(tctx, "skipping cupsaddsmb test which only works against samba3");
+       }
+
+       d = talloc_zero(tctx, struct torture_driver_context);
+
+       d->info8.version                = SPOOLSS_DRIVER_VERSION_9X;
+       d->info8.driver_name            = TORTURE_DRIVER_ADOBE_CUPSADDSMB;
+       d->info8.architecture           = NULL;
+       d->info8.driver_path            = talloc_strdup(d, "ADOBEPS4.DRV");
+       d->info8.data_file              = talloc_strdup(d, "DEFPRTR2.PPD");
+       d->info8.config_file            = NULL;
+       d->info8.help_file              = talloc_strdup(d, "ADOBEPS4.HLP");
+       d->info8.monitor_name           = talloc_strdup(d, "PSMON.DLL");
+       d->info8.default_datatype       = talloc_strdup(d, "RAW");
+
+       a                               = talloc_zero(d, struct spoolss_StringArray);
+       a->string                       = talloc_zero_array(a, const char *, 7);
+       a->string[0]                    = talloc_strdup(a->string, "ADOBEPS4.DRV");
+       a->string[1]                    = talloc_strdup(a->string, "DEFPRTR2.PPD");
+       a->string[2]                    = talloc_strdup(a->string, "ADOBEPS4.HLP");
+       a->string[3]                    = talloc_strdup(a->string, "PSMON.DLL");
+       a->string[4]                    = talloc_strdup(a->string, "ADFONTS.MFM");
+       a->string[5]                    = talloc_strdup(a->string, "ICONLIB.DLL");
+
+       d->info8.dependent_files        = a;
+       d->local.environment            = talloc_strdup(d, "Windows 4.0");
+       d->local.driver_directory       = talloc_strdup(d, "/usr/share/cups/drivers/adobe/");
        d->ex                           = false;
 
        return test_add_driver_arg(tctx, p, d);
@@ -8539,22 +9042,15 @@ struct torture_suite *torture_rpc_spoolss_driver(TALLOC_CTX *mem_ctx)
 
        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);
+       torture_rpc_tcase_add_test(tcase, "add_driver_64", test_add_driver_64);
+       torture_rpc_tcase_add_test(tcase, "add_driver_ex_64", test_add_driver_ex_64);
 
-       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(tcase, "add_driver_32", test_add_driver_32);
+       torture_rpc_tcase_add_test(tcase, "add_driver_ex_32", test_add_driver_ex_32);
 
-       torture_rpc_tcase_add_test_ex(tcase, "add_driver_64", test_add_driver_64, t);
-       torture_rpc_tcase_add_test_ex(tcase, "add_driver_ex_64", test_add_driver_ex_64, t);
+       torture_rpc_tcase_add_test(tcase, "add_driver_adobe", test_add_driver_adobe);
 
-       torture_rpc_tcase_add_test_ex(tcase, "add_driver_32", test_add_driver_32, t);
-       torture_rpc_tcase_add_test_ex(tcase, "add_driver_ex_32", test_add_driver_ex_32, t);
+       torture_rpc_tcase_add_test(tcase, "add_driver_adobe_cupsaddsmb", test_add_driver_adobe_cupsaddsmb);
 
        return suite;
 }