]> git.ipfire.org Git - thirdparty/libarchive.git/commitdiff
Update RAR5 code to report encryption (#2096)
authorDuncan Horn <40036384+dunhor@users.noreply.github.com>
Fri, 11 Oct 2024 06:25:47 +0000 (23:25 -0700)
committerGitHub <noreply@github.com>
Fri, 11 Oct 2024 06:25:47 +0000 (08:25 +0200)
Currently, the RAR5 code always reports
`ARCHIVE_READ_FORMAT_ENCRYPTION_UNSUPPORTED` for
`archive_read_has_encrypted_entries`, nor does it set any of the
entry-specific properties, even though it has enough information to
properly report this information. Accurate reporting of encryption is
super useful for applications because reporting an error message such as
"the archive is encrypted, but we don't currently support encryption" is
a lot better than a not generally useful `errno` value and a
non-localizable error string with a confusing and unpredictable error
message.

Fixes #1661

13 files changed:
Makefile.am
libarchive/archive_read_support_format_rar5.c
libarchive/test/CMakeLists.txt
libarchive/test/test_read_format_rar4_encrypted.rar.uu [new file with mode: 0644]
libarchive/test/test_read_format_rar4_encrypted_filenames.rar.uu [new file with mode: 0644]
libarchive/test/test_read_format_rar4_solid_encrypted.rar.uu [new file with mode: 0644]
libarchive/test/test_read_format_rar4_solid_encrypted_filenames.rar.uu [new file with mode: 0644]
libarchive/test/test_read_format_rar5_encrypted.rar.uu [new file with mode: 0644]
libarchive/test/test_read_format_rar5_encrypted_filenames.rar.uu [new file with mode: 0644]
libarchive/test/test_read_format_rar5_solid_encrypted.rar.uu [new file with mode: 0644]
libarchive/test/test_read_format_rar5_solid_encrypted_filenames.rar.uu [new file with mode: 0644]
libarchive/test/test_read_format_rar_encryption.c [new file with mode: 0644]
libarchive/test/test_write_format_zip_stream.c

index 8d6c9f717055e68ee5f06b67be7c73c7cb7cf2c6..e3dbdb1d016390a79762b2fdd0deac68cfba1222 100644 (file)
@@ -510,6 +510,7 @@ libarchive_test_SOURCES= \
        libarchive/test/test_read_format_mtree_crash747.c \
        libarchive/test/test_read_format_pax_bz2.c \
        libarchive/test/test_read_format_rar.c \
+       libarchive/test/test_read_format_rar_encryption.c \
        libarchive/test/test_read_format_rar_encryption_data.c \
        libarchive/test/test_read_format_rar_encryption_partially.c \
        libarchive/test/test_read_format_rar_encryption_header.c \
@@ -888,6 +889,14 @@ libarchive_test_EXTRA_DIST=\
        libarchive/test/test_read_format_rar_subblock.rar.uu \
        libarchive/test/test_read_format_rar_unicode.rar.uu \
        libarchive/test/test_read_format_rar_windows.rar.uu \
+       libarchive/test/test_read_format_rar4_encrypted.rar.uu \
+       libarchive/test/test_read_format_rar4_encrypted_filenames.rar.uu \
+       libarchive/test/test_read_format_rar4_solid_encrypted.rar.uu \
+       libarchive/test/test_read_format_rar4_solid_encrypted_filenames.rar.uu \
+       libarchive/test/test_read_format_rar5_encrypted.rar.uu \
+       libarchive/test/test_read_format_rar5_encrypted_filenames.rar.uu \
+       libarchive/test/test_read_format_rar5_solid_encrypted.rar.uu \
+       libarchive/test/test_read_format_rar5_solid_encrypted_filenames.rar.uu \
        libarchive/test/test_read_format_rar5_arm.rar.uu \
        libarchive/test/test_read_format_rar5_blake2.rar.uu \
        libarchive/test/test_read_format_rar5_compressed.rar.uu \
index cafd064ad67869a3692657017f1133e65b29a84f..b99105d0cd33456b346c0c07fa33ad042945ee75 100644 (file)
@@ -210,7 +210,11 @@ struct comp_state {
           or just a part of it. */
        uint8_t block_parsing_finished : 1;
 
-       signed int notused : 4;
+       /* Flag used to indicate that a previous file using this buffer was
+          encrypted, meaning no data in the buffer can be trusted */
+       uint8_t data_encrypted : 1;
+
+       signed int notused : 3;
 
        int flags;                   /* Uncompression flags. */
        int method;                  /* Uncompression algorithm method. */
@@ -352,6 +356,12 @@ struct rar5 {
        /* The header of currently processed RARv5 block. Used in main
         * decompression logic loop. */
        struct compressed_block_header last_block_hdr;
+
+       /*
+        * Custom field to denote that this archive contains encrypted entries
+        */
+       int has_encrypted_entries;
+       int headers_are_encrypted;
 };
 
 /* Forward function declarations. */
@@ -1596,6 +1606,7 @@ static int process_head_file_extra(struct archive_read* a,
                if(!read_var(a, &extra_field_id, &var_size))
                        return ARCHIVE_EOF;
 
+               extra_field_size -= var_size;
                extra_data_size -= var_size;
                if(ARCHIVE_OK != consume(a, var_size)) {
                        return ARCHIVE_EOF;
@@ -1623,12 +1634,19 @@ static int process_head_file_extra(struct archive_read* a,
                                    &extra_data_size);
                                break;
                        case EX_CRYPT:
+                               /* Mark the entry as encrypted */
+                               archive_entry_set_is_data_encrypted(e, 1);
+                               rar->has_encrypted_entries = 1;
+                               rar->cstate.data_encrypted = 1;
                                /* fallthrough */
                        case EX_SUBDATA:
                                /* fallthrough */
                        default:
                                /* Skip unsupported entry. */
-                               return consume(a, extra_data_size);
+                               extra_data_size -= extra_field_size;
+                               if (ARCHIVE_OK != consume(a, extra_field_size)) {
+                                       return ARCHIVE_EOF;
+                               }
                }
        }
 
@@ -1746,9 +1764,11 @@ static int process_head_file(struct archive_read* a, struct rar5* rar,
        rar->file.solid = (compression_info & SOLID) > 0;
 
        /* Archives which declare solid files without initializing the window
-        * buffer first are invalid. */
+        * buffer first are invalid, unless previous data was encrypted, in
+        * which case we may never have had the chance */
 
-       if(rar->file.solid > 0 && rar->cstate.window_buf == NULL) {
+       if(rar->file.solid > 0 && rar->cstate.data_encrypted == 0 &&
+           rar->cstate.window_buf == NULL) {
                archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
                                  "Declared solid file, but no window buffer "
                                  "initialized yet.");
@@ -1777,6 +1797,8 @@ static int process_head_file(struct archive_read* a, struct rar5* rar,
                        return ARCHIVE_FATAL;
                }
        }
+       else
+               rar->cstate.data_encrypted = 0; /* Reset for new buffer */
 
        if(rar->cstate.window_size < (ssize_t) window_size &&
            rar->cstate.window_buf)
@@ -2279,6 +2301,10 @@ static int process_base_block(struct archive_read* a,
                        ret = process_head_file(a, rar, entry, header_flags);
                        return ret;
                case HEAD_CRYPT:
+                       archive_entry_set_is_metadata_encrypted(entry, 1);
+                       archive_entry_set_is_data_encrypted(entry, 1);
+                       rar->has_encrypted_entries = 1;
+                       rar->headers_are_encrypted = 1;
                        archive_set_error(&a->archive,
                            ARCHIVE_ERRNO_FILE_FORMAT,
                            "Encryption is not supported");
@@ -2423,6 +2449,14 @@ static int rar5_read_header(struct archive_read *a,
        struct rar5* rar = get_context(a);
        int ret;
 
+       /*
+        * It should be sufficient to call archive_read_next_header() for
+        * a reader to determine if an entry is encrypted or not.
+        */
+       if (rar->has_encrypted_entries == ARCHIVE_READ_FORMAT_ENCRYPTION_DONT_KNOW) {
+               rar->has_encrypted_entries = 0;
+       }
+
        if(rar->header_initialized == 0) {
                init_header(a);
                if ((ret = try_skip_sfx(a)) < ARCHIVE_WARN)
@@ -4083,6 +4117,16 @@ static int rar5_read_data(struct archive_read *a, const void **buff,
        if (size)
                *size = 0;
 
+       if (rar->has_encrypted_entries == ARCHIVE_READ_FORMAT_ENCRYPTION_DONT_KNOW) {
+               rar->has_encrypted_entries = 0;
+       }
+
+       if (rar->headers_are_encrypted || rar->cstate.data_encrypted) {
+               archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
+                   "Reading encrypted data is not currently supported");
+               return ARCHIVE_FATAL;
+       }
+
        if(rar->file.dir > 0) {
                /* Don't process any data if this file entry was declared
                 * as a directory. This is needed, because entries marked as
@@ -4134,11 +4178,14 @@ static int rar5_read_data(struct archive_read *a, const void **buff,
 static int rar5_read_data_skip(struct archive_read *a) {
        struct rar5* rar = get_context(a);
 
-       if(rar->main.solid) {
+       if(rar->main.solid && (rar->cstate.data_encrypted == 0)) {
                /* In solid archives, instead of skipping the data, we need to
                 * extract it, and dispose the result. The side effect of this
                 * operation will be setting up the initial window buffer state
-                * needed to be able to extract the selected file. */
+                * needed to be able to extract the selected file. Note that
+                * this is only possible when data withing this solid block is
+                * not encrypted, in which case we'll skip and fail if the user
+                * tries to read data. */
 
                int ret;
 
@@ -4214,14 +4261,19 @@ static int rar5_cleanup(struct archive_read *a) {
 
 static int rar5_capabilities(struct archive_read * a) {
        (void) a;
-       return 0;
+       return (ARCHIVE_READ_FORMAT_CAPS_ENCRYPT_DATA
+                       | ARCHIVE_READ_FORMAT_CAPS_ENCRYPT_METADATA);
 }
 
 static int rar5_has_encrypted_entries(struct archive_read *_a) {
-       (void) _a;
+       if (_a && _a->format) {
+               struct rar5 *rar = (struct rar5 *)_a->format->data;
+               if (rar) {
+                       return rar->has_encrypted_entries;
+               }
+       }
 
-       /* Unsupported for now. */
-       return ARCHIVE_READ_FORMAT_ENCRYPTION_UNSUPPORTED;
+       return ARCHIVE_READ_FORMAT_ENCRYPTION_DONT_KNOW;
 }
 
 static int rar5_init(struct rar5* rar) {
@@ -4230,6 +4282,12 @@ static int rar5_init(struct rar5* rar) {
        if(CDE_OK != cdeque_init(&rar->cstate.filters, 8192))
                return ARCHIVE_FATAL;
 
+       /*
+        * Until enough data has been read, we cannot tell about
+        * any encrypted entries yet.
+        */
+       rar->has_encrypted_entries = ARCHIVE_READ_FORMAT_ENCRYPTION_DONT_KNOW;
+
        return ARCHIVE_OK;
 }
 
index d34c39c8c66543bae476d6147621d1879ce8f4c5..7d5bc3626f7d410b7845d657a3450b96bd3461e4 100644 (file)
@@ -154,6 +154,7 @@ IF(ENABLE_TEST)
     test_read_format_mtree_crash747.c
     test_read_format_pax_bz2.c
     test_read_format_rar.c
+    test_read_format_rar_encryption.c
     test_read_format_rar_encryption_data.c
     test_read_format_rar_encryption_header.c
     test_read_format_rar_encryption_partially.c
diff --git a/libarchive/test/test_read_format_rar4_encrypted.rar.uu b/libarchive/test/test_read_format_rar4_encrypted.rar.uu
new file mode 100644 (file)
index 0000000..584183b
--- /dev/null
@@ -0,0 +1,10 @@
+begin 0744 test_read_format_rar4_encrypted.rar
+M4F%R(1H'`,^0<P``#0`````````J8W0@D"H`$@```!(````"56Y:[F17=E@=
+M,`4`(````&$N='AT`/#\3!M4:&ES(&ES(&9R;VT@82YT>'1?CG0DE#(`(```
+M`!(````"A13ZJ6=7=E@=,P4`(````&(N='ATO@(;FGDJBE4`L'*@-,GY]@T0
+M?ZC1UGSKU*2VR-1K@HH>GZZP#?C:ML=$"NKDN\=T()`J`!(````2`````C4]
+MFI1N5W98'3`%`"````!C+G1X=`"P/D@M5&AI<R!I<R!F<F]M(&,N='AT[<IT
+M))0R`"`````2`````B7ANB9-9'98'3,%`"````!D+G1X=*_B?1/SI5-2`/#[
+I88]V^#_)1V@;4"TVC,!XR=.I1:KVB0/<OAC@C&97VP3UZ<0]>P!`!P``
+`
+end
diff --git a/libarchive/test/test_read_format_rar4_encrypted_filenames.rar.uu b/libarchive/test/test_read_format_rar4_encrypted_filenames.rar.uu
new file mode 100644 (file)
index 0000000..3d7aa80
--- /dev/null
@@ -0,0 +1,14 @@
+begin 0744 test_read_format_rar4_encrypted_filenames.rar
+M4F%R(1H'`,Z9<X``#0```````````````````'0+AC,H,+6'0#)>8VT<XO:*
+M5M'"E1[V+ZKT=VW!$Y2=W$,@Y24Z^"L_;GVG\*4]&"6BQ#?@6TX38EQ\8\4-
+M<S5U7JMAF.'L3LOOCM6]\Q60C51S.)^'6MOG_R<DW8EG(```````````(B,(
+M]O5[61NCM'\Q9[&<E5D6F6`?WI`#-.(]J?W^C9!U-5O^2='P+5K(ED[:I4T=
+M0/ZHVQ[F8HPBZ<+WA.*T5<R$K+8&/OR_\BN8V5VVM]"5F:$4Y:\JR,),%],1
+MR;Z>``````````#*B0$)1EIB[[O98],X0DT>H`N+&*.NNPK!]1XJ#(AF_TF6
+M0FE3!L0.1T+=I<'X[Z0:F23U_[6S.I:ZNQ.\@HZ\]&0L/P:SA$:,Y<^4.A!\
+MSBD7NK5[VE/9$9K/N2`[7]T``````````.\$Z3?>_Z.3*>6<12%741?6_./A
+M!:XA!P"B0PS55>+%J)-H$0T!//>$']'-U?_"O=N?_:SNE<^54Z3/[8,M^F?6
+M36)XOUNLS4@\\N@1J#Z/V?J<_XS>CNA21,<Q;<;C[@``````````\)]%=^L\
+*)-I(DJO^>177HP``
+`
+end
diff --git a/libarchive/test/test_read_format_rar4_solid_encrypted.rar.uu b/libarchive/test/test_read_format_rar4_solid_encrypted.rar.uu
new file mode 100644 (file)
index 0000000..7d73ee8
--- /dev/null
@@ -0,0 +1,11 @@
+begin 0744 test_read_format_rar4_solid_encrypted.dat
+M4F%R(1H'`#O0<P@`#0`````````A873$E#(`,````!(````"56Y:[F17=E@=
+M,P4`(````&$N='AT````````````\/Q,&]Q,RV`3V)H10_&#G@'FZ'@$+I%W
+MXP?A#XMQ>A-D/\9QH!R+,]AV(8F*MQD3.<V`SC96=-24,@`0````$@````*%
+M%/JI9U=V6!TS!0`@````8BYT>'2/%M7(05"L]0"P<J`TBK7M!JH)_:_8K\\K
+M,U_X>\,C=-24,@`0````$@````(U/9J4;E=V6!TS!0`@````8RYT>'1ILB:<
+M@2)@M@"P/D@MD'UA]R2N^_G@1!L-H?V>K-TV=-24,@`0````$@````(EX;HF
+M361V6!TS!0`@````9"YT>'2C+AKDKML%S0#P^V&/?J,L#@>!52=M.=PPCAJF
+(IL0]>P!`!P``
+`
+end
diff --git a/libarchive/test/test_read_format_rar4_solid_encrypted_filenames.rar.uu b/libarchive/test/test_read_format_rar4_solid_encrypted_filenames.rar.uu
new file mode 100644 (file)
index 0000000..6c28e95
--- /dev/null
@@ -0,0 +1,13 @@
+begin 0744 test_read_format_rar4_solid_encrypted_filenames.rar
+M4F%R(1H'`#K9<X@`#0```````````````````,L":IWIGA+/YV2@]#O3Z\&O
+MM'G1)=DT/G2[DW184@7Z`)NZR=<IA_-5+=&`P_B)U/,]<+8]C:YI<X@;OT`3
+M]?.U#K0BV:I"0AYHE-->?V[74Q\@?])NR\68105J4BRL3O.E$I*!91X?$@/<
+M5C[G2D$``````````!NS=YISD[7`_=#)$A.9/&9<3`&D$(L]$^-&%;!SH,%>
+M!NZ:W\)5XCJI<"H7+BND(033Q/J9/18(=/`A%WI]@(`:H>AE`M3T)R8']S%P
+MHYCV```````````&TB\_##3K6#@Q+J)RDEJ0$CI"]*R1)8!Q.3B[,7O5NM,]
+ME::7;E__N2:-%4-;/D+DA:J@P.L0*I/__*OX77=\L4-&F^""&L'VP9/DK-;$
+MLP``````````1D.3Y0+"D$@9F(IYV&*B<`A2J2$)(C=_X_QEMWE*VK9ITH*U
+MAJ@<<Z%4#?(I"H:5J08&7^WM`<#3=A9D#':;X2IVK.%[ZZ#58(4W0Q[RT-X`
+7`````````/"?17?K/"3:2)*K_GD5UZ,`
+`
+end
diff --git a/libarchive/test/test_read_format_rar5_encrypted.rar.uu b/libarchive/test/test_read_format_rar5_encrypted.rar.uu
new file mode 100644 (file)
index 0000000..0a52fa2
--- /dev/null
@@ -0,0 +1,12 @@
+begin 0744 test_read_format_rar5_encrypted.rar
+M4F%R(1H'`0`SDK7E"@$%!@`%`0&`@``U_S(>'P(#"Q($$B!5;EKN@```!6$N
+M='AT"@,"?"&$HX)\V@%4:&ES(&ES(&9R;VT@82YT>'1Z07&S4`(#/#`$$B`8
+M1:,"@`,`!6(N='AT,`$``P_'1%[A@/BUG]8K0S<(O%?-^C3?!JM=!=23!W</
+M'8Z`4^HU9QUP\2U+:YP:G`H#`G)EF*:"?-H!8[I4LM`0I4E?M+K3P&FH.QN\
+MNS@GUX>3>',O?)/BTBC$`-[^IL`[?FQGU`50`-SXC7SQ9A\"`PL2!!(@-3V:
+ME(````5C+G1X=`H#`CY(Z:Z"?-H!5&AI<R!I<R!F<F]M(&,N='AT[/WP75("
+M`SR@``22`"##WV,2@`,`!60N='AT,`$``P_'1%[A@/BUG]8K0S<(O%?-\\W6
+MLQRT6Z=\K#98CK,.:8-,U$CI%>O6K'>WHPH#`GO%*?2/?-H!VVER]/96CJ;]
+?&67IE;,VA30W]2J@TR>'LO7!`C+8JEX==U91`P4$````
+`
+end
diff --git a/libarchive/test/test_read_format_rar5_encrypted_filenames.rar.uu b/libarchive/test/test_read_format_rar5_encrypted_filenames.rar.uu
new file mode 100644 (file)
index 0000000..931240a
--- /dev/null
@@ -0,0 +1,19 @@
+begin 0744 test_read_format_rar5_encrypted_filenames.rar
+M4F%R(1H'`0"N(]*0(00```$/:`NPT*?(O:'>=*=Q,C2;&;<*@A@[)[D`X\II
+M)1#LA,>A'D8M?0XU3L36UDKMZ3EWQ[HCXZ3<%!O*=.Y,W/S<QCA?O/:*,^Z5
+M=M6S3*Y6;+35C`9`*4W]<':72F3'&:K>,FBUJV)T^1MW,X0)C4P7W(`"$#-N
+MQ\V%/Z&YJ=4A7#WA+9.5'__1CF)4F:?SV[[N1U^16P.+TQ5X.'"@NQ"=6K3Z
+M>:;.1CVE<%%M1-OQ3L0FZ[KI2TSW`.2SF20<ZT/,=/(WK4+9"\+J&$')_3V,
+MFW%?=^[MI.6[JA/>0V5WTB3-QIV<3Q'?++X$0]?XV(?ER,71CAXBNL1KT5A*
+M8*&+T@6]A_)*KA]%V3S,0B;S(LW1V.AH.U6U0N\-%!@J9Q-FJ%^'O)(JR5+2
+MS$5JO/XA3W4MSJ[R27%P_4$GAWSW!SS(4IA_-)Z:[:?V5D!F@TGG9L0!1TF[
+M:AH<9G0.['%7-\:>"&(8Y#Z#62;U.:,3+=<$E6S8C02I[/<OZ>G>-3P1Y<'J
+MW_FJ/]VJ-Q7IA64<?`;GTW<H]@=YS0)S*\?SKXQ$H.Y!<ZK`[1[?Z(\(_\]>
+MU:_TK/EHMM;PWJ?3`Y9S6&%6L@T0-U<&4E[+_F>Z%+KFW'&W>`,.=]#SI;A[
+MYA);NM6`5K01J]@IT6O8W#!].A$%_5M\E]S0&<D`"T,:H7>.TOPBCL9$C"GU
+M2<W)Q\9ABJLH57<$#;&%<^N#-N[5KE?`56,WSHG<GU4!!.+@ZU+5N\;J[7J-
+M**R#V\19<I;O[I%?-002U,8R$.^M/P8W]?26N+VB5-\B#7;SV;_L#%4PQ36P
+MBTTF>G&8E))@.H01Q:@1Q^.YVYIG(?#2:S604D\'CWU.!:-E`=;4VFS+KULL
+KJ<2G@G$-MF5V72TYY!]U(UB473O?`U'=W'#D\4A%S-_F?/@]S)MU>.[V1```
+`
+end
diff --git a/libarchive/test/test_read_format_rar5_solid_encrypted.rar.uu b/libarchive/test/test_read_format_rar5_solid_encrypted.rar.uu
new file mode 100644 (file)
index 0000000..d3113a3
--- /dev/null
@@ -0,0 +1,14 @@
+begin 0744 test_read_format_rar5_solid_encrypted.rar
+M4F%R(1H'`0`@MOH1"@$%!@0%`0&`@`!A#\6>4@(#/+``!)(`(%5N6NZ`0P`%
+M82YT>'0P`0`!#X`.^EM!19`,=C!0B-G+#?0([51UI],+OH^T\:=V\5`OX@\X
+M+B?>=W@0'[TD"@,"?"&$HX)\V@$UI92M^>J?V-L?2@`2L023@_#?H\C>K?GG
+MDT*27O`>\]$\(4^12SZAD2GI6I(?@NS\ETUG4@(#/)``!)(`(#W[M6/`0P`%
+M8BYT>'0P`0`##X`.^EM!19`,=C!0B-G+#?09'G;UMT5!4+;8`6WM=*[?X@\X
+M+B?>=W@0'[TD"@,"<F68IH)\V@$C,XZR45`RX*-59&X3Y'+)'7P<"E("`SR0
+M``22`"#_)YR&P$,`!6,N='AT,`$``P^`#OI;0460#'8P4(C9RPWT6V3<1-F,
+M1I0"0-:R/5=BUN(/."XGWG=X$!^])`H#`CY(Z:Z"?-H!BBA?J'.;?7%L12A&
+M0%6=`D>/[#]2`@,\D``$D@`@>Q=TP\!#``5D+G1X=#`!``,/@`[Z6T%%D`QV
+M,%"(V<L-]&ES:(+U/SMVI#;?U9:@A&OB#S@N)]YW>!`?O20*`P)[Q2GTCWS:
+9`3G@<$3$LKSYCC7DX.K9`[`==U91`P4$````
+`
+end
diff --git a/libarchive/test/test_read_format_rar5_solid_encrypted_filenames.rar.uu b/libarchive/test/test_read_format_rar5_solid_encrypted_filenames.rar.uu
new file mode 100644 (file)
index 0000000..4f3dbfb
--- /dev/null
@@ -0,0 +1,18 @@
+begin 0744 test_read_format_rar5_solid_encrypted_filenames.rar
+M4F%R(1H'`0";0=T:(00```$/AC5`PSS2$L"IUF$&I":C])K[3<7Y3A09X<`H
+M`7''7U?%(MHPZ3W;#Z7PZEC<2`T4N9L0A@JE?=;1"4#J%N#6H+4KYITU<*=Q
+MG$W?R7^W[#&LN^@M8(VSG.,@!1JFX359D^5#S[,ZW]V]CJ'J?-Z!KX^]Y1FB
+M8I%5/(^2-8V^KY:K1^?K`DVW*MUL>Q9_6`W#,2ST:17"'W'YF2?)NH%5V"_F
+M7;[0VI^.\JJ-T,_(\\5#ZX1HVQJ7KU0UCF#FGD-?NRMKA;X<,[/[*94^27X,
+M#)I<:BO^_-I%B&A1U>S)9__""\/M>Q5AIY'*]EPTNJW+.J57[$X\U:;W">Z;
+M8P\Z0[ZQOI*B*?BJ?B5+(/Z4.4AJ@;()1YUV4+XY#!76WZV]LZ+;GZ_Q#LLP
+MP`7??+NV**I(A-9N^7HX\V!+YJ3%;R<PA5#T<.1"/TKRXC6SM=>%MD?Q5&H@
+M>$VAME3"U$312+@SF+8F2RR0)T"DG^4N,^P46&+TZKQ7KS`4@-:J%_["UP"(
+MK=]N^!UJUO2#6Q*`-`-)^?\/`;^4(@FVLVJ?!D,:O)A6@!TNA%.U^"0-?9H<
+M:0&(UWV=+&[82L>'L4XYO20"@)^<WC4/BKMBFP0G&/3,!*[Y+,F),*X7V7]H
+M3&`4SIL,>I']_<2C]D;_,]/)_1?N1+M@PTDL;'[J1L=5\,-?J5Q`$3>_9<2<
+MS^)#MZ*AE=5@5[O(<]*(EIA62$U`5B18?#W;BB.*0A3O%<OI.7X`?QB-FRV]
+M89*8RNH'P\"9I,0X&F;$<0Z70E(,^KF&PZ5WR-O%K;G`"/=E<\4-*H%FZ]O3
+8G%A)/>[(IVC3ME2PY5F>9$/U'$VW1-BZ
+`
+end
diff --git a/libarchive/test/test_read_format_rar_encryption.c b/libarchive/test/test_read_format_rar_encryption.c
new file mode 100644 (file)
index 0000000..233caad
--- /dev/null
@@ -0,0 +1,176 @@
+/*\r
+ * Copyright (c) 2003-2018\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms, with or without\r
+ * modification, are permitted provided that the following conditions\r
+ * are met:\r
+ * 1. Redistributions of source code must retain the above copyright\r
+ *    notice, this list of conditions and the following disclaimer\r
+ *    in this position and unchanged.\r
+ * 2. Redistributions in binary form must reproduce the above copyright\r
+ *    notice, this list of conditions and the following disclaimer in the\r
+ *    documentation and/or other materials provided with the distribution.\r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR\r
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\r
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\r
+ * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,\r
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT\r
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\r
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\r
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF\r
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
+ */\r
+#include "test.h"\r
+\r
+/*\r
+ * All of the archives for this teset contain four files: a.txt, b.txt, c.txt, and d.txt\r
+ * For solid archives or archvies or archives where filenames are encrypted, all four files are encrypted with the\r
+ * password "password". For non-solid archives without filename encryption, a.txt and c.txt are not encrypted, b.txt is\r
+ * encrypted with the password "password", and d.txt is encrypted with the password "password2".\r
+ *\r
+ * For all files the file contents is "This is from <filename>" (i.e. "This is from a.txt" etc.)\r
+ */\r
+static void test_encrypted_rar_archive(const char *filename, int filenamesEncrypted, int solid)\r
+{\r
+       struct archive_entry *ae;\r
+       struct archive *a;\r
+       char buff[128];\r
+       int expected_read_header_result, expected_read_data_result;\r
+       const int expected_file_size = 18; /* This is from X.txt */\r
+\r
+       /* We should only ever fail to read the header when filenames are encrypted. Otherwise we're failing for other\r
+        * unsupported reasons, in which case we have no hope of detecting encryption */\r
+       expected_read_header_result = filenamesEncrypted ? ARCHIVE_FATAL : ARCHIVE_OK;\r
+\r
+       /* We should only ever fail to read the data for "a.txt" and "c.txt" if they are encrypted */\r
+       /* NOTE: We'll never attempt this when filenames are encrypted, so we only check for solid here */\r
+       expected_read_data_result = solid ? ARCHIVE_FATAL : expected_file_size;\r
+\r
+       extract_reference_file(filename);\r
+       assert((a = archive_read_new()) != NULL);\r
+       assertEqualIntA(a, ARCHIVE_OK, archive_read_support_filter_all(a));\r
+       assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_all(a));\r
+       assertEqualIntA(a, ARCHIVE_OK, archive_read_open_filename(a, filename, 10240));\r
+\r
+       /* No data read yet; encryption unknown */\r
+       assertEqualInt(ARCHIVE_READ_FORMAT_ENCRYPTION_DONT_KNOW, archive_read_has_encrypted_entries(a));\r
+\r
+       /* Read the header for "a.txt" */\r
+       assertEqualIntA(a, expected_read_header_result, archive_read_next_header(a, &ae));\r
+       if (!filenamesEncrypted) {\r
+               assertEqualInt((AE_IFREG | 0644), archive_entry_mode(ae));\r
+               assertEqualString("a.txt", archive_entry_pathname(ae));\r
+               assertEqualInt(expected_file_size, archive_entry_size(ae));\r
+               assertEqualInt(solid, archive_entry_is_data_encrypted(ae));\r
+               assertEqualInt(0, archive_entry_is_metadata_encrypted(ae));\r
+               /* NOTE: The reader will set this value to zero on the first header that it reads, even if later entries\r
+                * are encrypted */\r
+               assertEqualInt(solid, archive_read_has_encrypted_entries(a));\r
+               assertEqualIntA(a, expected_read_data_result, archive_read_data(a, buff, sizeof(buff)));\r
+               if (!solid) {\r
+                       assertEqualMem("This is from a.txt", buff, expected_file_size);\r
+               }\r
+       }\r
+       else {\r
+               assertEqualInt(1, archive_entry_is_data_encrypted(ae));\r
+               assertEqualInt(1, archive_entry_is_metadata_encrypted(ae));\r
+               assertEqualInt(1, archive_read_has_encrypted_entries(a));\r
+               assertEqualInt(ARCHIVE_FATAL, archive_read_data(a, buff, sizeof(buff)));\r
+\r
+               /* Additional attempts to read headers are futile */\r
+               assertEqualInt(ARCHIVE_OK, archive_read_close(a));\r
+               assertEqualInt(ARCHIVE_OK, archive_read_free(a));\r
+               return;\r
+       }\r
+\r
+       /* From here on out, we can assume that !filenamesEncrypted */\r
+\r
+       /* Read the header for "b.txt" */\r
+       assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));\r
+       assertEqualInt((AE_IFREG | 0644), archive_entry_mode(ae));\r
+       assertEqualString("b.txt", archive_entry_pathname(ae));\r
+       assertEqualInt(expected_file_size, archive_entry_size(ae));\r
+       assertEqualInt(1, archive_entry_is_data_encrypted(ae));\r
+       assertEqualInt(0, archive_entry_is_metadata_encrypted(ae));\r
+       assertEqualInt(1, archive_read_has_encrypted_entries(a));\r
+       assertEqualIntA(a, ARCHIVE_FATAL, archive_read_data(a, buff, sizeof(buff)));\r
+\r
+       /* Read the header for "c.txt" */\r
+       assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));\r
+       assertEqualInt((AE_IFREG | 0644), archive_entry_mode(ae));\r
+       assertEqualString("c.txt", archive_entry_pathname(ae));\r
+       assertEqualInt(expected_file_size, archive_entry_size(ae));\r
+       assertEqualInt(solid, archive_entry_is_data_encrypted(ae));\r
+       assertEqualInt(0, archive_entry_is_metadata_encrypted(ae));\r
+       /* After setting to true above, this should forever be true */\r
+       assertEqualInt(1, archive_read_has_encrypted_entries(a));\r
+       assertEqualIntA(a, expected_read_data_result, archive_read_data(a, buff, sizeof(buff)));\r
+       if (!solid) {\r
+               assertEqualMem("This is from c.txt", buff, expected_file_size);\r
+       }\r
+\r
+       /* Read the header for "d.txt" */\r
+       assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));\r
+       assertEqualInt((AE_IFREG | 0644), archive_entry_mode(ae));\r
+       assertEqualString("d.txt", archive_entry_pathname(ae));\r
+       assertEqualInt(expected_file_size, archive_entry_size(ae));\r
+       assertEqualInt(1, archive_entry_is_data_encrypted(ae));\r
+       assertEqualInt(0, archive_entry_is_metadata_encrypted(ae));\r
+       assertEqualInt(1, archive_read_has_encrypted_entries(a));\r
+       assertEqualIntA(a, ARCHIVE_FATAL, archive_read_data(a, buff, sizeof(buff)));\r
+\r
+       /* End of archive. */\r
+       assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header(a, &ae));\r
+\r
+       /* Close the archive. */\r
+       assertEqualInt(ARCHIVE_OK, archive_read_close(a));\r
+       assertEqualInt(ARCHIVE_OK, archive_read_free(a));\r
+}\r
+\r
+DEFINE_TEST(test_read_format_rar4_encrypted)\r
+{\r
+       test_encrypted_rar_archive("test_read_format_rar4_encrypted.rar", 0, 0);\r
+}\r
+\r
+DEFINE_TEST(test_read_format_rar4_encrypted_filenames)\r
+{\r
+       test_encrypted_rar_archive("test_read_format_rar4_encrypted_filenames.rar", 1, 0);\r
+}\r
+\r
+DEFINE_TEST(test_read_format_rar4_solid_encrypted)\r
+{\r
+       /* TODO: If solid RAR4 support is ever added, the following should pass */\r
+#if 0\r
+       test_encrypted_rar_archive("test_read_format_rar4_solid_encrypted.rar", 0, 1);\r
+#else\r
+       skipping("RAR4 solid archive support not currently available");\r
+#endif\r
+}\r
+\r
+DEFINE_TEST(test_read_format_rar4_solid_encrypted_filenames)\r
+{\r
+       test_encrypted_rar_archive("test_read_format_rar4_solid_encrypted_filenames.rar", 1, 1);\r
+}\r
+\r
+DEFINE_TEST(test_read_format_rar5_encrypted)\r
+{\r
+       test_encrypted_rar_archive("test_read_format_rar5_encrypted.rar", 0, 0);\r
+}\r
+\r
+DEFINE_TEST(test_read_format_rar5_encrypted_filenames)\r
+{\r
+       test_encrypted_rar_archive("test_read_format_rar5_encrypted_filenames.rar", 1, 0);\r
+}\r
+\r
+DEFINE_TEST(test_read_format_rar5_solid_encrypted)\r
+{\r
+       test_encrypted_rar_archive("test_read_format_rar5_solid_encrypted.rar", 0, 1);\r
+}\r
+\r
+DEFINE_TEST(test_read_format_rar5_solid_encrypted_filenames)\r
+{\r
+       test_encrypted_rar_archive("test_read_format_rar5_solid_encrypted_filenames.rar", 1, 1);\r
+}\r
index 6619aa7f35fbcbb7202d24cf2234ac9704c15607..78bda6c27702262072d16ce60ebef301da9c62be 100644 (file)
@@ -71,7 +71,11 @@ DEFINE_TEST(test_write_format_zip_stream)
        unsigned long crc;
        unsigned long compressed_size = 0;
        int file_perm = 00644;
+#ifdef HAVE_ZLIB_H
        int zip_version = 20;
+#else
+       int zip_version = 10;
+#endif
        int zip_compression = 8;
        short file_uid = 10, file_gid = 20;
        unsigned char *buff, *buffend, *p;