From b8e271cb228f7809142ad6433fc92b92510a61b8 Mon Sep 17 00:00:00 2001 From: David Disseldorp Date: Tue, 10 Jan 2012 18:21:42 +0100 Subject: [PATCH 1/7] spoolss: fix DPD_DELETE_ALL_FILES error return If DeletePrinterDriverEx is called with DPD_DELETE_ALL_FILES and files assigned to the to-be-deleted driver overlap with other drivers then an error is returned. Change the error code here to match Windows 2k8r2. Signed-off-by: David Disseldorp Signed-off-by: Andreas Schneider --- source3/rpc_server/spoolss/srv_spoolss_nt.c | 3 +-- 1 files changed, 1 insertions(+), 2 deletions(-) diff --git a/source3/rpc_server/spoolss/srv_spoolss_nt.c b/source3/rpc_server/spoolss/srv_spoolss_nt.c index bfec3cc..2403f32 100644 --- a/source3/rpc_server/spoolss/srv_spoolss_nt.c +++ b/source3/rpc_server/spoolss/srv_spoolss_nt.c @@ -2264,8 +2264,7 @@ WERROR _spoolss_DeletePrinterDriverEx(struct pipes_struct *p, get_session_info_system(), p->msg_ctx, info)) { - /* no idea of the correct error here */ - status = WERR_ACCESS_DENIED; + status = WERR_PRINTER_DRIVER_IN_USE; goto done; } -- 1.7.7 From 55d9bf9087809f36a86aea261d86aec748ff4aac Mon Sep 17 00:00:00 2001 From: David Disseldorp Date: Wed, 11 Jan 2012 19:50:36 +0100 Subject: [PATCH 2/7] s3-spoolss: prefix print$ path on driver file deletion Driver file paths stored in the registry do not include the server path prefix. delete_driver_files() incorrectly assumes such a prefix. https://bugzilla.samba.org/show_bug.cgi?id=8697 --- source3/printing/nt_printing.c | 81 ++++++++++++++++++--------------------- 1 files changed, 37 insertions(+), 44 deletions(-) diff --git a/source3/printing/nt_printing.c b/source3/printing/nt_printing.c index d6b8bb1..b0d4e81 100644 --- a/source3/printing/nt_printing.c +++ b/source3/printing/nt_printing.c @@ -1493,20 +1493,30 @@ bool printer_driver_files_in_use(TALLOC_CTX *mem_ctx, } static NTSTATUS driver_unlink_internals(connection_struct *conn, - const char *name) + const char *short_arch, + int vers, + const char *fname) { + TALLOC_CTX *tmp_ctx = talloc_new(conn); struct smb_filename *smb_fname = NULL; - NTSTATUS status; + char *print_dlr_path; + NTSTATUS status = NT_STATUS_NO_MEMORY; + + print_dlr_path = talloc_asprintf(tmp_ctx, "%s/%d/%s", + short_arch, vers, fname); + if (print_dlr_path == NULL) { + goto err_out; + } - status = create_synthetic_smb_fname(talloc_tos(), name, NULL, NULL, - &smb_fname); + status = create_synthetic_smb_fname(tmp_ctx, print_dlr_path, + NULL, NULL, &smb_fname); if (!NT_STATUS_IS_OK(status)) { - return status; + goto err_out; } status = unlink_internals(conn, NULL, 0, smb_fname, false); - - TALLOC_FREE(smb_fname); +err_out: + talloc_free(tmp_ctx); return status; } @@ -1519,9 +1529,7 @@ static NTSTATUS driver_unlink_internals(connection_struct *conn, bool delete_driver_files(const struct auth_serversupplied_info *session_info, const struct spoolss_DriverInfo8 *r) { - int i = 0; - char *s; - const char *file; + const char *short_arch; connection_struct *conn; NTSTATUS nt_status; char *oldcwd; @@ -1572,55 +1580,40 @@ bool delete_driver_files(const struct auth_serversupplied_info *session_info, goto err_out; } - /* now delete the files; must strip the '\print$' string from - fron of path */ + short_arch = get_short_archi(r->architecture); + if (short_arch == NULL) { + DEBUG(0, ("bad architecture %s\n", r->architecture)); + ret = false; + goto err_out; + } + + /* now delete the files */ if (r->driver_path && r->driver_path[0]) { - if ((s = strchr(&r->driver_path[1], '\\')) != NULL) { - file = s; - DEBUG(10,("deleting driverfile [%s]\n", s)); - driver_unlink_internals(conn, file); - } + DEBUG(10,("deleting driverfile [%s]\n", r->driver_path)); + driver_unlink_internals(conn, short_arch, r->version, r->driver_path); } if (r->config_file && r->config_file[0]) { - if ((s = strchr(&r->config_file[1], '\\')) != NULL) { - file = s; - DEBUG(10,("deleting configfile [%s]\n", s)); - driver_unlink_internals(conn, file); - } + DEBUG(10,("deleting configfile [%s]\n", r->config_file)); + driver_unlink_internals(conn, short_arch, r->version, r->config_file); } if (r->data_file && r->data_file[0]) { - if ((s = strchr(&r->data_file[1], '\\')) != NULL) { - file = s; - DEBUG(10,("deleting datafile [%s]\n", s)); - driver_unlink_internals(conn, file); - } + DEBUG(10,("deleting datafile [%s]\n", r->data_file)); + driver_unlink_internals(conn, short_arch, r->version, r->data_file); } if (r->help_file && r->help_file[0]) { - if ((s = strchr(&r->help_file[1], '\\')) != NULL) { - file = s; - DEBUG(10,("deleting helpfile [%s]\n", s)); - driver_unlink_internals(conn, file); - } + DEBUG(10,("deleting helpfile [%s]\n", r->help_file)); + driver_unlink_internals(conn, short_arch, r->version, r->help_file); } - /* check if we are done removing files */ - if (r->dependent_files) { + int i = 0; while (r->dependent_files[i] && r->dependent_files[i][0]) { - char *p; - - /* bypass the "\print$" portion of the path */ - - if ((p = strchr(r->dependent_files[i]+1, '\\')) != NULL) { - file = p; - DEBUG(10,("deleting dependent file [%s]\n", file)); - driver_unlink_internals(conn, file); - } - + DEBUG(10,("deleting dependent file [%s]\n", r->dependent_files[i])); + driver_unlink_internals(conn, short_arch, r->version, r->dependent_files[i]); i++; } } -- 1.7.7 From 483a7e073cf4e7153e152ffef9dccaa68142bd19 Mon Sep 17 00:00:00 2001 From: David Disseldorp Date: Thu, 12 Jan 2012 16:27:37 +0100 Subject: [PATCH 3/7] s3-spoolss: fix printer driver version deletion Spoolss delete printer driver code currently makes invalid version assumptions based on the architecture requested by the client. Ugly hacks are in place to cover removal of other versions (2 and 3). This change wraps multi version deletion in a simple for loop. --- source3/rpc_server/spoolss/srv_spoolss_nt.c | 302 +++++++++++--------------- 1 files changed, 128 insertions(+), 174 deletions(-) diff --git a/source3/rpc_server/spoolss/srv_spoolss_nt.c b/source3/rpc_server/spoolss/srv_spoolss_nt.c index 2403f32..8e4ddc0 100644 --- a/source3/rpc_server/spoolss/srv_spoolss_nt.c +++ b/source3/rpc_server/spoolss/srv_spoolss_nt.c @@ -2042,6 +2042,12 @@ static const struct print_architecture_table_node archi_table[]= { {NULL, "", -1 } }; +static const int drv_cversion[] = {SPOOLSS_DRIVER_VERSION_9X, + SPOOLSS_DRIVER_VERSION_NT35, + SPOOLSS_DRIVER_VERSION_NT4, + SPOOLSS_DRIVER_VERSION_200X, + -1}; + static int get_version_id(const char *arch) { int i; @@ -2064,10 +2070,12 @@ WERROR _spoolss_DeletePrinterDriver(struct pipes_struct *p, { struct spoolss_DriverInfo8 *info = NULL; - struct spoolss_DriverInfo8 *info_win2k = NULL; int version; WERROR status; struct dcerpc_binding_handle *b; + TALLOC_CTX *tmp_ctx = NULL; + int i; + bool found; /* if the user is not root, doesn't have SE_PRINT_OPERATOR privilege, and not a printer admin, then fail */ @@ -2089,73 +2097,112 @@ WERROR _spoolss_DeletePrinterDriver(struct pipes_struct *p, if ((version = get_version_id(r->in.architecture)) == -1) return WERR_INVALID_ENVIRONMENT; - status = winreg_printer_binding_handle(p->mem_ctx, + tmp_ctx = talloc_new(p->mem_ctx); + if (!tmp_ctx) { + return WERR_NOMEM; + } + + status = winreg_printer_binding_handle(tmp_ctx, get_session_info_system(), p->msg_ctx, &b); if (!W_ERROR_IS_OK(status)) { - return status; + goto done; } - status = winreg_get_driver(p->mem_ctx, b, - r->in.architecture, r->in.driver, - version, &info); - if (!W_ERROR_IS_OK(status)) { - /* try for Win2k driver if "Windows NT x86" */ - - if ( version == 2 ) { - version = 3; - - status = winreg_get_driver(p->mem_ctx, b, - r->in.architecture, - r->in.driver, - version, &info); - if (!W_ERROR_IS_OK(status)) { - status = WERR_UNKNOWN_PRINTER_DRIVER; - goto done; - } + for (found = false, i = 0; drv_cversion[i] >= 0; i++) { + status = winreg_get_driver(tmp_ctx, b, + r->in.architecture, r->in.driver, + drv_cversion[i], &info); + if (!W_ERROR_IS_OK(status)) { + DEBUG(5, ("skipping del of driver with version %d\n", + drv_cversion[i])); + continue; } - /* otherwise it was a failure */ - else { - status = WERR_UNKNOWN_PRINTER_DRIVER; + found = true; + + if (printer_driver_in_use(tmp_ctx, get_session_info_system(), + p->msg_ctx, info)) { + status = WERR_PRINTER_DRIVER_IN_USE; goto done; } + status = winreg_del_driver(tmp_ctx, b, info, drv_cversion[i]); + if (!W_ERROR_IS_OK(status)) { + DEBUG(0, ("failed del of driver with version %d\n", + drv_cversion[i])); + goto done; + } } + if (found == false) { + DEBUG(0, ("driver %s not found for deletion\n", r->in.driver)); + status = WERR_UNKNOWN_PRINTER_DRIVER; + } else { + status = WERR_OK; + } + +done: + talloc_free(tmp_ctx); + return status; +} - if (printer_driver_in_use(p->mem_ctx, - get_session_info_system(), - p->msg_ctx, - info)) { +static WERROR spoolss_dpd_version(TALLOC_CTX *mem_ctx, + struct pipes_struct *p, + struct spoolss_DeletePrinterDriverEx *r, + struct dcerpc_binding_handle *b, + struct spoolss_DriverInfo8 *info) +{ + WERROR status; + bool delete_files; + + if (printer_driver_in_use(mem_ctx, get_session_info_system(), + p->msg_ctx, info)) { status = WERR_PRINTER_DRIVER_IN_USE; goto done; } - if (version == 2) { - status = winreg_get_driver(p->mem_ctx, b, - r->in.architecture, - r->in.driver, 3, &info_win2k); - if (W_ERROR_IS_OK(status)) { - /* if we get to here, we now have 2 driver info structures to remove */ - /* remove the Win2k driver first*/ + /* + * we have a couple of cases to consider. + * (1) Are any files in use? If so and DPD_DELETE_ALL_FILES is set, + * then the delete should fail if **any** files overlap with + * other drivers + * (2) If DPD_DELETE_UNUSED_FILES is set, then delete all + * non-overlapping files + * (3) If neither DPD_DELETE_ALL_FILES nor DPD_DELETE_UNUSED_FILES + * is set, then do not delete any files + * Refer to MSDN docs on DeletePrinterDriverEx() for details. + */ - status = winreg_del_driver(p->mem_ctx, b, - info_win2k, 3); - talloc_free(info_win2k); + delete_files = r->in.delete_flags + & (DPD_DELETE_ALL_FILES | DPD_DELETE_UNUSED_FILES); - /* this should not have failed---if it did, report to client */ - if (!W_ERROR_IS_OK(status)) { - goto done; - } - } + /* fail if any files are in use and DPD_DELETE_ALL_FILES is set */ + + if (delete_files && + (r->in.delete_flags & DPD_DELETE_ALL_FILES) && + printer_driver_files_in_use(mem_ctx, + get_session_info_system(), + b, + info)) { + status = WERR_PRINTER_DRIVER_IN_USE; + goto done; } - status = winreg_del_driver(p->mem_ctx, b, - info, version); + status = winreg_del_driver(mem_ctx, b, info, info->version); + if (!W_ERROR_IS_OK(status)) { + goto done; + } -done: - talloc_free(info); + /* + * now delete any associated files if delete_files is + * true. Even if this part failes, we return succes + * because the driver doesn not exist any more + */ + if (delete_files) { + delete_driver_files(get_session_info_system(), info); + } +done: return status; } @@ -2166,12 +2213,12 @@ done: WERROR _spoolss_DeletePrinterDriverEx(struct pipes_struct *p, struct spoolss_DeletePrinterDriverEx *r) { - struct spoolss_DriverInfo8 *info = NULL; - struct spoolss_DriverInfo8 *info_win2k = NULL; - int version; - bool delete_files; + struct spoolss_DriverInfo8 *info = NULL; WERROR status; struct dcerpc_binding_handle *b; + TALLOC_CTX *tmp_ctx = NULL; + int i; + bool found; /* if the user is not root, doesn't have SE_PRINT_OPERATOR privilege, and not a printer admin, then fail */ @@ -2188,150 +2235,57 @@ WERROR _spoolss_DeletePrinterDriverEx(struct pipes_struct *p, } /* check that we have a valid driver name first */ - if ((version = get_version_id(r->in.architecture)) == -1) { + if (get_version_id(r->in.architecture) == -1) { /* this is what NT returns */ return WERR_INVALID_ENVIRONMENT; } - if (r->in.delete_flags & DPD_DELETE_SPECIFIC_VERSION) - version = r->in.version; + tmp_ctx = talloc_new(p->mem_ctx); + if (!tmp_ctx) { + return WERR_NOMEM; + } - status = winreg_printer_binding_handle(p->mem_ctx, + status = winreg_printer_binding_handle(tmp_ctx, get_session_info_system(), p->msg_ctx, &b); if (!W_ERROR_IS_OK(status)) { - return status; + goto done; } - status = winreg_get_driver(p->mem_ctx, b, - r->in.architecture, - r->in.driver, - version, - &info); - if (!W_ERROR_IS_OK(status)) { - status = WERR_UNKNOWN_PRINTER_DRIVER; - - /* - * if the client asked for a specific version, - * or this is something other than Windows NT x86, - * then we've failed - */ - - if ( (r->in.delete_flags & DPD_DELETE_SPECIFIC_VERSION) || (version !=2) ) - goto done; - - /* try for Win2k driver if "Windows NT x86" */ + for (found = false, i = 0; drv_cversion[i] >= 0; i++) { + if ((r->in.delete_flags & DPD_DELETE_SPECIFIC_VERSION) + && (drv_cversion[i] != r->in.version)) { + continue; + } - version = 3; - status = winreg_get_driver(info, b, - r->in.architecture, - r->in.driver, - version, &info); + /* check if a driver with this version exists before delete */ + status = winreg_get_driver(tmp_ctx, b, + r->in.architecture, r->in.driver, + drv_cversion[i], &info); if (!W_ERROR_IS_OK(status)) { - status = WERR_UNKNOWN_PRINTER_DRIVER; - goto done; + DEBUG(5, ("skipping del of driver with version %d\n", + drv_cversion[i])); + continue; } - } - - if (printer_driver_in_use(info, - get_session_info_system(), - p->msg_ctx, - info)) { - status = WERR_PRINTER_DRIVER_IN_USE; - goto done; - } - - /* - * we have a couple of cases to consider. - * (1) Are any files in use? If so and DPD_DELTE_ALL_FILE is set, - * then the delete should fail if **any** files overlap with - * other drivers - * (2) If DPD_DELTE_UNUSED_FILES is sert, then delete all - * non-overlapping files - * (3) If neither DPD_DELTE_ALL_FILE nor DPD_DELTE_ALL_FILES - * is set, the do not delete any files - * Refer to MSDN docs on DeletePrinterDriverEx() for details. - */ - - delete_files = r->in.delete_flags & (DPD_DELETE_ALL_FILES|DPD_DELETE_UNUSED_FILES); - - /* fail if any files are in use and DPD_DELETE_ALL_FILES is set */ - - if (delete_files && - (r->in.delete_flags & DPD_DELETE_ALL_FILES) && - printer_driver_files_in_use(info, - get_session_info_system(), - p->msg_ctx, - info)) { - status = WERR_PRINTER_DRIVER_IN_USE; - goto done; - } - - - /* also check for W32X86/3 if necessary; maybe we already have? */ - - if ( (version == 2) && ((r->in.delete_flags & DPD_DELETE_SPECIFIC_VERSION) != DPD_DELETE_SPECIFIC_VERSION) ) { - status = winreg_get_driver(info, b, - r->in.architecture, - r->in.driver, 3, &info_win2k); - if (W_ERROR_IS_OK(status)) { - - if (delete_files && - (r->in.delete_flags & DPD_DELETE_ALL_FILES) && - printer_driver_files_in_use(info, - get_session_info_system(), - p->msg_ctx, - info_win2k)) { - /* no idea of the correct error here */ - talloc_free(info_win2k); - status = WERR_ACCESS_DENIED; - goto done; - } - - /* if we get to here, we now have 2 driver info structures to remove */ - /* remove the Win2k driver first*/ - - status = winreg_del_driver(info, b, - info_win2k, - 3); - - /* this should not have failed---if it did, report to client */ - - if (!W_ERROR_IS_OK(status)) { - goto done; - } + found = true; - /* - * now delete any associated files if delete_files is - * true. Even if this part failes, we return succes - * because the driver doesn not exist any more - */ - if (delete_files) { - delete_driver_files(get_session_info_system(), - info_win2k); - } + status = spoolss_dpd_version(tmp_ctx, p, r, b, info); + if (!W_ERROR_IS_OK(status)) { + DEBUG(0, ("failed to delete driver with version %d\n", + drv_cversion[i])); + goto done; } } - - status = winreg_del_driver(info, b, - info, - version); - if (!W_ERROR_IS_OK(status)) { - goto done; - } - - /* - * now delete any associated files if delete_files is - * true. Even if this part failes, we return succes - * because the driver doesn not exist any more - */ - if (delete_files) { - delete_driver_files(get_session_info_system(), info); + if (found == false) { + DEBUG(0, ("driver %s not found for deletion\n", r->in.driver)); + status = WERR_UNKNOWN_PRINTER_DRIVER; + } else { + status = WERR_OK; } done: - talloc_free(info); + talloc_free(tmp_ctx); return status; } -- 1.7.7 From b3c87bac1fd3347416077c55b5d8463bf13a6d8b Mon Sep 17 00:00:00 2001 From: David Disseldorp Date: Tue, 17 Jan 2012 17:06:38 +0100 Subject: [PATCH 4/7] s3-spoolss: fix printer_driver_files_in_use() call ordering printer_driver_files_in_use() performs two tasks: it returns whether any of the files in the to-be-deleted driver overlap with other drivers, it also trims such files from the info structure passed in. In processing a DeletePrinterDataEx request with DPD_DELETE_UNUSED_FILES set, printer_driver_files_in_use() must be called to ensure files in use by other drivers are not removed. https://bugzilla.samba.org/show_bug.cgi?id=4942 --- source3/rpc_server/spoolss/srv_spoolss_nt.c | 23 +++++++++++++---------- 1 files changed, 13 insertions(+), 10 deletions(-) diff --git a/source3/rpc_server/spoolss/srv_spoolss_nt.c b/source3/rpc_server/spoolss/srv_spoolss_nt.c index 8e4ddc0..ea99d10 100644 --- a/source3/rpc_server/spoolss/srv_spoolss_nt.c +++ b/source3/rpc_server/spoolss/srv_spoolss_nt.c @@ -2176,16 +2176,19 @@ static WERROR spoolss_dpd_version(TALLOC_CTX *mem_ctx, delete_files = r->in.delete_flags & (DPD_DELETE_ALL_FILES | DPD_DELETE_UNUSED_FILES); - /* fail if any files are in use and DPD_DELETE_ALL_FILES is set */ - - if (delete_files && - (r->in.delete_flags & DPD_DELETE_ALL_FILES) && - printer_driver_files_in_use(mem_ctx, - get_session_info_system(), - b, - info)) { - status = WERR_PRINTER_DRIVER_IN_USE; - goto done; + if (delete_files) { + bool in_use = printer_driver_files_in_use(mem_ctx, + get_session_info_system(), + b, + info); + if (in_use && (r->in.delete_flags & DPD_DELETE_ALL_FILES)) { + status = WERR_PRINTER_DRIVER_IN_USE; + goto done; + } + /* + * printer_driver_files_in_use() has trimmed overlapping files + * from info so they are not removed on DPD_DELETE_UNUSED_FILES + */ } status = winreg_del_driver(mem_ctx, b, info, info->version); -- 1.7.7 From c89e554fc070381a416427872414a58adaf02c87 Mon Sep 17 00:00:00 2001 From: David Disseldorp Date: Mon, 16 Jan 2012 16:30:17 +0100 Subject: [PATCH 5/7] torture: add spoolss del printer driver test Test handling of DeletePrinterDriverEx when the DPD_DELETE_ALL_FILES flag is set. --- source4/torture/rpc/spoolss.c | 63 +++++++++++++++++++++++++++++++++++++++++ 1 files changed, 63 insertions(+), 0 deletions(-) diff --git a/source4/torture/rpc/spoolss.c b/source4/torture/rpc/spoolss.c index 3809136..1aa84f7 100644 --- a/source4/torture/rpc/spoolss.c +++ b/source4/torture/rpc/spoolss.c @@ -49,6 +49,7 @@ #define TORTURE_DRIVER_EX_ADOBE "torture_driver_ex_adobe" #define TORTURE_DRIVER_ADOBE_CUPSADDSMB "torture_driver_adobe_cupsaddsmb" #define TORTURE_DRIVER_TIMESTAMPS "torture_driver_timestamps" +#define TORTURE_DRIVER_DELETER "torture_driver_deleter" #define TOP_LEVEL_PRINT_KEY "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Print" #define TOP_LEVEL_PRINT_PRINTERS_KEY TOP_LEVEL_PRINT_KEY "\\Printers" @@ -9206,6 +9207,10 @@ static bool test_add_driver_adobe(struct torture_context *tctx, { struct torture_driver_context *d; + if (!torture_setting_bool(tctx, "samba3", false)) { + torture_skip(tctx, "skipping adobe test which only works against samba3"); + } + d = talloc_zero(tctx, struct torture_driver_context); d->info8.version = SPOOLSS_DRIVER_VERSION_9X; @@ -9371,6 +9376,62 @@ static bool test_multiple_drivers(struct torture_context *tctx, return true; } +static bool test_del_driver_all_files(struct torture_context *tctx, + struct dcerpc_pipe *p) +{ + struct torture_driver_context *d; + struct spoolss_StringArray *a; + uint32_t add_flags = APD_COPY_NEW_FILES; + uint32_t delete_flags = DPD_DELETE_ALL_FILES; + struct dcerpc_binding_handle *b = p->binding_handle; + const char *server_name_slash = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p)); + + d = talloc_zero(tctx, struct torture_driver_context); + + d->ex = true; + d->info8.version = SPOOLSS_DRIVER_VERSION_200X; + d->info8.driver_name = TORTURE_DRIVER_DELETER; + 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->info8.help_file = talloc_strdup(d, "pscript.hlp"); + d->local.environment = talloc_strdup(d, SPOOLSS_ARCHITECTURE_x64); + d->local.driver_directory = talloc_strdup(d, "/usr/share/cups/drivers/x64"); + + a = talloc_zero(d, struct spoolss_StringArray); + a->string = talloc_zero_array(a, const char *, 3); + a->string[0] = talloc_strdup(a->string, "cups6.inf"); + a->string[1] = talloc_strdup(a->string, "cups6.ini"); + + d->info8.dependent_files = a; + d->info8.architecture = d->local.environment; + + torture_assert(tctx, + fillup_printserver_info(tctx, p, d), + "failed to fillup printserver info"); + + if (!directory_exist(d->local.driver_directory)) { + torture_skip(tctx, "Skipping Printer Driver test as no local driver is available"); + } + + torture_assert(tctx, + upload_printer_driver(tctx, dcerpc_server_name(p), d), + "failed to upload printer driver"); + + torture_assert(tctx, + test_AddPrinterDriver_args_level_3(tctx, b, server_name_slash, &d->info8, add_flags, true, NULL), + "failed to add driver"); + + torture_assert(tctx, + test_DeletePrinterDriverEx(tctx, b, server_name_slash, d->info8.driver_name, d->local.environment, delete_flags, d->info8.version), + "failed to delete driver"); + + /* TODO check all files are removed */ + + return true; +} + struct torture_suite *torture_rpc_spoolss_driver(TALLOC_CTX *mem_ctx) { struct torture_suite *suite = torture_suite_create(mem_ctx, "spoolss.driver"); @@ -9391,5 +9452,7 @@ struct torture_suite *torture_rpc_spoolss_driver(TALLOC_CTX *mem_ctx) torture_rpc_tcase_add_test(tcase, "multiple_drivers", test_multiple_drivers); + torture_rpc_tcase_add_test(tcase, "del_driver_all_files", test_del_driver_all_files); + return suite; } -- 1.7.7 From 4ca17354b255b9deb4bfd8f437ac86b656b923bd Mon Sep 17 00:00:00 2001 From: David Disseldorp Date: Tue, 17 Jan 2012 15:20:51 +0100 Subject: [PATCH 6/7] torture: confirm printer driver file removal --- source4/torture/rpc/spoolss.c | 82 ++++++++++++++++++++++++++++++++++++++++- 1 files changed, 81 insertions(+), 1 deletions(-) diff --git a/source4/torture/rpc/spoolss.c b/source4/torture/rpc/spoolss.c index 1aa84f7..1fb7d35 100644 --- a/source4/torture/rpc/spoolss.c +++ b/source4/torture/rpc/spoolss.c @@ -8923,6 +8923,84 @@ static bool upload_printer_driver(struct torture_context *tctx, return true; } +static bool check_printer_driver_file(struct torture_context *tctx, + struct smbcli_state *cli, + struct torture_driver_context *d, + const char *file_name) +{ + const char *remote_arch_dir = driver_directory_dir(d->remote.driver_directory); + const char *remote_name = talloc_asprintf(tctx, "%s\\%d\\%s", + remote_arch_dir, + d->info8.version, + file_name); + int fnum; + + torture_assert(tctx, (file_name && strlen(file_name) != 0), "invalid filename"); + + torture_comment(tctx, "checking for driver file at %s\n", remote_name); + + fnum = smbcli_open(cli->tree, remote_name, O_RDONLY, DENY_NONE); + if (fnum == -1) { + return false; + } + + torture_assert_ntstatus_ok(tctx, + smbcli_close(cli->tree, fnum), + "failed to close driver file"); + + return true; +} + +static bool check_printer_driver_files(struct torture_context *tctx, + const char *server_name, + struct torture_driver_context *d, + bool expect_exist) +{ + struct smbcli_state *cli; + const char *share_name = driver_directory_share(tctx, d->remote.driver_directory); + int i; + + torture_assert(tctx, + connect_printer_driver_share(tctx, server_name, share_name, &cli), + "failed to connect to driver share"); + + torture_comment(tctx, "checking %sexistent driver files at \\\\%s\\%s\n", + (expect_exist ? "": "non-"), + server_name, share_name); + + if (d->info8.driver_path && d->info8.driver_path[0]) { + torture_assert(tctx, + check_printer_driver_file(tctx, cli, d, d->info8.driver_path) == expect_exist, + "failed driver_path check"); + } + if (d->info8.data_file && d->info8.data_file[0]) { + torture_assert(tctx, + check_printer_driver_file(tctx, cli, d, d->info8.data_file) == expect_exist, + "failed data_file check"); + } + if (d->info8.config_file && d->info8.config_file[0]) { + torture_assert(tctx, + check_printer_driver_file(tctx, cli, d, d->info8.config_file) == expect_exist, + "failed config_file check"); + } + if (d->info8.help_file && d->info8.help_file[0]) { + torture_assert(tctx, + check_printer_driver_file(tctx, cli, d, d->info8.help_file) == expect_exist, + "failed help_file check"); + } + if (d->info8.dependent_files) { + for (i=0; d->info8.dependent_files->string && d->info8.dependent_files->string[i] != NULL; i++) { + torture_assert(tctx, + check_printer_driver_file(tctx, cli, d, d->info8.dependent_files->string[i]) == expect_exist, + "failed dependent_files check"); + } + } + + talloc_free(cli); + + return true; +} + static bool remove_printer_driver_file(struct torture_context *tctx, struct smbcli_state *cli, struct torture_driver_context *d, @@ -9427,7 +9505,9 @@ static bool test_del_driver_all_files(struct torture_context *tctx, test_DeletePrinterDriverEx(tctx, b, server_name_slash, d->info8.driver_name, d->local.environment, delete_flags, d->info8.version), "failed to delete driver"); - /* TODO check all files are removed */ + torture_assert(tctx, + check_printer_driver_files(tctx, dcerpc_server_name(p), d, false), + "printer driver file check failed"); return true; } -- 1.7.7 From c9c762f0a58319c168e6f9f04cd2bf48bb349f98 Mon Sep 17 00:00:00 2001 From: David Disseldorp Date: Tue, 17 Jan 2012 17:07:01 +0100 Subject: [PATCH 7/7] torture: add spoolss overlapping driver deletion tests --- source4/torture/rpc/spoolss.c | 119 ++++++++++++++++++++++++++++++++++++++++- 1 files changed, 118 insertions(+), 1 deletions(-) diff --git a/source4/torture/rpc/spoolss.c b/source4/torture/rpc/spoolss.c index 1fb7d35..df800dc 100644 --- a/source4/torture/rpc/spoolss.c +++ b/source4/torture/rpc/spoolss.c @@ -50,6 +50,7 @@ #define TORTURE_DRIVER_ADOBE_CUPSADDSMB "torture_driver_adobe_cupsaddsmb" #define TORTURE_DRIVER_TIMESTAMPS "torture_driver_timestamps" #define TORTURE_DRIVER_DELETER "torture_driver_deleter" +#define TORTURE_DRIVER_DELETERIN "torture_driver_deleterin" #define TOP_LEVEL_PRINT_KEY "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Print" #define TOP_LEVEL_PRINT_PRINTERS_KEY TOP_LEVEL_PRINT_KEY "\\Printers" @@ -9502,13 +9503,127 @@ static bool test_del_driver_all_files(struct torture_context *tctx, "failed to add driver"); torture_assert(tctx, - test_DeletePrinterDriverEx(tctx, b, server_name_slash, d->info8.driver_name, d->local.environment, delete_flags, d->info8.version), + test_DeletePrinterDriverEx(tctx, b, server_name_slash, + d->info8.driver_name, + d->local.environment, + delete_flags, + d->info8.version), "failed to delete driver"); torture_assert(tctx, check_printer_driver_files(tctx, dcerpc_server_name(p), d, false), "printer driver file check failed"); + talloc_free(d); + return true; +} + +static bool test_del_driver_unused_files(struct torture_context *tctx, + struct dcerpc_pipe *p) +{ + struct torture_driver_context *d1; + struct torture_driver_context *d2; + uint32_t add_flags = APD_COPY_NEW_FILES; + struct dcerpc_binding_handle *b = p->binding_handle; + const char *server_name_slash = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p)); + + d1 = talloc_zero(tctx, struct torture_driver_context); + d1->ex = true; + d1->info8.version = SPOOLSS_DRIVER_VERSION_200X; + d1->info8.driver_name = TORTURE_DRIVER_DELETER; + d1->info8.architecture = NULL; + d1->info8.driver_path = talloc_strdup(d1, "pscript5.dll"); + d1->info8.data_file = talloc_strdup(d1, "cups6.ppd"); + d1->info8.config_file = talloc_strdup(d1, "cupsui6.dll"); + d1->info8.help_file = talloc_strdup(d1, "pscript.hlp"); + d1->local.environment = talloc_strdup(d1, SPOOLSS_ARCHITECTURE_x64); + d1->local.driver_directory = talloc_strdup(d1, "/usr/share/cups/drivers/x64"); + d1->info8.architecture = d1->local.environment; + + d2 = talloc_zero(tctx, struct torture_driver_context); + d2->ex = true; + d2->info8.version = SPOOLSS_DRIVER_VERSION_200X; + d2->info8.driver_name = TORTURE_DRIVER_DELETERIN; + d2->info8.architecture = NULL; + d2->info8.driver_path = talloc_strdup(d2, "pscript5.dll"); /* overlapping */ + d2->info8.data_file = talloc_strdup(d2, "cupsps6.dll"); + d2->info8.config_file = talloc_strdup(d2, "cups6.ini"); + d2->info8.help_file = talloc_strdup(d2, "pscript.hlp"); /* overlapping */ + d2->local.environment = talloc_strdup(d2, SPOOLSS_ARCHITECTURE_x64); + d2->local.driver_directory = talloc_strdup(d2, "/usr/share/cups/drivers/x64"); + d2->info8.architecture = d2->local.environment; + + torture_assert(tctx, + fillup_printserver_info(tctx, p, d1), + "failed to fillup printserver info"); + torture_assert(tctx, + fillup_printserver_info(tctx, p, d2), + "failed to fillup printserver info"); + + if (!directory_exist(d1->local.driver_directory)) { + torture_skip(tctx, "Skipping Printer Driver test as no local driver is available"); + } + + torture_assert(tctx, + upload_printer_driver(tctx, dcerpc_server_name(p), d1), + "failed to upload printer driver"); + torture_assert(tctx, + test_AddPrinterDriver_args_level_3(tctx, b, server_name_slash, &d1->info8, add_flags, true, NULL), + "failed to add driver"); + + torture_assert(tctx, + upload_printer_driver(tctx, dcerpc_server_name(p), d2), + "failed to upload printer driver"); + torture_assert(tctx, + test_AddPrinterDriver_args_level_3(tctx, b, server_name_slash, &d2->info8, add_flags, true, NULL), + "failed to add driver"); + + /* some files are in use by a separate driver, should fail */ + torture_assert(tctx, + test_DeletePrinterDriverEx_exp(tctx, b, server_name_slash, + d1->info8.driver_name, + d1->local.environment, + DPD_DELETE_ALL_FILES, + d1->info8.version, + WERR_PRINTER_DRIVER_IN_USE), + "invalid delete driver response"); + + /* should only delete files not in use by other driver */ + torture_assert(tctx, + test_DeletePrinterDriverEx_exp(tctx, b, server_name_slash, + d1->info8.driver_name, + d1->local.environment, + DPD_DELETE_UNUSED_FILES, + d1->info8.version, + WERR_OK), + "failed to delete driver (unused files)"); + + /* check non-overlapping were deleted */ + d1->info8.driver_path = NULL; + d1->info8.help_file = NULL; + torture_assert(tctx, + check_printer_driver_files(tctx, dcerpc_server_name(p), d1, false), + "printer driver file check failed"); + /* d2 files should be uneffected */ + torture_assert(tctx, + check_printer_driver_files(tctx, dcerpc_server_name(p), d2, true), + "printer driver file check failed"); + + torture_assert(tctx, + test_DeletePrinterDriverEx_exp(tctx, b, server_name_slash, + d2->info8.driver_name, + d2->local.environment, + DPD_DELETE_ALL_FILES, + d2->info8.version, + WERR_OK), + "failed to delete driver"); + + torture_assert(tctx, + check_printer_driver_files(tctx, dcerpc_server_name(p), d2, false), + "printer driver file check failed"); + + talloc_free(d1); + talloc_free(d2); return true; } @@ -9534,5 +9649,7 @@ struct torture_suite *torture_rpc_spoolss_driver(TALLOC_CTX *mem_ctx) torture_rpc_tcase_add_test(tcase, "del_driver_all_files", test_del_driver_all_files); + torture_rpc_tcase_add_test(tcase, "del_driver_unused_files", test_del_driver_unused_files); + return suite; } -- 1.7.7