summaryrefslogtreecommitdiff
path: root/source3/printing
diff options
context:
space:
mode:
authorJeremy Allison <jra@samba.org>2000-10-25 17:56:38 +0000
committerJeremy Allison <jra@samba.org>2000-10-25 17:56:38 +0000
commit209485694266a91935d8ef7dda6c7d635d40d23f (patch)
treeaf4463edaffb0d430e7b4366d6899d267c62606f /source3/printing
parent72626a7954a4bd64a05a3610907c1f8f1a6f1fc1 (diff)
downloadsamba-209485694266a91935d8ef7dda6c7d635d40d23f.tar.gz
samba-209485694266a91935d8ef7dda6c7d635d40d23f.tar.bz2
samba-209485694266a91935d8ef7dda6c7d635d40d23f.zip
John Reilly @ HP (who is a wonderful human being and *definately* needs
CVS commit access :-) has written a simple routine that peeks inside the MS PE printer driver file format and can tell if a driver is W2K or NT4.x. So we can now correctly return the driver version number. Hurrah ! JF - this is the code you always wanted ..... :-) :-). Jeremy. (This used to be commit fd17374e6d888813f4ed7142480cf93b8a16bfef)
Diffstat (limited to 'source3/printing')
-rw-r--r--source3/printing/nt_printing.c215
1 files changed, 161 insertions, 54 deletions
diff --git a/source3/printing/nt_printing.c b/source3/printing/nt_printing.c
index bd968c66ab..48bab48b3c 100644
--- a/source3/printing/nt_printing.c
+++ b/source3/printing/nt_printing.c
@@ -340,36 +340,129 @@ BOOL get_short_archi(char *short_archi, char *long_archi)
}
/****************************************************************************
+Determine the correct cVersion associated with an architecture and driver
****************************************************************************/
-static void clean_up_driver_struct_level_3(NT_PRINTER_DRIVER_INFO_LEVEL_3 *driver)
+static uint32 get_correct_cversion(fstring architecture, fstring driverpath_in)
{
- fstring architecture;
- fstring new_name;
- char *p;
- int i;
+ int fd = -1;
+ int service;
+ int cversion;
+ ssize_t byte_count;
+ char buf[PE_HEADER_SIZE];
+ pstring driverpath;
+
+ /* If architecture is Windows 95/98, the version is always 0. */
+ if (strcmp(architecture, "WIN40") == 0) {
+ DEBUG(10,("get_correct_cversion: Driver is Win9x, cversion = 0\n"));
+ return 0;
+ }
- /* jfm:7/16/2000 the client always sends the cversion=0.
- * The server should check which version the driver is by reading the PE header
- * of driver->driverpath.
- *
- * For Windows 95/98 the version is 0 (so the value sent is correct)
- * For Windows NT (the architecture doesn't matter)
- * NT 3.1: cversion=0
- * NT 3.5/3.51: cversion=1
- * NT 4: cversion=2
- * NT2K: cversion=3
+ /* Open the driver file (Portable Executable format) and determine the
+ * deriver the cversion.
*/
+ if ((service = find_service("print$")) == -1) {
+ DEBUG(3,("get_correct_cversion: Can't find print$ service\n"));
+ goto error_exit;
+ }
- get_short_archi(architecture, driver->environment);
+ slprintf(driverpath, sizeof(driverpath), "%s/%s/%s",
+ lp_pathname(service), architecture, driverpath_in);
- /* if it's Windows 95/98, we keep the version at 0
- * jfmxxx: I need to redo that more correctly for NT2K.
- */
+ dos_to_unix(driverpath, True);
+
+ if ((fd = sys_open(driverpath, O_RDONLY, 0)) == -1) {
+ DEBUG(3,("get_correct_cversion: Can't open file [%s], errno = %d\n",
+ driverpath, errno));
+ goto error_exit;
+ }
- if (StrCaseCmp(driver->environment, "Windows 4.0")==0)
- driver->cversion=0;
- else
- driver->cversion=2;
+ if ((byte_count = read(fd, buf, DOS_HEADER_SIZE)) < DOS_HEADER_SIZE) {
+ DEBUG(3,("get_correct_cversion: File [%s] DOS header too short, bytes read = %d\n",
+ driverpath, byte_count));
+ goto error_exit;
+ }
+
+ /* Is this really a DOS header? */
+ if (SVAL(buf,DOS_HEADER_MAGIC_OFFSET) != DOS_HEADER_MAGIC) {
+ DEBUG(6,("get_correct_cversion: File [%s] bad DOS magic = 0x%x\n",
+ driverpath, SVAL(buf,DOS_HEADER_MAGIC_OFFSET)));
+ goto error_exit;
+ }
+
+ /* Skip OEM header (if any) and the DOS stub to start of Windows header */
+ if (sys_lseek(fd, SVAL(buf,DOS_HEADER_LFANEW_OFFSET), SEEK_SET) == (SMB_OFF_T)-1) {
+ DEBUG(3,("get_correct_cversion: File [%s] too short, errno = %d\n",
+ driverpath, errno));
+ goto error_exit;
+ }
+
+ if ((byte_count = read(fd, buf, PE_HEADER_SIZE)) < PE_HEADER_SIZE) {
+ DEBUG(3,("get_correct_cversion: File [%s] Windows header too short, bytes read = %d\n",
+ driverpath, byte_count));
+ goto error_exit;
+ }
+ close(fd);
+
+ /* The header may be a PE (Portable Executable) or an NE (New Executable) */
+ if (IVAL(buf,PE_HEADER_SIGNATURE_OFFSET) == PE_HEADER_SIGNATURE) {
+ if (SVAL(buf,PE_HEADER_MACHINE_OFFSET) == PE_HEADER_MACHINE_I386) {
+
+ switch (SVAL(buf,PE_HEADER_MAJOR_OS_VER_OFFSET)) {
+ case 4: cversion = 2; break; /* Win NT 4 */
+ case 5: cversion = 3; break; /* Win 2000 */
+ default:
+ DEBUG(6,("get_correct_cversion: PE formated file [%s] bad version = %d\n",
+ driverpath, SVAL(buf,PE_HEADER_MAJOR_OS_VER_OFFSET)));
+ goto error_exit;
+ }
+ } else {
+ DEBUG(6,("get_correct_cversion: PE formatted file [%s] wrong machine = 0x%x\n",
+ driverpath, SVAL(buf,PE_HEADER_MACHINE_OFFSET)));
+ goto error_exit;
+ }
+
+ } else if (SVAL(buf,NE_HEADER_SIGNATURE_OFFSET) == NE_HEADER_SIGNATURE) {
+ if (CVAL(buf,NE_HEADER_TARGET_OS_OFFSET) == NE_HEADER_TARGOS_WIN ) {
+
+ switch (CVAL(buf,NE_HEADER_MAJOR_VER_OFFSET)) {
+ case 3: cversion = 0; break; /* Win 3.x / Win 9x / Win ME */
+ /* case ?: cversion = 1; break;*/ /* Win NT 3.51 ... needs research JRR */
+ default:
+ DEBUG(6,("get_correct_cversion: NE formated file [%s] bad version = %d\n",
+ driverpath, CVAL(buf,NE_HEADER_MAJOR_VER_OFFSET)));
+ goto error_exit;
+ }
+ } else {
+ DEBUG(6,("get_correct_cversion: NE formatted file [%s] wrong target OS = 0x%x\n",
+ driverpath, CVAL(buf,NE_HEADER_TARGET_OS_OFFSET)));
+ goto error_exit;
+ }
+
+ } else {
+ DEBUG(6,("get_correct_cversion: Unknown file format [%s], signature = 0x%x\n",
+ driverpath, IVAL(buf,PE_HEADER_SIGNATURE_OFFSET)));
+ goto error_exit;
+ }
+
+ DEBUG(10,("get_correct_cversion: Driver file [%s] cversion = %d\n",
+ driverpath, cversion));
+ return cversion;
+
+
+ error_exit:
+ if(fd != -1)
+ close(fd);
+ return -1;
+}
+
+/****************************************************************************
+****************************************************************************/
+static uint32 clean_up_driver_struct_level_3(NT_PRINTER_DRIVER_INFO_LEVEL_3 *driver)
+{
+ fstring architecture;
+ fstring new_name;
+ char *p;
+ int i;
/* clean up the driver name.
* we can get .\driver.dll
@@ -404,20 +497,12 @@ static void clean_up_driver_struct_level_3(NT_PRINTER_DRIVER_INFO_LEVEL_3 *drive
}
}
}
-}
-/****************************************************************************
-****************************************************************************/
-static void clean_up_driver_struct_level_6(NT_PRINTER_DRIVER_INFO_LEVEL_6 *driver)
-{
- fstring architecture;
- fstring new_name;
- char *p;
- int i;
+ get_short_archi(architecture, driver->environment);
/* jfm:7/16/2000 the client always sends the cversion=0.
- * The server should check which version the driver is by reading the PE header
- * of driver->driverpath.
+ * The server should check which version the driver is by reading
+ * the PE header of driver->driverpath.
*
* For Windows 95/98 the version is 0 (so the value sent is correct)
* For Windows NT (the architecture doesn't matter)
@@ -426,17 +511,21 @@ static void clean_up_driver_struct_level_6(NT_PRINTER_DRIVER_INFO_LEVEL_6 *drive
* NT 4: cversion=2
* NT2K: cversion=3
*/
+ if ((driver->cversion = get_correct_cversion(architecture,
+ driver->driverpath)) == -1)
+ return ERROR_INVALID_PARAMETER; /* Not the best error. Fix JRR */
- get_short_archi(architecture, driver->environment);
-
- /* if it's Windows 95/98, we keep the version at 0
- * jfmxxx: I need to redo that more correctly for NT2K.
- */
+ return NT_STATUS_NO_PROBLEMO;
+}
- if (StrCaseCmp(driver->environment, "Windows 4.0")==0)
- driver->version=0;
- else
- driver->version=2;
+/****************************************************************************
+****************************************************************************/
+static uint32 clean_up_driver_struct_level_6(NT_PRINTER_DRIVER_INFO_LEVEL_6 *driver)
+{
+ fstring architecture;
+ fstring new_name;
+ char *p;
+ int i;
/* clean up the driver name.
* we can get .\driver.dll
@@ -471,6 +560,25 @@ static void clean_up_driver_struct_level_6(NT_PRINTER_DRIVER_INFO_LEVEL_6 *drive
}
}
}
+
+ get_short_archi(architecture, driver->environment);
+
+ /* jfm:7/16/2000 the client always sends the cversion=0.
+ * The server should check which version the driver is by reading
+ * the PE header of driver->driverpath.
+ *
+ * For Windows 95/98 the version is 0 (so the value sent is correct)
+ * For Windows NT (the architecture doesn't matter)
+ * NT 3.1: cversion=0
+ * NT 3.5/3.51: cversion=1
+ * NT 4: cversion=2
+ * NT2K: cversion=3
+ */
+ if ((driver->version = get_correct_cversion(architecture,
+ driver->driverpath)) == -1)
+ return ERROR_INVALID_PARAMETER; /* Not the best error. Fix JRR */
+
+ return NT_STATUS_NO_PROBLEMO;
}
/****************************************************************************
@@ -514,6 +622,7 @@ static void convert_level_6_to_level3(NT_PRINTER_DRIVER_INFO_LEVEL_3 *dst, NT_PR
dst->dependentfiles = src->dependentfiles;
}
+
/****************************************************************************
****************************************************************************/
BOOL move_driver_to_download_area(NT_PRINTER_DRIVER_INFO_LEVEL driver_abstract, uint32 level, struct current_user *user, uint32 *perr)
@@ -607,6 +716,8 @@ BOOL move_driver_to_download_area(NT_PRINTER_DRIVER_INFO_LEVEL driver_abstract,
*/
DEBUG(5,("Moving file now !\n"));
+
+ if (driver->driverpath && strlen(driver->driverpath)) {
slprintf(old_name, sizeof(old_name), "%s\\%s", architecture, driver->driverpath);
slprintf(new_name, sizeof(new_name), "%s\\%s", new_dir, driver->driverpath);
if ((outsize = rename_internals(conn, inbuf, outbuf, old_name, new_name, True)) != 0) {
@@ -617,7 +728,9 @@ BOOL move_driver_to_download_area(NT_PRINTER_DRIVER_INFO_LEVEL driver_abstract,
*perr = (uint32)SVAL(outbuf,smb_err);
return False;
}
+ }
+ if (driver->datafile && strlen(driver->datafile)) {
if (!strequal(driver->datafile, driver->driverpath)) {
slprintf(old_name, sizeof(old_name), "%s\\%s", architecture, driver->datafile);
slprintf(new_name, sizeof(new_name), "%s\\%s", new_dir, driver->datafile);
@@ -630,7 +743,9 @@ BOOL move_driver_to_download_area(NT_PRINTER_DRIVER_INFO_LEVEL driver_abstract,
return False;
}
}
+ }
+ if (driver->configfile && strlen(driver->configfile)) {
if (!strequal(driver->configfile, driver->driverpath) &&
!strequal(driver->configfile, driver->datafile)) {
slprintf(old_name, sizeof(old_name), "%s\\%s", architecture, driver->configfile);
@@ -644,7 +759,9 @@ BOOL move_driver_to_download_area(NT_PRINTER_DRIVER_INFO_LEVEL driver_abstract,
return False;
}
}
+ }
+ if (driver->helpfile && strlen(driver->helpfile)) {
if (!strequal(driver->helpfile, driver->driverpath) &&
!strequal(driver->helpfile, driver->datafile) &&
!strequal(driver->helpfile, driver->configfile)) {
@@ -659,6 +776,7 @@ BOOL move_driver_to_download_area(NT_PRINTER_DRIVER_INFO_LEVEL driver_abstract,
return False;
}
}
+ }
if (driver->dependentfiles) {
for (i=0; *driver->dependentfiles[i]; i++) {
@@ -848,17 +966,6 @@ static uint32 get_a_printer_driver_3(NT_PRINTER_DRIVER_INFO_LEVEL_3 **info_ptr,
get_short_archi(architecture, in_arch);
- /*
- * Note - the version sent here for Win2k is probably (3). Due to the
- * hack done in clean_up_driver_struct_level_3() we need to
- * do the same hack so we can find the correctly stored driver. JRA.
- */
-
- if (StrCaseCmp(in_arch, "Windows 4.0")==0)
- version=0;
- else
- version=2;
-
DEBUG(8,("get_a_printer_driver_3: [%s%s/%d/%s]\n", DRIVERS_PREFIX, architecture, version, in_prt));
slprintf(key, sizeof(key), "%s%s/%d/%s", DRIVERS_PREFIX, architecture, version, in_prt);