diff options
-rw-r--r-- | 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 2403f32d9db..8e4ddc0414f 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; } |