From 7a9a320f87408a775d481ec363fbc666a49e8aea Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Mon, 30 Apr 2018 11:57:52 -0700 Subject: [PATCH 01/13] s3: printing: Reformatting of parts of this file to modern coding standards. This should not change the code behavior in any way, it is just being done to make it easier for me to move this code to calling the standard read_file() function later on, which takes a file offset to read from (and uses pread internally). Signed-off-by: Jeremy Allison --- source3/printing/nt_printing.c | 370 +++++++++++++++++++++++---------- 1 file changed, 264 insertions(+), 106 deletions(-) diff --git a/source3/printing/nt_printing.c b/source3/printing/nt_printing.c index bf54fd4e6b3..7a7a78b59e2 100644 --- a/source3/printing/nt_printing.c +++ b/source3/printing/nt_printing.c @@ -316,7 +316,9 @@ const char *get_short_archi(const char *long_archi) (note: EINTR re-read differs from vfs_write_data) ****************************************************************************/ -static ssize_t vfs_read_data(files_struct *fsp, char *buf, size_t byte_count) +static ssize_t vfs_read_data(files_struct *fsp, + char *buf, + size_t byte_count) { size_t total=0; @@ -347,128 +349,223 @@ static ssize_t vfs_read_data(files_struct *fsp, char *buf, size_t byte_count) returns -1 on error, 1 on version info found, and 0 on no version info found. ****************************************************************************/ -static int get_file_version(files_struct *fsp, char *fname,uint32_t *major, uint32_t *minor) +static int get_file_version(files_struct *fsp, + char *fname, + uint32_t *major, + uint32_t *minor) { int i; char *buf = NULL; ssize_t byte_count; - - if ((buf=(char *)SMB_MALLOC(DOS_HEADER_SIZE)) == NULL) { - DEBUG(0,("get_file_version: PE file [%s] DOS Header malloc failed bytes = %d\n", - fname, DOS_HEADER_SIZE)); + off_t pos; + off_t oret; + + buf=(char *)SMB_MALLOC(DOS_HEADER_SIZE); + if (buf == NULL) { + DBG_ERR("PE file [%s] DOS Header malloc failed bytes = %d\n", + fname, + DOS_HEADER_SIZE); goto error_exit; } - if ((byte_count = vfs_read_data(fsp, buf, DOS_HEADER_SIZE)) < DOS_HEADER_SIZE) { - DEBUG(3,("get_file_version: File [%s] DOS header too short, bytes read = %lu\n", - fname, (unsigned long)byte_count)); + byte_count = vfs_read_data(fsp, buf, DOS_HEADER_SIZE); + if (byte_count < DOS_HEADER_SIZE) { + DBG_NOTICE("File [%s] DOS header too short, bytes read = %lu\n", + fname, + (unsigned long)byte_count); goto no_version_info; } /* Is this really a DOS header? */ if (SVAL(buf,DOS_HEADER_MAGIC_OFFSET) != DOS_HEADER_MAGIC) { - DEBUG(6,("get_file_version: File [%s] bad DOS magic = 0x%x\n", - fname, SVAL(buf,DOS_HEADER_MAGIC_OFFSET))); + DBG_INFO("File [%s] bad DOS magic = 0x%x\n", + fname, + SVAL(buf,DOS_HEADER_MAGIC_OFFSET)); goto no_version_info; } - /* Skip OEM header (if any) and the DOS stub to start of Windows header */ - if (SMB_VFS_LSEEK(fsp, SVAL(buf,DOS_HEADER_LFANEW_OFFSET), SEEK_SET) == (off_t)-1) { - DEBUG(3,("get_file_version: File [%s] too short, errno = %d\n", - fname, errno)); - /* Assume this isn't an error... the file just looks sort of like a PE/NE file */ + /* + * Skip OEM header (if any) and the + * DOS stub to start of Windows header. + */ + pos = SVAL(buf,DOS_HEADER_LFANEW_OFFSET); + oret = SMB_VFS_LSEEK(fsp, pos, SEEK_SET); + if (oret == (off_t)-1) { + DBG_NOTICE("File [%s] too short, errno = %d\n", + fname, + errno); + /* + * Assume this isn't an error... + * the file just looks sort of like a PE/NE file. + */ goto no_version_info; } /* Note: DOS_HEADER_SIZE and NE_HEADER_SIZE are incidentally same */ - if ((byte_count = vfs_read_data(fsp, buf, NE_HEADER_SIZE)) < NE_HEADER_SIZE) { - DEBUG(3,("get_file_version: File [%s] Windows header too short, bytes read = %lu\n", - fname, (unsigned long)byte_count)); - /* Assume this isn't an error... the file just looks sort of like a PE/NE file */ + byte_count = vfs_read_data(fsp, buf, NE_HEADER_SIZE); + if (byte_count < NE_HEADER_SIZE) { + DBG_NOTICE("File [%s] Windows header too short, " + "bytes read = %lu\n", + fname, + (unsigned long)byte_count); + /* + * Assume this isn't an error... + * the file just looks sort of like a PE/NE file + */ goto no_version_info; } - /* The header may be a PE (Portable Executable) or an NE (New Executable) */ + /* + * The header may be a PE (Portable Executable) + * or an NE (New Executable). + */ if (IVAL(buf,PE_HEADER_SIGNATURE_OFFSET) == PE_HEADER_SIGNATURE) { unsigned int num_sections; unsigned int section_table_bytes; /* Just skip over optional header to get to section table */ - if (SMB_VFS_LSEEK(fsp, - SVAL(buf,PE_HEADER_OPTIONAL_HEADER_SIZE)-(NE_HEADER_SIZE-PE_HEADER_SIZE), - SEEK_CUR) == (off_t)-1) { - DEBUG(3,("get_file_version: File [%s] Windows optional header too short, errno = %d\n", - fname, errno)); + pos = SVAL(buf,PE_HEADER_OPTIONAL_HEADER_SIZE)- + (NE_HEADER_SIZE-PE_HEADER_SIZE); + + oret = SMB_VFS_LSEEK(fsp, pos, SEEK_CUR); + if (oret == (off_t)-1) { + DBG_NOTICE("File [%s] Windows optional header " + "too short, errno = %d\n", + fname, + errno); goto error_exit; } /* get the section table */ num_sections = SVAL(buf,PE_HEADER_NUMBER_OF_SECTIONS); section_table_bytes = num_sections * PE_HEADER_SECT_HEADER_SIZE; - if (section_table_bytes == 0) + if (section_table_bytes == 0) { goto error_exit; + } SAFE_FREE(buf); - if ((buf=(char *)SMB_MALLOC(section_table_bytes)) == NULL) { - DEBUG(0,("get_file_version: PE file [%s] section table malloc failed bytes = %d\n", - fname, section_table_bytes)); + buf = (char *)SMB_MALLOC(section_table_bytes); + if (buf == NULL) { + DBG_ERR("PE file [%s] section table malloc " + "failed bytes = %d\n", + fname, + section_table_bytes); goto error_exit; } - if ((byte_count = vfs_read_data(fsp, buf, section_table_bytes)) < section_table_bytes) { - DEBUG(3,("get_file_version: PE file [%s] Section header too short, bytes read = %lu\n", - fname, (unsigned long)byte_count)); + byte_count = vfs_read_data(fsp, buf, section_table_bytes); + if (byte_count < section_table_bytes) { + DBG_NOTICE("PE file [%s] " + "Section header too short, bytes read = %lu\n", + fname, + (unsigned long)byte_count); goto error_exit; } - /* Iterate the section table looking for the resource section ".rsrc" */ + /* + * Iterate the section table looking for + * the resource section ".rsrc" + */ for (i = 0; i < num_sections; i++) { int sec_offset = i * PE_HEADER_SECT_HEADER_SIZE; - if (strcmp(".rsrc", &buf[sec_offset+PE_HEADER_SECT_NAME_OFFSET]) == 0) { - unsigned int section_pos = IVAL(buf,sec_offset+PE_HEADER_SECT_PTR_DATA_OFFSET); - unsigned int section_bytes = IVAL(buf,sec_offset+PE_HEADER_SECT_SIZE_DATA_OFFSET); - - if (section_bytes == 0) + if (strcmp(".rsrc", + &buf[sec_offset+ + PE_HEADER_SECT_NAME_OFFSET]) + == 0) { + unsigned int section_pos = + IVAL(buf, + sec_offset+ + PE_HEADER_SECT_PTR_DATA_OFFSET); + unsigned int section_bytes = + IVAL(buf, + sec_offset+ + PE_HEADER_SECT_SIZE_DATA_OFFSET); + + if (section_bytes == 0) { goto error_exit; + } SAFE_FREE(buf); - if ((buf=(char *)SMB_MALLOC(section_bytes)) == NULL) { - DEBUG(0,("get_file_version: PE file [%s] version malloc failed bytes = %d\n", - fname, section_bytes)); + buf=(char *)SMB_MALLOC(section_bytes); + if (buf == NULL) { + DBG_ERR("PE file [%s] version malloc " + "failed bytes = %d\n", + fname, + section_bytes); goto error_exit; } - /* Seek to the start of the .rsrc section info */ - if (SMB_VFS_LSEEK(fsp, section_pos, SEEK_SET) == (off_t)-1) { - DEBUG(3,("get_file_version: PE file [%s] too short for section info, errno = %d\n", - fname, errno)); + /* + * Seek to the start of the .rsrc + * section info + */ + oret = SMB_VFS_LSEEK(fsp, + section_pos, + SEEK_SET); + if (oret == (off_t)-1) { + DBG_NOTICE("PE file [%s] too short for " + "section info, errno = %d\n", + fname, + errno); goto error_exit; } - if ((byte_count = vfs_read_data(fsp, buf, section_bytes)) < section_bytes) { - DEBUG(3,("get_file_version: PE file [%s] .rsrc section too short, bytes read = %lu\n", - fname, (unsigned long)byte_count)); + byte_count = vfs_read_data(fsp, + buf, + section_bytes); + if (byte_count < section_bytes) { + DBG_NOTICE("PE file " + "[%s] .rsrc section too short, " + "bytes read = %lu\n", + fname, + (unsigned long)byte_count); goto error_exit; } - if (section_bytes < VS_VERSION_INFO_UNICODE_SIZE) + if (section_bytes < + VS_VERSION_INFO_UNICODE_SIZE) { goto error_exit; + } - for (i=0; i>16)&0xffff, *major&0xffff, - (*minor>>16)&0xffff, *minor&0xffff)); + int mpos = + (i + + sizeof(VS_SIGNATURE)*2 + + 3) & 0xfffffffc; + + if (IVAL(buf,mpos) == + VS_MAGIC_VALUE) { + *major = IVAL(buf, + mpos+ + VS_MAJOR_OFFSET); + *minor = IVAL(buf, + mpos+ + VS_MINOR_OFFSET); + + DBG_INFO("PE file [%s] " + "Version = " + "%08x:%08x " + "(%d.%d.%d.%d)\n", + fname, + *major, + *minor, + (*major>>16)&0xffff, + *major&0xffff, + (*minor>>16)&0xffff, + *minor&0xffff); SAFE_FREE(buf); return 1; } @@ -478,40 +575,68 @@ static int get_file_version(files_struct *fsp, char *fname,uint32_t *major, uint } /* Version info not found, fall back to origin date/time */ - DEBUG(10,("get_file_version: PE file [%s] has no version info\n", fname)); + DBG_DEBUG("PE file [%s] has no version info\n", fname); SAFE_FREE(buf); return 0; - } else if (SVAL(buf,NE_HEADER_SIGNATURE_OFFSET) == NE_HEADER_SIGNATURE) { - if (CVAL(buf,NE_HEADER_TARGET_OS_OFFSET) != NE_HEADER_TARGOS_WIN ) { - DEBUG(3,("get_file_version: NE file [%s] wrong target OS = 0x%x\n", - fname, CVAL(buf,NE_HEADER_TARGET_OS_OFFSET))); - /* At this point, we assume the file is in error. It still could be something - * else besides a NE file, but it unlikely at this point. */ + } else if (SVAL(buf,NE_HEADER_SIGNATURE_OFFSET) == + NE_HEADER_SIGNATURE) { + if (CVAL(buf,NE_HEADER_TARGET_OS_OFFSET) != + NE_HEADER_TARGOS_WIN ) { + DBG_NOTICE("NE file [%s] wrong target OS = 0x%x\n", + fname, + CVAL(buf,NE_HEADER_TARGET_OS_OFFSET)); + /* + * At this point, we assume the file is in error. + * It still could be something else besides a NE file, + * but it unlikely at this point. + */ goto error_exit; } /* Allocate a bit more space to speed up things */ SAFE_FREE(buf); - if ((buf=(char *)SMB_MALLOC(VS_NE_BUF_SIZE)) == NULL) { - DEBUG(0,("get_file_version: NE file [%s] malloc failed bytes = %d\n", - fname, PE_HEADER_SIZE)); + buf=(char *)SMB_MALLOC(VS_NE_BUF_SIZE); + if (buf == NULL) { + DBG_ERR("NE file [%s] malloc failed bytes = %d\n", + fname, + PE_HEADER_SIZE); goto error_exit; } - /* This is a HACK! I got tired of trying to sort through the messy - * 'NE' file format. If anyone wants to clean this up please have at - * it, but this works. 'NE' files will eventually fade away. JRR */ - while((byte_count = vfs_read_data(fsp, buf, VS_NE_BUF_SIZE)) > 0) { - /* Cover case that should not occur in a well formed 'NE' .dll file */ - if (byte_count-VS_VERSION_INFO_SIZE <= 0) break; + /* + * This is a HACK! I got tired of trying to sort through the + * messy 'NE' file format. If anyone wants to clean this up + * please have at it, but this works. 'NE' files will + * eventually fade away. JRR + */ + byte_count = vfs_read_data(fsp, buf, VS_NE_BUF_SIZE); + while (byte_count > 0) { + /* + * Cover case that should not occur in a well + * formed 'NE' .dll file + */ + if (byte_count-VS_VERSION_INFO_SIZE <= 0) { + break; + } for(i=0; ibyte_count-VS_VERSION_INFO_SIZE) { ssize_t amount_read; ssize_t amount_unused = byte_count-i; @@ -521,9 +646,10 @@ static int get_file_version(files_struct *fsp, char *fname,uint32_t *major, uint &buf[amount_unused], VS_NE_BUF_SIZE- amount_unused); if (amount_read < 0) { - - DEBUG(0,("get_file_version: NE file [%s] Read error, errno=%d\n", - fname, errno)); + DBG_ERR("NE file [%s] Read " + "error, errno=%d\n", + fname, + errno); goto error_exit; } @@ -542,22 +668,49 @@ static int get_file_version(files_struct *fsp, char *fname,uint32_t *major, uint i = 0; } - /* Check that the full signature string and the magic number that - * follows exist (not a perfect solution, but the chances that this - * occurs in code is, well, remote. Yes I know I'm comparing the 'V' - * twice, as it is simpler to read the code. */ + /* + * Check that the full signature string and + * the magic number that follows exist (not + * a perfect solution, but the chances that this + * occurs in code is, well, remote. Yes I know + * I'm comparing the 'V' twice, as it is + * simpler to read the code. + */ if (strcmp(&buf[i], VS_SIGNATURE) == 0) { - /* Compute skip alignment to next long address */ - int skip = -(SMB_VFS_LSEEK(fsp, 0, SEEK_CUR) - (byte_count - i) + - sizeof(VS_SIGNATURE)) & 3; - if (IVAL(buf,i+sizeof(VS_SIGNATURE)+skip) != 0xfeef04bd) continue; - - *major = IVAL(buf,i+sizeof(VS_SIGNATURE)+skip+VS_MAJOR_OFFSET); - *minor = IVAL(buf,i+sizeof(VS_SIGNATURE)+skip+VS_MINOR_OFFSET); - DEBUG(6,("get_file_version: NE file [%s] Version = %08x:%08x (%d.%d.%d.%d)\n", - fname, *major, *minor, - (*major>>16)&0xffff, *major&0xffff, - (*minor>>16)&0xffff, *minor&0xffff)); + /* + * Compute skip alignment to next + * long address. + */ + off_t cpos = SMB_VFS_LSEEK(fsp, + 0, + SEEK_CUR); + + int skip = -(cpos - (byte_count - i) + + sizeof(VS_SIGNATURE)) & 3; + if (IVAL(buf, + i+sizeof(VS_SIGNATURE)+skip) + != 0xfeef04bd) { + byte_count = vfs_read_data(fsp, + buf, + VS_NE_BUF_SIZE); + continue; + } + + *major = IVAL(buf, + i+sizeof(VS_SIGNATURE)+ + skip+VS_MAJOR_OFFSET); + *minor = IVAL(buf, + i+sizeof(VS_SIGNATURE)+ + skip+VS_MINOR_OFFSET); + DBG_INFO("NE file [%s] Version " + "= %08x:%08x (%d.%d.%d.%d)\n", + fname, + *major, + *minor, + (*major>>16)&0xffff, + *major&0xffff, + (*minor>>16)&0xffff, + *minor&0xffff); SAFE_FREE(buf); return 1; } @@ -565,14 +718,19 @@ static int get_file_version(files_struct *fsp, char *fname,uint32_t *major, uint } /* Version info not found, fall back to origin date/time */ - DEBUG(0,("get_file_version: NE file [%s] Version info not found\n", fname)); + DBG_ERR("NE file [%s] Version info not found\n", fname); SAFE_FREE(buf); return 0; - } else - /* Assume this isn't an error... the file just looks sort of like a PE/NE file */ - DEBUG(3,("get_file_version: File [%s] unknown file format, signature = 0x%x\n", - fname, IVAL(buf,PE_HEADER_SIGNATURE_OFFSET))); + } else { + /* + * Assume this isn't an error... the file just + * looks sort of like a PE/NE file. + */ + DBG_NOTICE("File [%s] unknown file format, signature = 0x%x\n", + fname, + IVAL(buf,PE_HEADER_SIGNATURE_OFFSET)); + } no_version_info: SAFE_FREE(buf); -- 2.17.0.441.gb46fe60e1d-goog From 1151b3e5e1ceab1aa4b710e3088652085e68b702 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Mon, 30 Apr 2018 15:06:39 -0700 Subject: [PATCH 02/13] s3: printing: Split handling of PE file into separate function. This is *horrible* old code... Signed-off-by: Jeremy Allison --- source3/printing/nt_printing.c | 347 ++++++++++++++++++--------------- 1 file changed, 188 insertions(+), 159 deletions(-) diff --git a/source3/printing/nt_printing.c b/source3/printing/nt_printing.c index 7a7a78b59e2..55720350dcc 100644 --- a/source3/printing/nt_printing.c +++ b/source3/printing/nt_printing.c @@ -341,6 +341,189 @@ static ssize_t vfs_read_data(files_struct *fsp, return (ssize_t)total; } +/**************************************************************************** + Detect the major and minor version of a PE file. + Returns: + + 1 if file is a PE file and we got version numbers, + 0 if this file is a PE file and we couldn't get the version numbers, + -1 on error. + + NB. buf is passed into and freed inside this function. This is a + bad API design, but fixing this is a task for another day. +****************************************************************************/ + +static int handle_pe_file(files_struct *fsp, + char *fname, + char *buf, + uint32_t *major, + uint32_t *minor) +{ + unsigned int i; + unsigned int num_sections; + unsigned int section_table_bytes; + ssize_t byte_count; + off_t oret; + off_t pos; + int ret = -1; + + /* Just skip over optional header to get to section table */ + pos = SVAL(buf,PE_HEADER_OPTIONAL_HEADER_SIZE)- + (NE_HEADER_SIZE-PE_HEADER_SIZE); + + oret = SMB_VFS_LSEEK(fsp, pos, SEEK_CUR); + if (oret == (off_t)-1) { + DBG_NOTICE("File [%s] Windows optional header " + "too short, errno = %d\n", + fname, + errno); + goto out; + } + + /* get the section table */ + num_sections = SVAL(buf,PE_HEADER_NUMBER_OF_SECTIONS); + section_table_bytes = num_sections * PE_HEADER_SECT_HEADER_SIZE; + if (section_table_bytes == 0) { + goto out; + } + + SAFE_FREE(buf); + buf = (char *)SMB_MALLOC(section_table_bytes); + if (buf == NULL) { + DBG_ERR("PE file [%s] section table malloc " + "failed bytes = %d\n", + fname, + section_table_bytes); + goto out; + } + + byte_count = vfs_read_data(fsp, buf, section_table_bytes); + if (byte_count < section_table_bytes) { + DBG_NOTICE("PE file [%s] Section header too short, " + "bytes read = %lu\n", + fname, + (unsigned long)byte_count); + goto out; + } + + /* + * Iterate the section table looking for + * the resource section ".rsrc" + */ + for (i = 0; i < num_sections; i++) { + int sec_offset = i * PE_HEADER_SECT_HEADER_SIZE; + + if (strcmp(".rsrc", + &buf[sec_offset+ PE_HEADER_SECT_NAME_OFFSET]) == 0) { + unsigned int section_pos = IVAL(buf, + sec_offset+ + PE_HEADER_SECT_PTR_DATA_OFFSET); + unsigned int section_bytes = IVAL(buf, + sec_offset+ + PE_HEADER_SECT_SIZE_DATA_OFFSET); + + if (section_bytes == 0) { + goto out; + } + + SAFE_FREE(buf); + buf=(char *)SMB_MALLOC(section_bytes); + if (buf == NULL) { + DBG_ERR("PE file [%s] version malloc " + "failed bytes = %d\n", + fname, + section_bytes); + goto out; + } + + /* + * Seek to the start of the .rsrc + * section info + */ + oret = SMB_VFS_LSEEK(fsp, + section_pos, + SEEK_SET); + if (oret == (off_t)-1) { + DBG_NOTICE("PE file [%s] too short for " + "section info, errno = %d\n", + fname, + errno); + goto out; + } + + byte_count = vfs_read_data(fsp, + buf, + section_bytes); + if (byte_count < section_bytes) { + DBG_NOTICE("PE file " + "[%s] .rsrc section too short, " + "bytes read = %lu\n", + fname, + (unsigned long)byte_count); + goto out; + } + + if (section_bytes < VS_VERSION_INFO_UNICODE_SIZE) { + goto out; + } + + for (i=0; + i< section_bytes - VS_VERSION_INFO_UNICODE_SIZE; + i++) { + /* + * Scan for 1st 3 unicoded bytes + * followed by word aligned magic + * value. + */ + int mpos; + bool magic_match = false; + + if (buf[i] == 'V' && + buf[i+1] == '\0' && + buf[i+2] == 'S') { + magic_match = true; + } + + if (magic_match == false) { + continue; + } + + /* Align to next long address */ + mpos = (i + sizeof(VS_SIGNATURE)*2 + + 3) & 0xfffffffc; + + if (IVAL(buf,mpos) == VS_MAGIC_VALUE) { + *major = IVAL(buf, + mpos+ VS_MAJOR_OFFSET); + *minor = IVAL(buf, + mpos+ VS_MINOR_OFFSET); + + DBG_INFO("PE file [%s] Version = " + "%08x:%08x (%d.%d.%d.%d)\n", + fname, + *major, + *minor, + (*major>>16)&0xffff, + *major&0xffff, + (*minor>>16)&0xffff, + *minor&0xffff); + ret = 1; + goto out; + } + } + } + } + + /* Version info not found, fall back to origin date/time */ + DBG_DEBUG("PE file [%s] has no version info\n", fname); + ret = 0; + + out: + + SAFE_FREE(buf); + return ret; +} + /**************************************************************************** Version information in Microsoft files is held in a VS_VERSION_INFO structure. There are two case to be covered here: PE (Portable Executable) and NE (New @@ -420,165 +603,11 @@ static int get_file_version(files_struct *fsp, * or an NE (New Executable). */ if (IVAL(buf,PE_HEADER_SIGNATURE_OFFSET) == PE_HEADER_SIGNATURE) { - unsigned int num_sections; - unsigned int section_table_bytes; - - /* Just skip over optional header to get to section table */ - pos = SVAL(buf,PE_HEADER_OPTIONAL_HEADER_SIZE)- - (NE_HEADER_SIZE-PE_HEADER_SIZE); - - oret = SMB_VFS_LSEEK(fsp, pos, SEEK_CUR); - if (oret == (off_t)-1) { - DBG_NOTICE("File [%s] Windows optional header " - "too short, errno = %d\n", - fname, - errno); - goto error_exit; - } - - /* get the section table */ - num_sections = SVAL(buf,PE_HEADER_NUMBER_OF_SECTIONS); - section_table_bytes = num_sections * PE_HEADER_SECT_HEADER_SIZE; - if (section_table_bytes == 0) { - goto error_exit; - } - - SAFE_FREE(buf); - buf = (char *)SMB_MALLOC(section_table_bytes); - if (buf == NULL) { - DBG_ERR("PE file [%s] section table malloc " - "failed bytes = %d\n", - fname, - section_table_bytes); - goto error_exit; - } - - byte_count = vfs_read_data(fsp, buf, section_table_bytes); - if (byte_count < section_table_bytes) { - DBG_NOTICE("PE file [%s] " - "Section header too short, bytes read = %lu\n", - fname, - (unsigned long)byte_count); - goto error_exit; - } - - /* - * Iterate the section table looking for - * the resource section ".rsrc" - */ - for (i = 0; i < num_sections; i++) { - int sec_offset = i * PE_HEADER_SECT_HEADER_SIZE; - - if (strcmp(".rsrc", - &buf[sec_offset+ - PE_HEADER_SECT_NAME_OFFSET]) - == 0) { - unsigned int section_pos = - IVAL(buf, - sec_offset+ - PE_HEADER_SECT_PTR_DATA_OFFSET); - unsigned int section_bytes = - IVAL(buf, - sec_offset+ - PE_HEADER_SECT_SIZE_DATA_OFFSET); - - if (section_bytes == 0) { - goto error_exit; - } - - SAFE_FREE(buf); - buf=(char *)SMB_MALLOC(section_bytes); - if (buf == NULL) { - DBG_ERR("PE file [%s] version malloc " - "failed bytes = %d\n", - fname, - section_bytes); - goto error_exit; - } - - /* - * Seek to the start of the .rsrc - * section info - */ - oret = SMB_VFS_LSEEK(fsp, - section_pos, - SEEK_SET); - if (oret == (off_t)-1) { - DBG_NOTICE("PE file [%s] too short for " - "section info, errno = %d\n", - fname, - errno); - goto error_exit; - } - - byte_count = vfs_read_data(fsp, - buf, - section_bytes); - if (byte_count < section_bytes) { - DBG_NOTICE("PE file " - "[%s] .rsrc section too short, " - "bytes read = %lu\n", - fname, - (unsigned long)byte_count); - goto error_exit; - } - - if (section_bytes < - VS_VERSION_INFO_UNICODE_SIZE) { - goto error_exit; - } - - for (i=0; - i< section_bytes- - VS_VERSION_INFO_UNICODE_SIZE; - i++) { - /* - * Scan for 1st 3 unicoded bytes - * followed by word aligned magic - * value. - */ - if (buf[i] == 'V' && - buf[i+1] == '\0' && - buf[i+2] == 'S') { - /* Align to next long address */ - int mpos = - (i + - sizeof(VS_SIGNATURE)*2 + - 3) & 0xfffffffc; - - if (IVAL(buf,mpos) == - VS_MAGIC_VALUE) { - *major = IVAL(buf, - mpos+ - VS_MAJOR_OFFSET); - *minor = IVAL(buf, - mpos+ - VS_MINOR_OFFSET); - - DBG_INFO("PE file [%s] " - "Version = " - "%08x:%08x " - "(%d.%d.%d.%d)\n", - fname, - *major, - *minor, - (*major>>16)&0xffff, - *major&0xffff, - (*minor>>16)&0xffff, - *minor&0xffff); - SAFE_FREE(buf); - return 1; - } - } - } - } - } - - /* Version info not found, fall back to origin date/time */ - DBG_DEBUG("PE file [%s] has no version info\n", fname); - SAFE_FREE(buf); - return 0; - + return handle_pe_file(fsp, + fname, + buf, + major, + minor); } else if (SVAL(buf,NE_HEADER_SIGNATURE_OFFSET) == NE_HEADER_SIGNATURE) { if (CVAL(buf,NE_HEADER_TARGET_OS_OFFSET) != -- 2.17.0.441.gb46fe60e1d-goog From a2a63a958676b845e244c5934e35db919b45fa6a Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Mon, 30 Apr 2018 15:50:14 -0700 Subject: [PATCH 03/13] s3: printing: Move handle_ne_file code into a separate function. Signed-off-by: Jeremy Allison --- source3/printing/nt_printing.c | 315 ++++++++++++++++++--------------- 1 file changed, 173 insertions(+), 142 deletions(-) diff --git a/source3/printing/nt_printing.c b/source3/printing/nt_printing.c index 55720350dcc..65172a75084 100644 --- a/source3/printing/nt_printing.c +++ b/source3/printing/nt_printing.c @@ -524,6 +524,173 @@ static int handle_pe_file(files_struct *fsp, return ret; } +/**************************************************************************** + Detect the major and minor version of an NE file. + Returns: + + 1 if file is an NE file and we got version numbers, + 0 if this file is an NE file and we couldn't get the version numbers, + -1 on error. + + NB. buf is passed into and freed inside this function. This is a + bad API design, but fixing this is a task for another day. +****************************************************************************/ + +static int handle_ne_file(files_struct *fsp, + char *fname, + char *buf, + uint32_t *major, + uint32_t *minor) +{ + unsigned int i; + ssize_t byte_count; + int ret = -1; + + if (CVAL(buf,NE_HEADER_TARGET_OS_OFFSET) != NE_HEADER_TARGOS_WIN ) { + DBG_NOTICE("NE file [%s] wrong target OS = 0x%x\n", + fname, + CVAL(buf,NE_HEADER_TARGET_OS_OFFSET)); + /* + * At this point, we assume the file is in error. + * It still could be something else besides a NE file, + * but it unlikely at this point. + */ + goto out; + } + + /* Allocate a bit more space to speed up things */ + SAFE_FREE(buf); + buf=(char *)SMB_MALLOC(VS_NE_BUF_SIZE); + if (buf == NULL) { + DBG_ERR("NE file [%s] malloc failed bytes = %d\n", + fname, + PE_HEADER_SIZE); + goto out; + } + + /* + * This is a HACK! I got tired of trying to sort through the + * messy 'NE' file format. If anyone wants to clean this up + * please have at it, but this works. 'NE' files will + * eventually fade away. JRR + */ + byte_count = vfs_read_data(fsp, buf, VS_NE_BUF_SIZE); + while (byte_count > 0) { + /* + * Cover case that should not occur in a well + * formed 'NE' .dll file + */ + if (byte_count-VS_VERSION_INFO_SIZE <= 0) { + break; + } + + for(i=0; ibyte_count-VS_VERSION_INFO_SIZE) { + ssize_t amount_read; + ssize_t amount_unused = byte_count-i; + + memmove(buf, &buf[i], amount_unused); + amount_read = vfs_read_data(fsp, + &buf[amount_unused], + VS_NE_BUF_SIZE- amount_unused); + if (amount_read < 0) { + DBG_ERR("NE file [%s] Read " + "error, errno=%d\n", + fname, + errno); + goto out; + } + + if (amount_read + amount_unused < + amount_read) { + /* Check for integer wrap. */ + break; + } + + byte_count = amount_read + + amount_unused; + if (byte_count < VS_VERSION_INFO_SIZE) { + break; + } + + i = 0; + } + + /* + * Check that the full signature string and + * the magic number that follows exist (not + * a perfect solution, but the chances that this + * occurs in code is, well, remote. Yes I know + * I'm comparing the 'V' twice, as it is + * simpler to read the code. + */ + if (strcmp(&buf[i], VS_SIGNATURE) == 0) { + /* + * Compute skip alignment to next + * long address. + */ + off_t cpos = SMB_VFS_LSEEK(fsp, + 0, + SEEK_CUR); + + int skip = -(cpos - (byte_count - i) + + sizeof(VS_SIGNATURE)) & 3; + if (IVAL(buf, + i+sizeof(VS_SIGNATURE)+skip) + != 0xfeef04bd) { + byte_count = vfs_read_data(fsp, + buf, + VS_NE_BUF_SIZE); + continue; + } + + *major = IVAL(buf, + i+sizeof(VS_SIGNATURE)+ + skip+VS_MAJOR_OFFSET); + *minor = IVAL(buf, + i+sizeof(VS_SIGNATURE)+ + skip+VS_MINOR_OFFSET); + DBG_INFO("NE file [%s] Version " + "= %08x:%08x (%d.%d.%d.%d)\n", + fname, + *major, + *minor, + (*major>>16)&0xffff, + *major&0xffff, + (*minor>>16)&0xffff, + *minor&0xffff); + ret = 1; + goto out; + } + } + } + + /* Version info not found, fall back to origin date/time */ + DBG_ERR("NE file [%s] Version info not found\n", fname); + ret = 0; + + out: + + SAFE_FREE(buf); + return ret; +} + /**************************************************************************** Version information in Microsoft files is held in a VS_VERSION_INFO structure. There are two case to be covered here: PE (Portable Executable) and NE (New @@ -537,7 +704,6 @@ static int get_file_version(files_struct *fsp, uint32_t *major, uint32_t *minor) { - int i; char *buf = NULL; ssize_t byte_count; off_t pos; @@ -610,147 +776,11 @@ static int get_file_version(files_struct *fsp, minor); } else if (SVAL(buf,NE_HEADER_SIGNATURE_OFFSET) == NE_HEADER_SIGNATURE) { - if (CVAL(buf,NE_HEADER_TARGET_OS_OFFSET) != - NE_HEADER_TARGOS_WIN ) { - DBG_NOTICE("NE file [%s] wrong target OS = 0x%x\n", - fname, - CVAL(buf,NE_HEADER_TARGET_OS_OFFSET)); - /* - * At this point, we assume the file is in error. - * It still could be something else besides a NE file, - * but it unlikely at this point. - */ - goto error_exit; - } - - /* Allocate a bit more space to speed up things */ - SAFE_FREE(buf); - buf=(char *)SMB_MALLOC(VS_NE_BUF_SIZE); - if (buf == NULL) { - DBG_ERR("NE file [%s] malloc failed bytes = %d\n", - fname, - PE_HEADER_SIZE); - goto error_exit; - } - - /* - * This is a HACK! I got tired of trying to sort through the - * messy 'NE' file format. If anyone wants to clean this up - * please have at it, but this works. 'NE' files will - * eventually fade away. JRR - */ - byte_count = vfs_read_data(fsp, buf, VS_NE_BUF_SIZE); - while (byte_count > 0) { - /* - * Cover case that should not occur in a well - * formed 'NE' .dll file - */ - if (byte_count-VS_VERSION_INFO_SIZE <= 0) { - break; - } - - for(i=0; ibyte_count-VS_VERSION_INFO_SIZE) { - ssize_t amount_read; - ssize_t amount_unused = byte_count-i; - - memmove(buf, &buf[i], amount_unused); - amount_read = vfs_read_data(fsp, - &buf[amount_unused], - VS_NE_BUF_SIZE- amount_unused); - if (amount_read < 0) { - DBG_ERR("NE file [%s] Read " - "error, errno=%d\n", - fname, - errno); - goto error_exit; - } - - if (amount_read + amount_unused < - amount_read) { - /* Check for integer wrap. */ - break; - } - - byte_count = amount_read + - amount_unused; - if (byte_count < VS_VERSION_INFO_SIZE) { - break; - } - - i = 0; - } - - /* - * Check that the full signature string and - * the magic number that follows exist (not - * a perfect solution, but the chances that this - * occurs in code is, well, remote. Yes I know - * I'm comparing the 'V' twice, as it is - * simpler to read the code. - */ - if (strcmp(&buf[i], VS_SIGNATURE) == 0) { - /* - * Compute skip alignment to next - * long address. - */ - off_t cpos = SMB_VFS_LSEEK(fsp, - 0, - SEEK_CUR); - - int skip = -(cpos - (byte_count - i) + - sizeof(VS_SIGNATURE)) & 3; - if (IVAL(buf, - i+sizeof(VS_SIGNATURE)+skip) - != 0xfeef04bd) { - byte_count = vfs_read_data(fsp, - buf, - VS_NE_BUF_SIZE); - continue; - } - - *major = IVAL(buf, - i+sizeof(VS_SIGNATURE)+ - skip+VS_MAJOR_OFFSET); - *minor = IVAL(buf, - i+sizeof(VS_SIGNATURE)+ - skip+VS_MINOR_OFFSET); - DBG_INFO("NE file [%s] Version " - "= %08x:%08x (%d.%d.%d.%d)\n", - fname, - *major, - *minor, - (*major>>16)&0xffff, - *major&0xffff, - (*minor>>16)&0xffff, - *minor&0xffff); - SAFE_FREE(buf); - return 1; - } - } - } - - /* Version info not found, fall back to origin date/time */ - DBG_ERR("NE file [%s] Version info not found\n", fname); - SAFE_FREE(buf); - return 0; - + return handle_ne_file(fsp, + fname, + buf, + major, + minor); } else { /* * Assume this isn't an error... the file just @@ -759,6 +789,7 @@ static int get_file_version(files_struct *fsp, DBG_NOTICE("File [%s] unknown file format, signature = 0x%x\n", fname, IVAL(buf,PE_HEADER_SIGNATURE_OFFSET)); + /* Fallthrough into no_version_info: */ } no_version_info: -- 2.17.0.441.gb46fe60e1d-goog From cc0c2acf3d1cc1e0c2c0a176041ce8ad38d2cf84 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Mon, 30 Apr 2018 16:04:23 -0700 Subject: [PATCH 04/13] s3: printing: Rename vfs_read_data() -> printing_read_data(). This is an internal printing call, nothing to do with the VFS. Signed-off-by: Jeremy Allison --- source3/printing/nt_printing.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/source3/printing/nt_printing.c b/source3/printing/nt_printing.c index 65172a75084..754e04ace91 100644 --- a/source3/printing/nt_printing.c +++ b/source3/printing/nt_printing.c @@ -316,7 +316,7 @@ const char *get_short_archi(const char *long_archi) (note: EINTR re-read differs from vfs_write_data) ****************************************************************************/ -static ssize_t vfs_read_data(files_struct *fsp, +static ssize_t printing_read_data(files_struct *fsp, char *buf, size_t byte_count) { @@ -397,7 +397,7 @@ static int handle_pe_file(files_struct *fsp, goto out; } - byte_count = vfs_read_data(fsp, buf, section_table_bytes); + byte_count = printing_read_data(fsp, buf, section_table_bytes); if (byte_count < section_table_bytes) { DBG_NOTICE("PE file [%s] Section header too short, " "bytes read = %lu\n", @@ -451,7 +451,7 @@ static int handle_pe_file(files_struct *fsp, goto out; } - byte_count = vfs_read_data(fsp, + byte_count = printing_read_data(fsp, buf, section_bytes); if (byte_count < section_bytes) { @@ -574,7 +574,7 @@ static int handle_ne_file(files_struct *fsp, * please have at it, but this works. 'NE' files will * eventually fade away. JRR */ - byte_count = vfs_read_data(fsp, buf, VS_NE_BUF_SIZE); + byte_count = printing_read_data(fsp, buf, VS_NE_BUF_SIZE); while (byte_count > 0) { /* * Cover case that should not occur in a well @@ -590,7 +590,7 @@ static int handle_ne_file(files_struct *fsp, * possibly match */ if (buf[i] != 'V') { - byte_count = vfs_read_data(fsp, + byte_count = printing_read_data(fsp, buf, VS_NE_BUF_SIZE); continue; @@ -606,7 +606,7 @@ static int handle_ne_file(files_struct *fsp, ssize_t amount_unused = byte_count-i; memmove(buf, &buf[i], amount_unused); - amount_read = vfs_read_data(fsp, + amount_read = printing_read_data(fsp, &buf[amount_unused], VS_NE_BUF_SIZE- amount_unused); if (amount_read < 0) { @@ -654,7 +654,7 @@ static int handle_ne_file(files_struct *fsp, if (IVAL(buf, i+sizeof(VS_SIGNATURE)+skip) != 0xfeef04bd) { - byte_count = vfs_read_data(fsp, + byte_count = printing_read_data(fsp, buf, VS_NE_BUF_SIZE); continue; @@ -717,7 +717,7 @@ static int get_file_version(files_struct *fsp, goto error_exit; } - byte_count = vfs_read_data(fsp, buf, DOS_HEADER_SIZE); + byte_count = printing_read_data(fsp, buf, DOS_HEADER_SIZE); if (byte_count < DOS_HEADER_SIZE) { DBG_NOTICE("File [%s] DOS header too short, bytes read = %lu\n", fname, @@ -749,9 +749,10 @@ static int get_file_version(files_struct *fsp, */ goto no_version_info; } + pos = oret; /* Update new position. */ /* Note: DOS_HEADER_SIZE and NE_HEADER_SIZE are incidentally same */ - byte_count = vfs_read_data(fsp, buf, NE_HEADER_SIZE); + byte_count = printing_read_data(fsp, buf, NE_HEADER_SIZE); if (byte_count < NE_HEADER_SIZE) { DBG_NOTICE("File [%s] Windows header too short, " "bytes read = %lu\n", -- 2.17.0.441.gb46fe60e1d-goog From 9e8140305a2d49086d0d51c62d8c49f4c96d1a6c Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Tue, 1 May 2018 11:38:49 -0700 Subject: [PATCH 05/13] s3: printing: Rename printing_read_data() -> printing_pread_data() and add an offset parameter. Currently pass -1 as the offset, so it's not used. Signed-off-by: Jeremy Allison --- source3/printing/nt_printing.c | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/source3/printing/nt_printing.c b/source3/printing/nt_printing.c index 754e04ace91..c5c6e07ec3b 100644 --- a/source3/printing/nt_printing.c +++ b/source3/printing/nt_printing.c @@ -316,8 +316,9 @@ const char *get_short_archi(const char *long_archi) (note: EINTR re-read differs from vfs_write_data) ****************************************************************************/ -static ssize_t printing_read_data(files_struct *fsp, +static ssize_t printing_pread_data(files_struct *fsp, char *buf, + off_t *poff_unused, size_t byte_count) { size_t total=0; @@ -365,6 +366,7 @@ static int handle_pe_file(files_struct *fsp, ssize_t byte_count; off_t oret; off_t pos; + off_t in_pos = -1; int ret = -1; /* Just skip over optional header to get to section table */ @@ -397,7 +399,7 @@ static int handle_pe_file(files_struct *fsp, goto out; } - byte_count = printing_read_data(fsp, buf, section_table_bytes); + byte_count = printing_pread_data(fsp, buf, &in_pos, section_table_bytes); if (byte_count < section_table_bytes) { DBG_NOTICE("PE file [%s] Section header too short, " "bytes read = %lu\n", @@ -451,8 +453,9 @@ static int handle_pe_file(files_struct *fsp, goto out; } - byte_count = printing_read_data(fsp, + byte_count = printing_pread_data(fsp, buf, + &in_pos, section_bytes); if (byte_count < section_bytes) { DBG_NOTICE("PE file " @@ -545,6 +548,7 @@ static int handle_ne_file(files_struct *fsp, unsigned int i; ssize_t byte_count; int ret = -1; + off_t in_pos = -1; if (CVAL(buf,NE_HEADER_TARGET_OS_OFFSET) != NE_HEADER_TARGOS_WIN ) { DBG_NOTICE("NE file [%s] wrong target OS = 0x%x\n", @@ -574,7 +578,7 @@ static int handle_ne_file(files_struct *fsp, * please have at it, but this works. 'NE' files will * eventually fade away. JRR */ - byte_count = printing_read_data(fsp, buf, VS_NE_BUF_SIZE); + byte_count = printing_pread_data(fsp, buf, &in_pos, VS_NE_BUF_SIZE); while (byte_count > 0) { /* * Cover case that should not occur in a well @@ -590,8 +594,9 @@ static int handle_ne_file(files_struct *fsp, * possibly match */ if (buf[i] != 'V') { - byte_count = printing_read_data(fsp, + byte_count = printing_pread_data(fsp, buf, + &in_pos, VS_NE_BUF_SIZE); continue; } @@ -606,8 +611,9 @@ static int handle_ne_file(files_struct *fsp, ssize_t amount_unused = byte_count-i; memmove(buf, &buf[i], amount_unused); - amount_read = printing_read_data(fsp, + amount_read = printing_pread_data(fsp, &buf[amount_unused], + &in_pos, VS_NE_BUF_SIZE- amount_unused); if (amount_read < 0) { DBG_ERR("NE file [%s] Read " @@ -654,8 +660,9 @@ static int handle_ne_file(files_struct *fsp, if (IVAL(buf, i+sizeof(VS_SIGNATURE)+skip) != 0xfeef04bd) { - byte_count = printing_read_data(fsp, + byte_count = printing_pread_data(fsp, buf, + &in_pos, VS_NE_BUF_SIZE); continue; } @@ -708,6 +715,7 @@ static int get_file_version(files_struct *fsp, ssize_t byte_count; off_t pos; off_t oret; + off_t in_pos = -1; buf=(char *)SMB_MALLOC(DOS_HEADER_SIZE); if (buf == NULL) { @@ -717,7 +725,7 @@ static int get_file_version(files_struct *fsp, goto error_exit; } - byte_count = printing_read_data(fsp, buf, DOS_HEADER_SIZE); + byte_count = printing_pread_data(fsp, buf, &in_pos, DOS_HEADER_SIZE); if (byte_count < DOS_HEADER_SIZE) { DBG_NOTICE("File [%s] DOS header too short, bytes read = %lu\n", fname, @@ -752,7 +760,7 @@ static int get_file_version(files_struct *fsp, pos = oret; /* Update new position. */ /* Note: DOS_HEADER_SIZE and NE_HEADER_SIZE are incidentally same */ - byte_count = printing_read_data(fsp, buf, NE_HEADER_SIZE); + byte_count = printing_pread_data(fsp, buf, &in_pos, NE_HEADER_SIZE); if (byte_count < NE_HEADER_SIZE) { DBG_NOTICE("File [%s] Windows header too short, " "bytes read = %lu\n", -- 2.17.0.441.gb46fe60e1d-goog From 96d0af482d8b596589963187950b28c783d09501 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Wed, 2 May 2018 13:45:44 -0700 Subject: [PATCH 06/13] s3: printing: Make printing_pread_data() update the offset paramter, if not passed in as -1. As all callers pass -1 here, still not used. Signed-off-by: Jeremy Allison --- source3/printing/nt_printing.c | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/source3/printing/nt_printing.c b/source3/printing/nt_printing.c index c5c6e07ec3b..1a31199d6ab 100644 --- a/source3/printing/nt_printing.c +++ b/source3/printing/nt_printing.c @@ -318,16 +318,31 @@ const char *get_short_archi(const char *long_archi) static ssize_t printing_pread_data(files_struct *fsp, char *buf, - off_t *poff_unused, + off_t *poff, size_t byte_count) { size_t total=0; + off_t in_pos = *poff; + + if (in_pos != (off_t)-1) { + in_pos = SMB_VFS_LSEEK(fsp, in_pos, SEEK_SET); + if (in_pos == (off_t)-1) { + return -1; + } + /* Don't allow integer wrap on read. */ + if (in_pos + byte_count < in_pos) { + return -1; + } + } while (total < byte_count) { ssize_t ret = SMB_VFS_READ(fsp, buf + total, byte_count - total); if (ret == 0) { + if (*poff != (off_t)-1) { + *poff = in_pos; + } return total; } if (ret == -1) { @@ -337,8 +352,12 @@ static ssize_t printing_pread_data(files_struct *fsp, return -1; } } + in_pos += ret; total += ret; } + if (*poff != (off_t)-1) { + *poff = in_pos; + } return (ssize_t)total; } -- 2.17.0.441.gb46fe60e1d-goog From 04b66523225d6ce458319e0aa68eab73490edd25 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Tue, 1 May 2018 11:08:40 -0700 Subject: [PATCH 07/13] s3: printing: Use auto-updating of offset in printing_pread_data() to remove offset tracking in get_file_version(). Signed-off-by: Jeremy Allison --- source3/printing/nt_printing.c | 18 ++---------------- 1 file changed, 2 insertions(+), 16 deletions(-) diff --git a/source3/printing/nt_printing.c b/source3/printing/nt_printing.c index 1a31199d6ab..f4e2768e536 100644 --- a/source3/printing/nt_printing.c +++ b/source3/printing/nt_printing.c @@ -732,9 +732,7 @@ static int get_file_version(files_struct *fsp, { char *buf = NULL; ssize_t byte_count; - off_t pos; - off_t oret; - off_t in_pos = -1; + off_t in_pos = fsp->fh->pos; buf=(char *)SMB_MALLOC(DOS_HEADER_SIZE); if (buf == NULL) { @@ -764,19 +762,7 @@ static int get_file_version(files_struct *fsp, * Skip OEM header (if any) and the * DOS stub to start of Windows header. */ - pos = SVAL(buf,DOS_HEADER_LFANEW_OFFSET); - oret = SMB_VFS_LSEEK(fsp, pos, SEEK_SET); - if (oret == (off_t)-1) { - DBG_NOTICE("File [%s] too short, errno = %d\n", - fname, - errno); - /* - * Assume this isn't an error... - * the file just looks sort of like a PE/NE file. - */ - goto no_version_info; - } - pos = oret; /* Update new position. */ + in_pos = SVAL(buf,DOS_HEADER_LFANEW_OFFSET); /* Note: DOS_HEADER_SIZE and NE_HEADER_SIZE are incidentally same */ byte_count = printing_pread_data(fsp, buf, &in_pos, NE_HEADER_SIZE); -- 2.17.0.441.gb46fe60e1d-goog From 7891b12e7186afd00856f34ffde691b7738627c6 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Tue, 1 May 2018 11:11:01 -0700 Subject: [PATCH 08/13] s3: printing: Add existing offset position as a parameter to handle_pe_file(), handle_ne_file() Not yet used. Signed-off-by: Jeremy Allison --- source3/printing/nt_printing.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/source3/printing/nt_printing.c b/source3/printing/nt_printing.c index f4e2768e536..8c73b52801a 100644 --- a/source3/printing/nt_printing.c +++ b/source3/printing/nt_printing.c @@ -374,6 +374,7 @@ static ssize_t printing_pread_data(files_struct *fsp, ****************************************************************************/ static int handle_pe_file(files_struct *fsp, + off_t in_pos_unused, char *fname, char *buf, uint32_t *major, @@ -559,6 +560,7 @@ static int handle_pe_file(files_struct *fsp, ****************************************************************************/ static int handle_ne_file(files_struct *fsp, + off_t in_pos_unused, char *fname, char *buf, uint32_t *major, @@ -784,6 +786,7 @@ static int get_file_version(files_struct *fsp, */ if (IVAL(buf,PE_HEADER_SIGNATURE_OFFSET) == PE_HEADER_SIGNATURE) { return handle_pe_file(fsp, + in_pos, fname, buf, major, @@ -791,6 +794,7 @@ static int get_file_version(files_struct *fsp, } else if (SVAL(buf,NE_HEADER_SIGNATURE_OFFSET) == NE_HEADER_SIGNATURE) { return handle_ne_file(fsp, + in_pos, fname, buf, major, -- 2.17.0.441.gb46fe60e1d-goog From 4dc61bb47da06dd13582592a68b99802b4a74b26 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Tue, 1 May 2018 11:16:02 -0700 Subject: [PATCH 09/13] s3: printing: Use passed in offset, and offset tracking in printing_pread_data() to remove seeks from handle_pe_file(). Signed-off-by: Jeremy Allison --- source3/printing/nt_printing.c | 29 +++++++---------------------- 1 file changed, 7 insertions(+), 22 deletions(-) diff --git a/source3/printing/nt_printing.c b/source3/printing/nt_printing.c index 8c73b52801a..cd64016b389 100644 --- a/source3/printing/nt_printing.c +++ b/source3/printing/nt_printing.c @@ -374,7 +374,7 @@ static ssize_t printing_pread_data(files_struct *fsp, ****************************************************************************/ static int handle_pe_file(files_struct *fsp, - off_t in_pos_unused, + off_t in_pos, char *fname, char *buf, uint32_t *major, @@ -384,21 +384,15 @@ static int handle_pe_file(files_struct *fsp, unsigned int num_sections; unsigned int section_table_bytes; ssize_t byte_count; - off_t oret; - off_t pos; - off_t in_pos = -1; + off_t rel_pos; int ret = -1; /* Just skip over optional header to get to section table */ - pos = SVAL(buf,PE_HEADER_OPTIONAL_HEADER_SIZE)- + rel_pos = SVAL(buf,PE_HEADER_OPTIONAL_HEADER_SIZE)- (NE_HEADER_SIZE-PE_HEADER_SIZE); - oret = SMB_VFS_LSEEK(fsp, pos, SEEK_CUR); - if (oret == (off_t)-1) { - DBG_NOTICE("File [%s] Windows optional header " - "too short, errno = %d\n", - fname, - errno); + if (in_pos + rel_pos < in_pos) { + /* Integer wrap. */ goto out; } @@ -459,19 +453,10 @@ static int handle_pe_file(files_struct *fsp, } /* - * Seek to the start of the .rsrc + * Read from the start of the .rsrc * section info */ - oret = SMB_VFS_LSEEK(fsp, - section_pos, - SEEK_SET); - if (oret == (off_t)-1) { - DBG_NOTICE("PE file [%s] too short for " - "section info, errno = %d\n", - fname, - errno); - goto out; - } + in_pos = section_pos; byte_count = printing_pread_data(fsp, buf, -- 2.17.0.441.gb46fe60e1d-goog From 1734cc3857e4ac88d818ac3b6f8dad926e024dda Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Tue, 1 May 2018 11:19:49 -0700 Subject: [PATCH 10/13] s3: printing: Use offset tracking in printing_pread_data() to remove the seek in handle_ne_file(). Uses the fact that: lseek(fd, 0, SEEK_CUR) is merely getting the current file position, which we have already tracked in in_pos. Signed-off-by: Jeremy Allison --- source3/printing/nt_printing.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/source3/printing/nt_printing.c b/source3/printing/nt_printing.c index cd64016b389..308568b5f10 100644 --- a/source3/printing/nt_printing.c +++ b/source3/printing/nt_printing.c @@ -545,7 +545,7 @@ static int handle_pe_file(files_struct *fsp, ****************************************************************************/ static int handle_ne_file(files_struct *fsp, - off_t in_pos_unused, + off_t in_pos, char *fname, char *buf, uint32_t *major, @@ -554,7 +554,6 @@ static int handle_ne_file(files_struct *fsp, unsigned int i; ssize_t byte_count; int ret = -1; - off_t in_pos = -1; if (CVAL(buf,NE_HEADER_TARGET_OS_OFFSET) != NE_HEADER_TARGOS_WIN ) { DBG_NOTICE("NE file [%s] wrong target OS = 0x%x\n", @@ -657,10 +656,7 @@ static int handle_ne_file(files_struct *fsp, * Compute skip alignment to next * long address. */ - off_t cpos = SMB_VFS_LSEEK(fsp, - 0, - SEEK_CUR); - + off_t cpos = in_pos; int skip = -(cpos - (byte_count - i) + sizeof(VS_SIGNATURE)) & 3; if (IVAL(buf, -- 2.17.0.441.gb46fe60e1d-goog From 8ff7005008fc5cfbfed95a03cb96feca8ce77c64 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Tue, 1 May 2018 11:47:24 -0700 Subject: [PATCH 11/13] s3: printing: Now we never pass an offset of -1, remove the off_t==-1 protections from printing_pread_data(). Signed-off-by: Jeremy Allison --- source3/printing/nt_printing.c | 24 +++++++++--------------- 1 file changed, 9 insertions(+), 15 deletions(-) diff --git a/source3/printing/nt_printing.c b/source3/printing/nt_printing.c index 308568b5f10..ea95cee05a0 100644 --- a/source3/printing/nt_printing.c +++ b/source3/printing/nt_printing.c @@ -324,15 +324,13 @@ static ssize_t printing_pread_data(files_struct *fsp, size_t total=0; off_t in_pos = *poff; - if (in_pos != (off_t)-1) { - in_pos = SMB_VFS_LSEEK(fsp, in_pos, SEEK_SET); - if (in_pos == (off_t)-1) { - return -1; - } - /* Don't allow integer wrap on read. */ - if (in_pos + byte_count < in_pos) { - return -1; - } + in_pos = SMB_VFS_LSEEK(fsp, in_pos, SEEK_SET); + if (in_pos == (off_t)-1) { + return -1; + } + /* Don't allow integer wrap on read. */ + if (in_pos + byte_count < in_pos) { + return -1; } while (total < byte_count) { @@ -340,9 +338,7 @@ static ssize_t printing_pread_data(files_struct *fsp, byte_count - total); if (ret == 0) { - if (*poff != (off_t)-1) { - *poff = in_pos; - } + *poff = in_pos; return total; } if (ret == -1) { @@ -355,9 +351,7 @@ static ssize_t printing_pread_data(files_struct *fsp, in_pos += ret; total += ret; } - if (*poff != (off_t)-1) { - *poff = in_pos; - } + *poff = in_pos; return (ssize_t)total; } -- 2.17.0.441.gb46fe60e1d-goog From d13fa4d49a9d023641e2ff99730ea9d975c46af3 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Tue, 1 May 2018 11:51:43 -0700 Subject: [PATCH 12/13] s3: printing: Remove the LSEEK in printing_pread_data() and use read_file() instead. Removes last-but-one user of SMB_VFS_READ. Signed-off-by: Jeremy Allison --- source3/printing/nt_printing.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/source3/printing/nt_printing.c b/source3/printing/nt_printing.c index ea95cee05a0..fcff0819daf 100644 --- a/source3/printing/nt_printing.c +++ b/source3/printing/nt_printing.c @@ -324,17 +324,15 @@ static ssize_t printing_pread_data(files_struct *fsp, size_t total=0; off_t in_pos = *poff; - in_pos = SMB_VFS_LSEEK(fsp, in_pos, SEEK_SET); - if (in_pos == (off_t)-1) { - return -1; - } /* Don't allow integer wrap on read. */ if (in_pos + byte_count < in_pos) { return -1; } while (total < byte_count) { - ssize_t ret = SMB_VFS_READ(fsp, buf + total, + ssize_t ret = read_file(fsp, + buf + total, + in_pos, byte_count - total); if (ret == 0) { -- 2.17.0.441.gb46fe60e1d-goog From 7598ec99a72e741b7b98cadeeb3668f9e41612d7 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Tue, 1 May 2018 11:53:10 -0700 Subject: [PATCH 13/13] s3: torture: Make cmd_read use read_file(). Removed last user of SMB_VFS_READ. Signed-off-by: Jeremy Allison --- source3/torture/cmd_vfs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source3/torture/cmd_vfs.c b/source3/torture/cmd_vfs.c index 3ae788e7bd9..28335c0fa9d 100644 --- a/source3/torture/cmd_vfs.c +++ b/source3/torture/cmd_vfs.c @@ -527,7 +527,7 @@ static NTSTATUS cmd_read(struct vfs_state *vfs, TALLOC_CTX *mem_ctx, int argc, c } vfs->data_size = size; - rsize = SMB_VFS_READ(vfs->files[fd], vfs->data, size); + rsize = read_file(vfs->files[fd], vfs->data, 0, size); if (rsize == -1) { printf("read: error=%d (%s)\n", errno, strerror(errno)); return NT_STATUS_UNSUCCESSFUL; -- 2.17.0.441.gb46fe60e1d-goog