From fa6ebf10de3dfe847b204531024893b35806ac75 Mon Sep 17 00:00:00 2001 From: David Disseldorp Date: Fri, 24 Jun 2011 10:55:08 +0200 Subject: [PATCH 1/2] s3-printing: fix migrate_driver() _spoolss_AddPrinterDriverEx() currently strips all driver paths to base file names and assumes that these files are staged in the $architecture subdirectory of the print$ share path. This assumption is incorrect when an AddPrinterDriver is issued to upgrade internal printing tdbs to the new registry format, as performed by migrate_driver(). This fix adds support for APD_COPY_FROM_DIRECTORY which allows fully qualified file names in an AddPrinterDriverEx request. https://bugzilla.samba.org/show_bug.cgi?id=8214 --- source3/include/nt_printing.h | 11 ++- source3/printing/nt_printing.c | 148 ++++++++++++++++---------- source3/printing/nt_printing_migrate.c | 69 ++++++++---- source3/rpc_server/spoolss/srv_spoolss_nt.c | 26 +++++- 4 files changed, 169 insertions(+), 85 deletions(-) diff --git a/source3/include/nt_printing.h b/source3/include/nt_printing.h index ad6262e..ee16145 100644 --- a/source3/include/nt_printing.h +++ b/source3/include/nt_printing.h @@ -172,9 +172,14 @@ bool delete_driver_files(const struct auth_serversupplied_info *server_info, WERROR move_driver_to_download_area(struct auth_serversupplied_info *session_info, struct spoolss_AddDriverInfoCtr *r); -WERROR clean_up_driver_struct(TALLOC_CTX *mem_ctx, - struct auth_serversupplied_info *session_info, - struct spoolss_AddDriverInfoCtr *r); +WERROR get_driver_cversion_struct(TALLOC_CTX *mem_ctx, + struct auth_serversupplied_info *session_info, + struct spoolss_AddDriverInfoCtr *r); + +WERROR strip_driver_paths_struct(TALLOC_CTX *mem_ctx, + struct auth_serversupplied_info *session_info, + struct spoolss_AddDriverInfoCtr *r, + bool prepend_arch); void map_printer_permissions(struct security_descriptor *sd); diff --git a/source3/printing/nt_printing.c b/source3/printing/nt_printing.c index 6d4bebb..71c442a 100644 --- a/source3/printing/nt_printing.c +++ b/source3/printing/nt_printing.c @@ -581,7 +581,6 @@ static uint32 get_correct_cversion(struct auth_serversupplied_info *session_info int cversion = -1; NTSTATUS nt_status; struct smb_filename *smb_fname = NULL; - char *driverpath = NULL; files_struct *fsp = NULL; connection_struct *conn = NULL; char *oldcwd; @@ -639,16 +638,7 @@ static uint32 get_correct_cversion(struct auth_serversupplied_info *session_info /* Open the driver file (Portable Executable format) and determine the * deriver the cversion. */ - driverpath = talloc_asprintf(talloc_tos(), - "%s/%s", - architecture, - driverpath_in); - if (!driverpath) { - *perr = WERR_NOMEM; - goto error_exit; - } - - nt_status = driver_unix_convert(conn, driverpath, &smb_fname); + nt_status = driver_unix_convert(conn, driverpath_in, &smb_fname); if (!NT_STATUS_IS_OK(nt_status)) { *perr = ntstatus_to_werror(nt_status); goto error_exit; @@ -753,27 +743,28 @@ static uint32 get_correct_cversion(struct auth_serversupplied_info *session_info /**************************************************************************** ****************************************************************************/ -#define strip_driver_path(_mem_ctx, _element) do { \ +#define strip_driver_path(_mem_ctx, _prefix, _element) do { \ + char *_p; \ if (_element && ((_p = strrchr((_element), '\\')) != NULL)) { \ - (_element) = talloc_asprintf((_mem_ctx), "%s", _p+1); \ + (_element) = talloc_asprintf((_mem_ctx), "%s%s", \ + (_prefix) ? (_prefix) : "", _p+1); \ W_ERROR_HAVE_NO_MEMORY((_element)); \ } \ } while (0); -static WERROR clean_up_driver_struct_level(TALLOC_CTX *mem_ctx, - struct auth_serversupplied_info *session_info, - const char *architecture, - const char **driver_path, - const char **data_file, - const char **config_file, - const char **help_file, - struct spoolss_StringArray *dependent_files, - enum spoolss_DriverOSVersion *version) +static WERROR strip_driver_paths(TALLOC_CTX *mem_ctx, + struct auth_serversupplied_info *session_info, + const char *architecture, + const char **driver_path, + const char **data_file, + const char **config_file, + const char **help_file, + struct spoolss_StringArray *dependent_files, + bool prepend_arch) { - const char *short_architecture; int i; - WERROR err; - char *_p; + const char *short_architecture; + const char *prefix; if (!*driver_path || !*data_file) { return WERR_INVALID_PARAM; @@ -783,28 +774,68 @@ static WERROR clean_up_driver_struct_level(TALLOC_CTX *mem_ctx, return WERR_INVALID_PARAM; } + short_architecture = get_short_archi(architecture); + if (!short_architecture) { + return WERR_UNKNOWN_PRINTER_DRIVER; + } + + if (prepend_arch) { + prefix = talloc_asprintf(mem_ctx, "%s\\", short_architecture); + } else { + prefix = NULL; + } + /* clean up the driver name. * we can get .\driver.dll * or worse c:\windows\system\driver.dll ! */ /* using an intermediate string to not have overlaping memcpy()'s */ - strip_driver_path(mem_ctx, *driver_path); - strip_driver_path(mem_ctx, *data_file); + strip_driver_path(mem_ctx, prefix, *driver_path); + strip_driver_path(mem_ctx, prefix, *data_file); if (*config_file) { - strip_driver_path(mem_ctx, *config_file); + strip_driver_path(mem_ctx, prefix, *config_file); } if (help_file) { - strip_driver_path(mem_ctx, *help_file); + strip_driver_path(mem_ctx, prefix, *help_file); } if (dependent_files && dependent_files->string) { for (i=0; dependent_files->string[i]; i++) { - strip_driver_path(mem_ctx, dependent_files->string[i]); + strip_driver_path(mem_ctx, prefix, + dependent_files->string[i]); } } - short_architecture = get_short_archi(architecture); + return WERR_OK; +} + +WERROR get_driver_cversion_struct(TALLOC_CTX *mem_ctx, + struct auth_serversupplied_info *session_info, + struct spoolss_AddDriverInfoCtr *r) +{ + const char *long_arch; + const char *short_architecture; + const char *driver_path; + enum spoolss_DriverOSVersion *version; + WERROR err; + + switch (r->level) { + case 3: + long_arch = r->info.info3->architecture; + driver_path = r->info.info3->driver_path; + version = &r->info.info3->version; + break; + case 6: + long_arch = r->info.info6->architecture; + driver_path = r->info.info6->driver_path; + version = &r->info.info6->version; + break; + default: + return WERR_NOT_SUPPORTED; + } + + short_architecture = get_short_archi(long_arch); if (!short_architecture) { return WERR_UNKNOWN_PRINTER_DRIVER; } @@ -822,40 +853,40 @@ static WERROR clean_up_driver_struct_level(TALLOC_CTX *mem_ctx, */ *version = get_correct_cversion(session_info, short_architecture, - *driver_path, &err); + driver_path, &err); if (*version == -1) { return err; } - return WERR_OK; } /**************************************************************************** ****************************************************************************/ -WERROR clean_up_driver_struct(TALLOC_CTX *mem_ctx, - struct auth_serversupplied_info *session_info, - struct spoolss_AddDriverInfoCtr *r) +WERROR strip_driver_paths_struct(TALLOC_CTX *mem_ctx, + struct auth_serversupplied_info *session_info, + struct spoolss_AddDriverInfoCtr *r, + bool prepend_arch) { switch (r->level) { case 3: - return clean_up_driver_struct_level(mem_ctx, session_info, - r->info.info3->architecture, - &r->info.info3->driver_path, - &r->info.info3->data_file, - &r->info.info3->config_file, - &r->info.info3->help_file, - r->info.info3->dependent_files, - &r->info.info3->version); + return strip_driver_paths(mem_ctx, session_info, + r->info.info3->architecture, + &r->info.info3->driver_path, + &r->info.info3->data_file, + &r->info.info3->config_file, + &r->info.info3->help_file, + r->info.info3->dependent_files, + prepend_arch); case 6: - return clean_up_driver_struct_level(mem_ctx, session_info, - r->info.info6->architecture, - &r->info.info6->driver_path, - &r->info.info6->data_file, - &r->info.info6->config_file, - &r->info.info6->help_file, - r->info.info6->dependent_files, - &r->info.info6->version); + return strip_driver_paths(mem_ctx, session_info, + r->info.info6->architecture, + &r->info.info6->driver_path, + &r->info.info6->data_file, + &r->info.info6->config_file, + &r->info.info6->help_file, + r->info.info6->dependent_files, + prepend_arch); default: return WERR_NOT_SUPPORTED; } @@ -883,6 +914,7 @@ static void convert_level_6_to_level3(struct spoolss_AddDriverInfo3 *dst, } /**************************************************************************** + Move a driver file to its corresponding $arch/$driver_version subdirectory ****************************************************************************/ static WERROR move_driver_file_to_download_area(TALLOC_CTX *mem_ctx, @@ -896,19 +928,21 @@ static WERROR move_driver_file_to_download_area(TALLOC_CTX *mem_ctx, struct smb_filename *smb_fname_new = NULL; char *old_name = NULL; char *new_name = NULL; + char *new_path_prefix; NTSTATUS status; WERROR ret; - old_name = talloc_asprintf(mem_ctx, "%s/%s", - short_architecture, driver_file); + old_name = talloc_strdup(mem_ctx, driver_file); W_ERROR_HAVE_NO_MEMORY(old_name); - new_name = talloc_asprintf(mem_ctx, "%s/%d/%s", - short_architecture, driver_version, driver_file); - if (new_name == NULL) { + new_name = old_name; + new_path_prefix = talloc_asprintf(mem_ctx, "%s/%d/", + short_architecture, driver_version); + if (new_path_prefix == NULL) { TALLOC_FREE(old_name); return WERR_NOMEM; } + strip_driver_path(mem_ctx, new_path_prefix, new_name); if (version != -1 && (version = file_version_is_newer(conn, old_name, new_name)) > 0) { diff --git a/source3/printing/nt_printing_migrate.c b/source3/printing/nt_printing_migrate.c index e122934..ad4b4b1 100644 --- a/source3/printing/nt_printing_migrate.c +++ b/source3/printing/nt_printing_migrate.c @@ -133,6 +133,15 @@ static NTSTATUS migrate_form(TALLOC_CTX *mem_ctx, return status; } +static char *normalize_drv_path(const char **path) +{ + int ret = strncmp(*path, "\\print$", sizeof("\\print$") - 1); + if (ret == 0) { + return (char *)(*path + sizeof("\\print$") - 1); + } + return (char *)*path; +} + static NTSTATUS migrate_driver(TALLOC_CTX *mem_ctx, struct rpc_pipe_client *pipe_hnd, const char *key_name, @@ -144,11 +153,13 @@ static NTSTATUS migrate_driver(TALLOC_CTX *mem_ctx, enum ndr_err_code ndr_err; struct ntprinting_driver r; struct spoolss_AddDriverInfoCtr d; - struct spoolss_AddDriverInfo3 d3; + struct spoolss_AddDriverInfo6 d6; struct spoolss_StringArray a; DATA_BLOB blob; NTSTATUS status; WERROR result; + char *npath; + int i; blob = data_blob_const(data, length); @@ -169,36 +180,48 @@ static NTSTATUS migrate_driver(TALLOC_CTX *mem_ctx, return NT_STATUS_NO_MEMORY; } - ZERO_STRUCT(d3); + ZERO_STRUCT(d6); ZERO_STRUCT(a); + for (i = 0; r.dependent_files[i] != NULL; i++) { + npath = normalize_drv_path(&r.dependent_files[i]); + r.dependent_files[i] = npath; + } a.string = r.dependent_files; - d3.architecture = r.environment; - d3.config_file = r.configfile; - d3.data_file = r.datafile; - d3.default_datatype = r.defaultdatatype; - d3.dependent_files = &a; - d3.driver_path = r.driverpath; - d3.help_file = r.helpfile; - d3.monitor_name = r.monitorname; - d3.driver_name = r.name; - d3.version = r.version; - - d.level = 3; - d.info.info3 = &d3; - - status = dcerpc_spoolss_AddPrinterDriver(b, - mem_ctx, - srv_name_slash, - &d, - &result); + /* file paths are in \print$\arch\driver_version format */ + d6.architecture = r.environment; + d6.config_file = normalize_drv_path(&r.configfile); + d6.data_file = normalize_drv_path(&r.datafile); + d6.default_datatype = r.defaultdatatype; + d6.dependent_files = &a; + d6.driver_path = normalize_drv_path(&r.driverpath); + d6.help_file = normalize_drv_path(&r.helpfile); + d6.monitor_name = r.monitorname; + d6.driver_name = r.name; + d6.version = r.version; + + d.level = 6; + d.info.info6 = &d6; + + /* + * Driver files are already present, use APD_COPY_FROM_DIRECTORY to: + * Add the printer driver by using the fully qualified file names that + * are specified in the _DRIVER_INFO_6 structure. + */ + status = dcerpc_spoolss_AddPrinterDriverEx(b, + mem_ctx, + srv_name_slash, + &d, + APD_COPY_NEW_FILES + | APD_COPY_FROM_DIRECTORY, + &result); if (!NT_STATUS_IS_OK(status)) { DEBUG(2, ("dcerpc_spoolss_AddPrinterDriver(%s) refused -- %s.\n", - d3.driver_name, nt_errstr(status))); + d6.driver_name, nt_errstr(status))); } else if (!W_ERROR_IS_OK(result)) { DEBUG(2, ("AddPrinterDriver(%s) refused -- %s.\n", - d3.driver_name, win_errstr(result))); + d6.driver_name, win_errstr(result))); status = werror_to_ntstatus(result); } diff --git a/source3/rpc_server/spoolss/srv_spoolss_nt.c b/source3/rpc_server/spoolss/srv_spoolss_nt.c index 7980072..289b25a 100644 --- a/source3/rpc_server/spoolss/srv_spoolss_nt.c +++ b/source3/rpc_server/spoolss/srv_spoolss_nt.c @@ -8029,7 +8029,8 @@ WERROR _spoolss_AddPrinterDriverEx(struct pipes_struct *p, return WERR_INVALID_PARAM; } - if (r->in.flags != APD_COPY_NEW_FILES) { + if ((r->in.flags != APD_COPY_NEW_FILES) + && (r->in.flags != (APD_COPY_NEW_FILES | APD_COPY_FROM_DIRECTORY))) { return WERR_ACCESS_DENIED; } @@ -8044,7 +8045,17 @@ WERROR _spoolss_AddPrinterDriverEx(struct pipes_struct *p, } DEBUG(5,("Cleaning driver's information\n")); - err = clean_up_driver_struct(p->mem_ctx, p->session_info, r->in.info_ctr); + if (r->in.flags & APD_COPY_FROM_DIRECTORY) { + /* TODO validate paths exist under print$ */ + } else { + /* assume source driver files are staged in print$\arch\ */ + err = strip_driver_paths_struct(p->mem_ctx, p->session_info, + r->in.info_ctr, true); + if (!W_ERROR_IS_OK(err)) + goto done; + } + err = get_driver_cversion_struct(p->mem_ctx, p->session_info, + r->in.info_ctr); if (!W_ERROR_IS_OK(err)) goto done; @@ -8054,6 +8065,17 @@ WERROR _spoolss_AddPrinterDriverEx(struct pipes_struct *p, goto done; } + /* + * Driver paths are stored in the registry stripped of directory + * prefixes. The print$\arch\version\ path is reconstructed when + * processing GetPrinterDriver requests. + */ + err = strip_driver_paths_struct(p->mem_ctx, p->session_info, + r->in.info_ctr, false); + if (!W_ERROR_IS_OK(err)) { + goto done; + } + err = winreg_add_driver(p->mem_ctx, get_session_info_system(), p->msg_ctx, -- 1.7.1