Hello community, here is the log from the commit of package cabextract for openSUSE:Factory checked in at 2015-04-03 14:34:51 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/cabextract (Old) and /work/SRC/openSUSE:Factory/.cabextract.new (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Package is "cabextract" Changes: -------- --- /work/SRC/openSUSE:Factory/cabextract/cabextract.changes 2015-02-22 17:26:50.000000000 +0100 +++ /work/SRC/openSUSE:Factory/.cabextract.new/cabextract.changes 2015-04-03 14:34:52.000000000 +0200 @@ -1,0 +2,8 @@ +Thu Apr 2 16:51:12 CEST 2015 - sbrabec@suse.cz + +- Update to version 1.6: + * further UTF-8 fixes + * sanitize file names +- Add -fno-strict-aliasing for md5.c: 114, 115. + +------------------------------------------------------------------- Old: ---- cabextract-1.5.tar.gz New: ---- cabextract-1.6.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ cabextract.spec ++++++ --- /var/tmp/diff_new_pack.XjPSG1/_old 2015-04-03 14:34:53.000000000 +0200 +++ /var/tmp/diff_new_pack.XjPSG1/_new 2015-04-03 14:34:53.000000000 +0200 @@ -17,7 +17,7 @@ Name: cabextract -Version: 1.5 +Version: 1.6 Release: 0 Summary: A Program to Extract Microsoft Cabinet Files License: GPL-3.0+ @@ -36,7 +36,7 @@ %setup -q %build -CFLAGS="%{optflags} -fPIE" +CFLAGS="%{optflags} -fPIE -fno-strict-aliasing" %configure --with-external-libmspack make %{?_smp_mflags} LDFLAGS="-pie" ++++++ cabextract-1.5.tar.gz -> cabextract-1.6.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cabextract-1.5/ChangeLog new/cabextract-1.6/ChangeLog --- old/cabextract-1.5/ChangeLog 2015-01-18 16:58:40.000000000 +0100 +++ new/cabextract-1.6/ChangeLog 2015-02-26 11:51:11.000000000 +0100 @@ -1,3 +1,18 @@ +2015-02-25 Stuart Caie <kyzer@4u.net> + + * create_output_name(): Simplify code; do path checking only after + output name has been constructed. Use towlower to lowercase UTF-8 + characters. Remove both leading '/' and '' from cab filenames and + change both "../" and ".." to "xx", for Cygwin and other Cygwin-like + environments that use both '/' and '' as path separators. Thanks to + Alexander Cherepanov and the MITRE team. + +2015-02-18 Stuart Caie <kyzer@4u.net> + + * create_output_name(): the check against leading slashes could be + evaded with malformed UTF-8. Thanks to Alexander Cherepanov for + reporting the issue. + 2015-01-18 Stuart Caie <kyzer@4u.net> * wince_rename: installed files now include their install directories. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cabextract-1.5/Makefile.in new/cabextract-1.6/Makefile.in --- old/cabextract-1.5/Makefile.in 2015-01-24 14:23:03.000000000 +0100 +++ new/cabextract-1.6/Makefile.in 2015-03-23 00:26:42.000000000 +0100 @@ -84,8 +84,8 @@ DIST_COMMON = INSTALL NEWS README AUTHORS ChangeLog COPYING \ $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ $(top_srcdir)/configure $(am__configure_deps) \ - $(srcdir)/config.h.in $(srcdir)/cabextract.spec.in getopt1.c \ - getopt.c mktime.c fnmatch.c TODO compile install-sh missing + $(srcdir)/config.h.in $(srcdir)/cabextract.spec.in mktime.c \ + getopt.c getopt1.c fnmatch.c TODO compile install-sh missing ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \ $(top_srcdir)/configure.ac diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cabextract-1.5/NEWS new/cabextract-1.6/NEWS --- old/cabextract-1.5/NEWS 2015-01-24 13:55:29.000000000 +0100 +++ new/cabextract-1.6/NEWS 2015-02-26 11:28:44.000000000 +0100 @@ -1,3 +1,12 @@ +New in 1.6 +* cabextract now prevents archive files giving themselves absolute path access + using badly UTF-8 encoded slashes. +* Because Cygwin allows both '/' and '' as path separators, cabextract now + removes both leading '/'s and ''s and changes both "../" and ".." in + CAB filenames to "xx". You can no longer have a CAB filename called e.g + "/t" (file "t" in the directory ""). If you need this, create a CAB file + where the filename is ".//t" instead. + New in 1.5 * cabextract replaces bad Unicode characters in filenames with the standard Unicode replacement character diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cabextract-1.5/README new/cabextract-1.6/README --- old/cabextract-1.5/README 2015-01-24 13:56:18.000000000 +0100 +++ new/cabextract-1.6/README 2015-03-23 00:21:25.000000000 +0100 @@ -1,4 +1,4 @@ -cabextract 1.5 - a program to extract Microsoft Cabinet files. +cabextract 1.6 - a program to extract Microsoft Cabinet files. (C) 2000-2015 Stuart Caie <kyzer@4u.net> This is free software with ABSOLUTELY NO WARRANTY. @@ -42,4 +42,4 @@ Testing the integrity of a cabinet file, without extracting it: $ cabextract -t wibble.cab -Stuart Caie <kyzer@4u.net>, January 2015 +Stuart Caie <kyzer@4u.net>, March 2015 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cabextract-1.5/cabextract.spec new/cabextract-1.6/cabextract.spec --- old/cabextract-1.5/cabextract.spec 2015-01-24 14:23:09.000000000 +0100 +++ new/cabextract-1.6/cabextract.spec 2015-03-23 00:26:48.000000000 +0100 @@ -1,6 +1,6 @@ Summary: A program to extract Microsoft Cabinet files Name: cabextract -Version: 1.5 +Version: 1.6 Release: 1 License: GPL Group: Applications/Archiving diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cabextract-1.5/config.h.in new/cabextract-1.6/config.h.in --- old/cabextract-1.5/config.h.in 2015-01-24 14:23:02.000000000 +0100 +++ new/cabextract-1.6/config.h.in 2015-03-23 00:26:40.000000000 +0100 @@ -68,6 +68,9 @@ /* Define to 1 if you have the `memcpy' function. */ #undef HAVE_MEMCPY +/* Define to 1 if you have the `memmove' function. */ +#undef HAVE_MEMMOVE + /* Define to 1 if you have the <memory.h> header file. */ #undef HAVE_MEMORY_H @@ -118,6 +121,9 @@ /* Define to 1 if you have the <sys/types.h> header file. */ #undef HAVE_SYS_TYPES_H +/* Define to 1 if you have the `towlower' function. */ +#undef HAVE_TOWLOWER + /* Define to 1 if you have the <unistd.h> header file. */ #undef HAVE_UNISTD_H diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cabextract-1.5/configure new/cabextract-1.6/configure --- old/cabextract-1.5/configure 2015-01-24 14:23:02.000000000 +0100 +++ new/cabextract-1.6/configure 2015-03-23 00:26:40.000000000 +0100 @@ -1,6 +1,6 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.69 for cabextract 1.5. +# Generated by GNU Autoconf 2.69 for cabextract 1.6. # # Report bugs to <kyzer@4u.net>. # @@ -579,8 +579,8 @@ # Identity of this package. PACKAGE_NAME='cabextract' PACKAGE_TARNAME='cabextract' -PACKAGE_VERSION='1.5' -PACKAGE_STRING='cabextract 1.5' +PACKAGE_VERSION='1.6' +PACKAGE_STRING='cabextract 1.6' PACKAGE_BUGREPORT='kyzer@4u.net' PACKAGE_URL='' @@ -1274,7 +1274,7 @@ # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF -`configure' configures cabextract 1.5 to adapt to many kinds of systems. +`configure' configures cabextract 1.6 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1340,7 +1340,7 @@ if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of cabextract 1.5:";; + short | recursive ) echo "Configuration of cabextract 1.6:";; esac cat <<_ACEOF @@ -1438,7 +1438,7 @@ test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<_ACEOF -cabextract configure 1.5 +cabextract configure 1.6 generated by GNU Autoconf 2.69 Copyright (C) 2012 Free Software Foundation, Inc. @@ -2090,7 +2090,7 @@ This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. -It was created by cabextract $as_me 1.5, which was +It was created by cabextract $as_me 1.6, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ @@ -2956,7 +2956,7 @@ # Define the identity of the package. PACKAGE='cabextract' - VERSION='1.5' + VERSION='1.6' cat >>confdefs.h <<_ACEOF @@ -4781,7 +4781,7 @@ for ac_header in ctype.h errno.h fnmatch.h libintl.h limits.h stdlib.h \ string.h strings.h utime.h stdarg.h sys/stat.h sys/time.h sys/types.h \ - getopt.h wchar.h wctype.h + getopt.h wchar.h wctype.h inttypes.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" @@ -5618,7 +5618,7 @@ fi -for ac_func in memcpy strcasecmp strchr utime utimes +for ac_func in memcpy memmove strcasecmp strchr towlower utime utimes do : as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" @@ -6626,7 +6626,7 @@ # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" -This file was extended by cabextract $as_me 1.5, which was +This file was extended by cabextract $as_me 1.6, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -6696,7 +6696,7 @@ cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\""`$]/\\&/g'`" ac_cs_version="\ -cabextract config.status 1.5 +cabextract config.status 1.6 configured by $0, generated by GNU Autoconf 2.69, with options \"$ac_cs_config\" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cabextract-1.5/configure.ac new/cabextract-1.6/configure.ac --- old/cabextract-1.5/configure.ac 2015-01-24 13:56:31.000000000 +0100 +++ new/cabextract-1.6/configure.ac 2015-02-26 11:52:22.000000000 +0100 @@ -1,7 +1,7 @@ # -*- Autoconf -*- # Process this file with autoconf to produce a configure script. AC_PREREQ(2.57) -AC_INIT(cabextract, 1.5, kyzer@4u.net) +AC_INIT(cabextract, 1.6, kyzer@4u.net) AM_INIT_AUTOMAKE AC_CONFIG_SRCDIR([src/cabextract.c]) AC_CONFIG_HEADER([config.h]) @@ -18,7 +18,7 @@ AC_HEADER_DIRENT AC_CHECK_HEADERS([ctype.h errno.h fnmatch.h libintl.h limits.h stdlib.h \ string.h strings.h utime.h stdarg.h sys/stat.h sys/time.h sys/types.h \ - getopt.h wchar.h wctype.h]) + getopt.h wchar.h wctype.h inttypes.h]) # Checks for typedefs, structures, and compiler characteristics. AC_C_CONST @@ -34,7 +34,7 @@ AC_FUNC_FSEEKO AX_FUNC_MKDIR AC_FUNC_MKTIME -AC_CHECK_FUNCS([memcpy strcasecmp strchr utime utimes]) +AC_CHECK_FUNCS([memcpy memmove strcasecmp strchr towlower utime utimes]) AC_CHECK_FUNCS([getopt_long],,[AC_CHECK_LIB([gnugetopt], [getopt_long], [AC_DEFINE([HAVE_GETOPT_LONG])],[AC_LIBOBJ(getopt) AC_LIBOBJ(getopt1)])]) AC_REPLACE_FNMATCH diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cabextract-1.5/mspack/ChangeLog new/cabextract-1.6/mspack/ChangeLog --- old/cabextract-1.5/mspack/ChangeLog 2015-01-19 00:11:15.000000000 +0100 +++ new/cabextract-1.6/mspack/ChangeLog 2015-01-30 01:00:05.000000000 +0100 @@ -1,3 +1,8 @@ +2015-01-29 Stuart Caie <kyzer@4u.net> + + * system.h: if C99 inttypes.h exists, use its PRI{d,u}{32,64} macros. + Thanks to Johnathan Kollasch for the suggestion. + 2015-01-18 Stuart Caie <kyzer@4u.net> * lzxd_decompress(): the byte-alignment code for reading uncompressed diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cabextract-1.5/mspack/system.h new/cabextract-1.6/mspack/system.h --- old/cabextract-1.5/mspack/system.h 2011-04-26 19:15:21.000000000 +0200 +++ new/cabextract-1.6/mspack/system.h 2015-01-30 00:58:32.000000000 +0100 @@ -57,17 +57,26 @@ # include <limits.h> #endif +#ifdef HAVE_INTTYPES_H +# include <inttypes.h> +#else +# define PRId64 "lld" +# define PRIu64 "llu" +# define PRId32 "ld" +# define PRIu32 "lu" +#endif + #if ((defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS >= 64) || \ (defined(FILESIZEBITS) && FILESIZEBITS >= 64) || \ (defined(SIZEOF_OFF_T) && SIZEOF_OFF_T >= 8) || \ defined(_LARGEFILE_SOURCE) || defined(_LARGEFILE64_SOURCE)) # define LARGEFILE_SUPPORT -# define LD "lld" -# define LU "llu" +# define LD PRId64 +# define LU PRIu64 #else extern const char *largefile_msg; -# define LD "ld" -# define LU "lu" +# define LD PRId32 +# define LU PRIu32 #endif /* endian-neutral reading of little-endian data */ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cabextract-1.5/src/cabextract.c new/cabextract-1.6/src/cabextract.c --- old/cabextract-1.5/src/cabextract.c 2015-01-10 19:13:11.000000000 +0100 +++ new/cabextract-1.6/src/cabextract.c 2015-02-26 11:53:01.000000000 +0100 @@ -1,5 +1,5 @@ -/* cabextract 1.4 - a program to extract Microsoft Cabinet files - * (C) 2000-2011 Stuart Caie <kyzer@4u.net> +/* cabextract 1.6 - a program to extract Microsoft Cabinet files + * (C) 2000-2015 Stuart Caie <kyzer@4u.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -35,6 +35,10 @@ # include <ctype.h> #endif +#if HAVE_WCTYPE_H +# include <wctype.h> +#endif + #if HAVE_ERRNO_H # include <errno.h> #endif @@ -112,6 +116,9 @@ # if !HAVE_MEMCPY # define memcpy(d,s,n) bcopy((s),(d),(n)) # endif +# if !HAVE_MEMMOVE +# define memmove(d,s,n) bcopy((s),(d),(n)) +# endif #endif #if HAVE_MKDIR @@ -212,7 +219,7 @@ char *basename); static char *find_cabinet_file(char *origcab, char *cabname); static int unix_path_seperators(struct mscabd_file *files); -static char *create_output_name(unsigned char *fname, unsigned char *dir, +static char *create_output_name(const char *fname, const char *dir, int lower, int isunix, int unicode); static void set_date_and_perm(struct mscabd_file *file, char *filename); @@ -441,8 +448,7 @@ /* process all files */ for (file = cab->files; file; file = file->next) { /* create the full UNIX output filename */ - if (!(name = create_output_name( - (unsigned char *) file->filename, (unsigned char *) args.dir, + if (!(name = create_output_name(file->filename, args.dir, args.lower, isunix, file->attribs & MSCAB_ATTRIB_UTF_NAME))) { errors++; @@ -735,77 +741,62 @@ * not enough memory. * @see unix_path_seperators() */ -static char *create_output_name(unsigned char *fname, unsigned char *dir, - int lower, int isunix, int utf8) +static char *create_output_name(const char *fname, const char *dir, + int lower, int isunix, int utf8) { - unsigned char *p, *name, c, *fe, sep, slash; - int x; + char sep = (isunix) ? '/' : '\'; /* the path-seperator */ + char slash = (isunix) ? '\' : '/'; /* the other slash */ + + size_t dirlen = dir ? strlen(dir) + 1 : 0; /* length of dir + '/' */ + size_t filelen = strlen(fname); - sep = (isunix) ? '/' : '\'; /* the path-seperator */ - slash = (isunix) ? '\' : '/'; /* the other slash */ + /* worst case, UTF-8 processing expands all chars to 4 bytes */ + char *name = malloc(dirlen + (filelen * 4) + 2); - /* length of filename */ - x = strlen((char *) fname); - /* UTF-8 worst case scenario: tolower() expands all chars from 1 to 4 bytes */ - if (utf8) x *= 4; - /* length of output directory */ - if (dir) x += strlen((char *) dir); - x += 2; + unsigned char *i = (unsigned char *) &fname[0]; + unsigned char *iend = (unsigned char *) &fname[filelen]; + unsigned char *o = (unsigned char *) &name[dirlen], c; - if (!(name = malloc(x))) { - fprintf(stderr, "Can't allocate output filename (%u bytes)\n", x); + if (!name) { + fprintf(stderr, "Can't allocate output filename\n"); return NULL; } - - /* start with blank name */ - *name = '\0'; - /* add output directory if needed */ + /* copy directory prefix if needed */ if (dir) { - strcpy((char *) name, (char *) dir); - strcat((char *) name, "/"); + strcpy(name, dir); + name[dirlen - 1] = '/'; } - /* remove leading slashes */ - while (*fname == sep) fname++; - - /* copy from fi->filename to new name, converting MS-DOS slashes to UNIX - * slashes as we go. Also lowercases characters if needed. - */ - p = &name[strlen((char *)name)]; /* p = start of output filename */ - fe = &fname[strlen((char *)fname)]; /* fe = end of input filename */ - + /* copy cab filename to output name, converting MS-DOS slashes to UNIX + * slashes as we go. Also lowercases characters if needed. */ if (utf8) { /* handle UTF-8 encoded filenames (see RFC 3629). This doesn't reject bad - * UTF-8 with overlong encodings, but does re-encode it as valid UTF-8. - */ - while (fname < fe) { + * UTF-8 with overlong encodings, but does re-encode it as valid UTF-8. */ + while (i < iend) { /* get next UTF-8 character */ - if ((c = *fname++) < 0x80) { + int x; + if ((c = *i++) < 0x80) { x = c; } - else if (c >= 0xC2 && c < 0xE0 && fname <= fe && - (fname[0] & 0xC0) == 0x80) - { + else if (c >= 0xC2 && c < 0xE0 && i <= iend && (i[0] & 0xC0) == 0x80) { x = (c & 0x1F) << 6; - x |= *fname++ & 0x3F; + x |= *i++ & 0x3F; } - else if (c >= 0xE0 && c < 0xF0 && fname+1 <= fe && - (fname[0] & 0xC0) == 0x80 && (fname[1] & 0xC0) == 0x80) + else if (c >= 0xE0 && c < 0xF0 && i+1 <= iend && (i[0] & 0xC0) == 0x80 && + (i[1] & 0xC0) == 0x80) { x = (c & 0x0F) << 12; - x |= (*fname++ & 0x3F) << 6; - x |= *fname++ & 0x3F; + x |= (*i++ & 0x3F) << 6; + x |= *i++ & 0x3F; } - else if (c >= 0xF0 && c < 0xF5 && fname+2 <= fe && - (fname[0] & 0xC0) == 0x80 && - (fname[1] & 0xC0) == 0x80 && - (fname[2] & 0xC0) == 0x80) + else if (c >= 0xF0 && c < 0xF5 && i+2 <= iend && (i[0] & 0xC0) == 0x80 && + (i[1] & 0xC0) == 0x80 && (i[2] & 0xC0) == 0x80) { x = (c & 0x07) << 18; - x |= (*fname++ & 0x3F) << 12; - x |= (*fname++ & 0x3F) << 6; - x |= *fname++ & 0x3F; + x |= (*i++ & 0x3F) << 12; + x |= (*i++ & 0x3F) << 6; + x |= *i++ & 0x3F; } else { x = 0xFFFD; /* unicode replacement character */ @@ -815,60 +806,78 @@ x = 0xFFFD; /* invalid code point or cheeky null byte */ } - /* whatever is the path seperator -> '/' - * whatever is the other slash -> '\' - * otherwise, if lower is set, the lowercase version */ - if (x == sep) x = '/'; - else if (x == slash) x = '\'; - else if (lower) x = tolower(x); +#ifdef HAVE_TOWLOWER + if (lower) x = towlower(x); +#else + if (lower && x < 256) x = tolower(x); +#endif + + /* whatever is the path separator -> '/' + * whatever is the other slash -> '' */ + if (x == sep) x = '/'; else if (x == slash) x = '\'; /* convert unicode character back to UTF-8 */ if (x < 0x80) { - *p++ = (unsigned char) x; + *o++ = (unsigned char) x; } else if (x < 0x800) { - *p++ = 0xC0 | (x >> 6); - *p++ = 0x80 | (x & 0x3F); + *o++ = 0xC0 | (x >> 6); + *o++ = 0x80 | (x & 0x3F); } else if (x < 0x10000) { - *p++ = 0xE0 | (x >> 12); - *p++ = 0x80 | ((x >> 6) & 0x3F); - *p++ = 0x80 | (x & 0x3F); + *o++ = 0xE0 | (x >> 12); + *o++ = 0x80 | ((x >> 6) & 0x3F); + *o++ = 0x80 | (x & 0x3F); } else if (x <= 0x10FFFF) { - *p++ = 0xF0 | (x >> 18); - *p++ = 0x80 | ((x >> 12) & 0x3F); - *p++ = 0x80 | ((x >> 6) & 0x3F); - *p++ = 0x80 | (x & 0x3F); + *o++ = 0xF0 | (x >> 18); + *o++ = 0x80 | ((x >> 12) & 0x3F); + *o++ = 0x80 | ((x >> 6) & 0x3F); + *o++ = 0x80 | (x & 0x3F); } else { - *p++ = 0xEF; /* unicode replacement character in UTF-8 */ - *p++ = 0xBF; - *p++ = 0xBD; + *o++ = 0xEF; /* unicode replacement character in UTF-8 */ + *o++ = 0xBF; + *o++ = 0xBD; } } - *p++ = 0; } else { - /* regular non-utf8 version */ - do { - c = *fname++; - if (c == sep) c = '/'; - else if (c == slash) c = '\'; - else if (lower) c = (unsigned char) tolower((int) c); - } while ((*p++ = c)); + /* non UTF-8 version */ + while (i < iend) { + c = *i++; + if (lower) c = (unsigned char) tolower((int) c); + if (c == sep) c = '/'; else if (c == slash) c = '\'; + *o++ = c; + } + } + *o++ = '\0'; + + /* remove any leading slashes in the cab filename part. + * This prevents unintended absolute file path access. */ + o = (unsigned char *) &name[dirlen]; + for (i = o; *i == '/' || *i == '\'; i++); + if (i != o) { + size_t len = strlen((char *) i); + if (len > 0) { + memmove(o, i, len + 1); + } + else { + /* change filename composed entirely of leading slashes to "x" */ + strcpy((char *) o, "x"); + } } - /* search for "../" in cab filename part and change to "xx/". This - * prevents any unintended directory traversal. */ - for (p = &name[dir ? strlen((char *) dir)+1 : 0]; *p; p++) { - if ((p[0] == '.') && (p[1] == '.') && (p[2] == '/')) { - p[0] = p[1] = 'x'; - p += 2; + /* search for "../" or ".." in cab filename part and change to "xx" + * This prevents unintended directory traversal. */ + for (; *o; o++) { + if ((o[0] == '.') && (o[1] == '.') && (o[2] == '/' || o[2] == '\')) { + o[0] = o[1] = 'x'; + o += 2; } } - return (char *) name; + return name; } /**