0004-unzip-6.0-alt-iconv-utf8.patch (14356B)
1 From: Giovanni Scafora <giovanni.archlinux.org> 2 Subject: unzip files encoded with non-latin, non-unicode file names 3 Last-Update: 2015-02-11 4 5 Updated 2015-02-11 by Marc Deslauriers <marc.deslauriers@canonical.com> 6 to fix buffer overflow in charset_to_intern() 7 8 Index: unzip-6.0/unix/unix.c 9 =================================================================== 10 --- unzip-6.0.orig/unix/unix.c 2015-02-11 08:46:43.675324290 -0500 11 +++ unzip-6.0/unix/unix.c 2015-02-11 09:18:04.902081319 -0500 12 @@ -30,6 +30,9 @@ 13 #define UNZIP_INTERNAL 14 #include "unzip.h" 15 16 +#include <iconv.h> 17 +#include <langinfo.h> 18 + 19 #ifdef SCO_XENIX 20 # define SYSNDIR 21 #else /* SCO Unix, AIX, DNIX, TI SysV, Coherent 4.x, ... */ 22 @@ -1874,3 +1877,102 @@ 23 } 24 } 25 #endif /* QLZIP */ 26 + 27 + 28 +typedef struct { 29 + char *local_charset; 30 + char *archive_charset; 31 +} CHARSET_MAP; 32 + 33 +/* A mapping of local <-> archive charsets used by default to convert filenames 34 + * of DOS/Windows Zip archives. Currently very basic. */ 35 +static CHARSET_MAP dos_charset_map[] = { 36 + { "ANSI_X3.4-1968", "CP850" }, 37 + { "ISO-8859-1", "CP850" }, 38 + { "CP1252", "CP850" }, 39 + { "UTF-8", "CP866" }, 40 + { "KOI8-R", "CP866" }, 41 + { "KOI8-U", "CP866" }, 42 + { "ISO-8859-5", "CP866" } 43 +}; 44 + 45 +char OEM_CP[MAX_CP_NAME] = ""; 46 +char ISO_CP[MAX_CP_NAME] = ""; 47 + 48 +/* Try to guess the default value of OEM_CP based on the current locale. 49 + * ISO_CP is left alone for now. */ 50 +void init_conversion_charsets() 51 +{ 52 + const char *local_charset; 53 + int i; 54 + 55 + /* Make a guess only if OEM_CP not already set. */ 56 + if(*OEM_CP == '\0') { 57 + local_charset = nl_langinfo(CODESET); 58 + for(i = 0; i < sizeof(dos_charset_map)/sizeof(CHARSET_MAP); i++) 59 + if(!strcasecmp(local_charset, dos_charset_map[i].local_charset)) { 60 + strncpy(OEM_CP, dos_charset_map[i].archive_charset, 61 + sizeof(OEM_CP)); 62 + break; 63 + } 64 + } 65 +} 66 + 67 +/* Convert a string from one encoding to the current locale using iconv(). 68 + * Be as non-intrusive as possible. If error is encountered during covertion 69 + * just leave the string intact. */ 70 +static void charset_to_intern(char *string, char *from_charset) 71 +{ 72 + iconv_t cd; 73 + char *s,*d, *buf; 74 + size_t slen, dlen, buflen; 75 + const char *local_charset; 76 + 77 + if(*from_charset == '\0') 78 + return; 79 + 80 + buf = NULL; 81 + local_charset = nl_langinfo(CODESET); 82 + 83 + if((cd = iconv_open(local_charset, from_charset)) == (iconv_t)-1) 84 + return; 85 + 86 + slen = strlen(string); 87 + s = string; 88 + 89 + /* Make sure OUTBUFSIZ + 1 never ends up smaller than FILNAMSIZ 90 + * as this function also gets called with G.outbuf in fileio.c 91 + */ 92 + buflen = FILNAMSIZ; 93 + if (OUTBUFSIZ + 1 < FILNAMSIZ) 94 + { 95 + buflen = OUTBUFSIZ + 1; 96 + } 97 + 98 + d = buf = malloc(buflen); 99 + if(!d) 100 + goto cleanup; 101 + 102 + bzero(buf,buflen); 103 + dlen = buflen - 1; 104 + 105 + if(iconv(cd, &s, &slen, &d, &dlen) == (size_t)-1) 106 + goto cleanup; 107 + strncpy(string, buf, buflen); 108 + 109 + cleanup: 110 + free(buf); 111 + iconv_close(cd); 112 +} 113 + 114 +/* Convert a string from OEM_CP to the current locale charset. */ 115 +inline void oem_intern(char *string) 116 +{ 117 + charset_to_intern(string, OEM_CP); 118 +} 119 + 120 +/* Convert a string from ISO_CP to the current locale charset. */ 121 +inline void iso_intern(char *string) 122 +{ 123 + charset_to_intern(string, ISO_CP); 124 +} 125 Index: unzip-6.0/unix/unxcfg.h 126 =================================================================== 127 --- unzip-6.0.orig/unix/unxcfg.h 2015-02-11 08:46:43.675324290 -0500 128 +++ unzip-6.0/unix/unxcfg.h 2015-02-11 08:46:43.671324260 -0500 129 @@ -228,4 +228,30 @@ 130 /* wild_dir, dirname, wildname, matchname[], dirnamelen, have_dirname, */ 131 /* and notfirstcall are used by do_wild(). */ 132 133 + 134 +#define MAX_CP_NAME 25 135 + 136 +#ifdef SETLOCALE 137 +# undef SETLOCALE 138 +#endif 139 +#define SETLOCALE(category, locale) setlocale(category, locale) 140 +#include <locale.h> 141 + 142 +#ifdef _ISO_INTERN 143 +# undef _ISO_INTERN 144 +#endif 145 +#define _ISO_INTERN(str1) iso_intern(str1) 146 + 147 +#ifdef _OEM_INTERN 148 +# undef _OEM_INTERN 149 +#endif 150 +#ifndef IZ_OEM2ISO_ARRAY 151 +# define IZ_OEM2ISO_ARRAY 152 +#endif 153 +#define _OEM_INTERN(str1) oem_intern(str1) 154 + 155 +void iso_intern(char *); 156 +void oem_intern(char *); 157 +void init_conversion_charsets(void); 158 + 159 #endif /* !__unxcfg_h */ 160 Index: unzip-6.0/unzip.c 161 =================================================================== 162 --- unzip-6.0.orig/unzip.c 2015-02-11 08:46:43.675324290 -0500 163 +++ unzip-6.0/unzip.c 2015-02-11 08:46:43.675324290 -0500 164 @@ -327,11 +327,21 @@ 165 -2 just filenames but allow -h/-t/-z -l long Unix \"ls -l\" format\n\ 166 -v verbose, multi-page format\n"; 167 168 +#ifndef UNIX 169 static ZCONST char Far ZipInfoUsageLine3[] = "miscellaneous options:\n\ 170 -h print header line -t print totals for listed files or for all\n\ 171 -z print zipfile comment -T print file times in sortable decimal format\ 172 \n -C be case-insensitive %s\ 173 -x exclude filenames that follow from listing\n"; 174 +#else /* UNIX */ 175 +static ZCONST char Far ZipInfoUsageLine3[] = "miscellaneous options:\n\ 176 + -h print header line -t print totals for listed files or for all\n\ 177 + -z print zipfile comment %c-T%c print file times in sortable decimal format\ 178 +\n %c-C%c be case-insensitive %s\ 179 + -x exclude filenames that follow from listing\n\ 180 + -O CHARSET specify a character encoding for DOS, Windows and OS/2 archives\n\ 181 + -I CHARSET specify a character encoding for UNIX and other archives\n"; 182 +#endif /* !UNIX */ 183 #ifdef MORE 184 static ZCONST char Far ZipInfoUsageLine4[] = 185 " -M page output through built-in \"more\"\n"; 186 @@ -664,6 +674,17 @@ 187 -U use escapes for all non-ASCII Unicode -UU ignore any Unicode fields\n\ 188 -C match filenames case-insensitively -L make (some) names \ 189 lowercase\n %-42s -V retain VMS version numbers\n%s"; 190 +#elif (defined UNIX) 191 +static ZCONST char Far UnzipUsageLine4[] = "\ 192 +modifiers:\n\ 193 + -n never overwrite existing files -q quiet mode (-qq => quieter)\n\ 194 + -o overwrite files WITHOUT prompting -a auto-convert any text files\n\ 195 + -j junk paths (do not make directories) -aa treat ALL files as text\n\ 196 + -U use escapes for all non-ASCII Unicode -UU ignore any Unicode fields\n\ 197 + -C match filenames case-insensitively -L make (some) names \ 198 +lowercase\n %-42s -V retain VMS version numbers\n%s\ 199 + -O CHARSET specify a character encoding for DOS, Windows and OS/2 archives\n\ 200 + -I CHARSET specify a character encoding for UNIX and other archives\n\n"; 201 #else /* !VMS */ 202 static ZCONST char Far UnzipUsageLine4[] = "\ 203 modifiers:\n\ 204 @@ -802,6 +823,10 @@ 205 #endif /* UNICODE_SUPPORT */ 206 207 208 +#ifdef UNIX 209 + init_conversion_charsets(); 210 +#endif 211 + 212 #if (defined(__IBMC__) && defined(__DEBUG_ALLOC__)) 213 extern void DebugMalloc(void); 214 215 @@ -1335,6 +1360,11 @@ 216 argc = *pargc; 217 argv = *pargv; 218 219 +#ifdef UNIX 220 + extern char OEM_CP[MAX_CP_NAME]; 221 + extern char ISO_CP[MAX_CP_NAME]; 222 +#endif 223 + 224 while (++argv, (--argc > 0 && *argv != NULL && **argv == '-')) { 225 s = *argv + 1; 226 while ((c = *s++) != 0) { /* "!= 0": prevent Turbo C warning */ 227 @@ -1516,6 +1546,35 @@ 228 } 229 break; 230 #endif /* MACOS */ 231 +#ifdef UNIX 232 + case ('I'): 233 + if (negative) { 234 + Info(slide, 0x401, ((char *)slide, 235 + "error: encodings can't be negated")); 236 + return(PK_PARAM); 237 + } else { 238 + if(*s) { /* Handle the -Icharset case */ 239 + /* Assume that charsets can't start with a dash to spot arguments misuse */ 240 + if(*s == '-') { 241 + Info(slide, 0x401, ((char *)slide, 242 + "error: a valid character encoding should follow the -I argument")); 243 + return(PK_PARAM); 244 + } 245 + strncpy(ISO_CP, s, sizeof(ISO_CP)); 246 + } else { /* -I charset */ 247 + ++argv; 248 + if(!(--argc > 0 && *argv != NULL && **argv != '-')) { 249 + Info(slide, 0x401, ((char *)slide, 250 + "error: a valid character encoding should follow the -I argument")); 251 + return(PK_PARAM); 252 + } 253 + s = *argv; 254 + strncpy(ISO_CP, s, sizeof(ISO_CP)); 255 + } 256 + while(*(++s)); /* No params straight after charset name */ 257 + } 258 + break; 259 +#endif /* ?UNIX */ 260 case ('j'): /* junk pathnames/directory structure */ 261 if (negative) 262 uO.jflag = FALSE, negative = 0; 263 @@ -1591,6 +1650,35 @@ 264 } else 265 ++uO.overwrite_all; 266 break; 267 +#ifdef UNIX 268 + case ('O'): 269 + if (negative) { 270 + Info(slide, 0x401, ((char *)slide, 271 + "error: encodings can't be negated")); 272 + return(PK_PARAM); 273 + } else { 274 + if(*s) { /* Handle the -Ocharset case */ 275 + /* Assume that charsets can't start with a dash to spot arguments misuse */ 276 + if(*s == '-') { 277 + Info(slide, 0x401, ((char *)slide, 278 + "error: a valid character encoding should follow the -I argument")); 279 + return(PK_PARAM); 280 + } 281 + strncpy(OEM_CP, s, sizeof(OEM_CP)); 282 + } else { /* -O charset */ 283 + ++argv; 284 + if(!(--argc > 0 && *argv != NULL && **argv != '-')) { 285 + Info(slide, 0x401, ((char *)slide, 286 + "error: a valid character encoding should follow the -O argument")); 287 + return(PK_PARAM); 288 + } 289 + s = *argv; 290 + strncpy(OEM_CP, s, sizeof(OEM_CP)); 291 + } 292 + while(*(++s)); /* No params straight after charset name */ 293 + } 294 + break; 295 +#endif /* ?UNIX */ 296 case ('p'): /* pipes: extract to stdout, no messages */ 297 if (negative) { 298 uO.cflag = FALSE; 299 Index: unzip-6.0/unzpriv.h 300 =================================================================== 301 --- unzip-6.0.orig/unzpriv.h 2015-02-11 08:46:43.675324290 -0500 302 +++ unzip-6.0/unzpriv.h 2015-02-11 08:46:43.675324290 -0500 303 @@ -3008,7 +3008,7 @@ 304 !(((islochdr) || (isuxatt)) && \ 305 ((hostver) == 25 || (hostver) == 26 || (hostver) == 40))) || \ 306 (hostnum) == FS_HPFS_ || \ 307 - ((hostnum) == FS_NTFS_ && (hostver) == 50)) { \ 308 + ((hostnum) == FS_NTFS_ /* && (hostver) == 50 */ )) { \ 309 _OEM_INTERN((string)); \ 310 } else { \ 311 _ISO_INTERN((string)); \ 312 Index: unzip-6.0/zipinfo.c 313 =================================================================== 314 --- unzip-6.0.orig/zipinfo.c 2015-02-11 08:46:43.675324290 -0500 315 +++ unzip-6.0/zipinfo.c 2015-02-11 08:46:43.675324290 -0500 316 @@ -457,6 +457,10 @@ 317 int tflag_slm=TRUE, tflag_2v=FALSE; 318 int explicit_h=FALSE, explicit_t=FALSE; 319 320 +#ifdef UNIX 321 + extern char OEM_CP[MAX_CP_NAME]; 322 + extern char ISO_CP[MAX_CP_NAME]; 323 +#endif 324 325 #ifdef MACOS 326 uO.lflag = LFLAG; /* reset default on each call */ 327 @@ -501,6 +505,35 @@ 328 uO.lflag = 0; 329 } 330 break; 331 +#ifdef UNIX 332 + case ('I'): 333 + if (negative) { 334 + Info(slide, 0x401, ((char *)slide, 335 + "error: encodings can't be negated")); 336 + return(PK_PARAM); 337 + } else { 338 + if(*s) { /* Handle the -Icharset case */ 339 + /* Assume that charsets can't start with a dash to spot arguments misuse */ 340 + if(*s == '-') { 341 + Info(slide, 0x401, ((char *)slide, 342 + "error: a valid character encoding should follow the -I argument")); 343 + return(PK_PARAM); 344 + } 345 + strncpy(ISO_CP, s, sizeof(ISO_CP)); 346 + } else { /* -I charset */ 347 + ++argv; 348 + if(!(--argc > 0 && *argv != NULL && **argv != '-')) { 349 + Info(slide, 0x401, ((char *)slide, 350 + "error: a valid character encoding should follow the -I argument")); 351 + return(PK_PARAM); 352 + } 353 + s = *argv; 354 + strncpy(ISO_CP, s, sizeof(ISO_CP)); 355 + } 356 + while(*(++s)); /* No params straight after charset name */ 357 + } 358 + break; 359 +#endif /* ?UNIX */ 360 case 'l': /* longer form of "ls -l" type listing */ 361 if (negative) 362 uO.lflag = -2, negative = 0; 363 @@ -521,6 +554,35 @@ 364 G.M_flag = TRUE; 365 break; 366 #endif 367 +#ifdef UNIX 368 + case ('O'): 369 + if (negative) { 370 + Info(slide, 0x401, ((char *)slide, 371 + "error: encodings can't be negated")); 372 + return(PK_PARAM); 373 + } else { 374 + if(*s) { /* Handle the -Ocharset case */ 375 + /* Assume that charsets can't start with a dash to spot arguments misuse */ 376 + if(*s == '-') { 377 + Info(slide, 0x401, ((char *)slide, 378 + "error: a valid character encoding should follow the -I argument")); 379 + return(PK_PARAM); 380 + } 381 + strncpy(OEM_CP, s, sizeof(OEM_CP)); 382 + } else { /* -O charset */ 383 + ++argv; 384 + if(!(--argc > 0 && *argv != NULL && **argv != '-')) { 385 + Info(slide, 0x401, ((char *)slide, 386 + "error: a valid character encoding should follow the -O argument")); 387 + return(PK_PARAM); 388 + } 389 + s = *argv; 390 + strncpy(OEM_CP, s, sizeof(OEM_CP)); 391 + } 392 + while(*(++s)); /* No params straight after charset name */ 393 + } 394 + break; 395 +#endif /* ?UNIX */ 396 case 's': /* default: shorter "ls -l" type listing */ 397 if (negative) 398 uO.lflag = -2, negative = 0;