2 * Copyright (c) 2014 Michihiro NAKAJIMA
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17 * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
18 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 #include "archive_platform.h"
27 __FBSDID("$FreeBSD$");
32 #include "archive_read_private.h"
35 add_passphrase_to_tail(struct archive_read
*a
,
36 struct archive_read_passphrase
*p
)
38 *a
->passphrases
.last
= p
;
39 a
->passphrases
.last
= &p
->next
;
43 static struct archive_read_passphrase
*
44 remove_passphrases_from_head(struct archive_read
*a
)
46 struct archive_read_passphrase
*p
;
48 p
= a
->passphrases
.first
;
50 a
->passphrases
.first
= p
->next
;
55 insert_passphrase_to_head(struct archive_read
*a
,
56 struct archive_read_passphrase
*p
)
58 p
->next
= a
->passphrases
.first
;
59 a
->passphrases
.first
= p
;
60 if (&a
->passphrases
.first
== a
->passphrases
.last
) {
61 a
->passphrases
.last
= &p
->next
;
66 static struct archive_read_passphrase
*
67 new_read_passphrase(struct archive_read
*a
, const char *passphrase
)
69 struct archive_read_passphrase
*p
;
71 p
= malloc(sizeof(*p
));
73 archive_set_error(&a
->archive
, ENOMEM
,
74 "Can't allocate memory");
77 p
->passphrase
= strdup(passphrase
);
78 if (p
->passphrase
== NULL
) {
80 archive_set_error(&a
->archive
, ENOMEM
,
81 "Can't allocate memory");
88 archive_read_add_passphrase(struct archive
*_a
, const char *passphrase
)
90 struct archive_read
*a
= (struct archive_read
*)_a
;
91 struct archive_read_passphrase
*p
;
93 archive_check_magic(_a
, ARCHIVE_READ_MAGIC
, ARCHIVE_STATE_NEW
,
94 "archive_read_add_passphrase");
96 if (passphrase
== NULL
|| passphrase
[0] == '\0') {
97 archive_set_error(&a
->archive
, ARCHIVE_ERRNO_MISC
,
98 "Empty passphrase is unacceptable");
99 return (ARCHIVE_FAILED
);
102 p
= new_read_passphrase(a
, passphrase
);
104 return (ARCHIVE_FATAL
);
105 add_passphrase_to_tail(a
, p
);
111 archive_read_set_passphrase_callback(struct archive
*_a
, void *client_data
,
112 archive_passphrase_callback
*cb
)
114 struct archive_read
*a
= (struct archive_read
*)_a
;
116 archive_check_magic(_a
, ARCHIVE_READ_MAGIC
, ARCHIVE_STATE_NEW
,
117 "archive_read_set_passphrase_callback");
119 a
->passphrases
.callback
= cb
;
120 a
->passphrases
.client_data
= client_data
;
125 * Call this in advance when you start to get a passphrase for decryption
129 __archive_read_reset_passphrase(struct archive_read
*a
)
132 a
->passphrases
.candidate
= -1;
136 * Get a passphrase for decryption.
139 __archive_read_next_passphrase(struct archive_read
*a
)
141 struct archive_read_passphrase
*p
;
142 const char *passphrase
;
144 if (a
->passphrases
.candidate
< 0) {
145 /* Count out how many passphrases we have. */
148 for (p
= a
->passphrases
.first
; p
!= NULL
; p
= p
->next
)
150 a
->passphrases
.candidate
= cnt
;
151 p
= a
->passphrases
.first
;
152 } else if (a
->passphrases
.candidate
> 1) {
153 /* Rotate a passphrase list. */
154 a
->passphrases
.candidate
--;
155 p
= remove_passphrases_from_head(a
);
156 add_passphrase_to_tail(a
, p
);
157 /* Pick a new passphrase candidate up. */
158 p
= a
->passphrases
.first
;
159 } else if (a
->passphrases
.candidate
== 1) {
160 /* This case is that all candidates failed to decrypt. */
161 a
->passphrases
.candidate
= 0;
162 if (a
->passphrases
.first
->next
!= NULL
) {
163 /* Rotate a passphrase list. */
164 p
= remove_passphrases_from_head(a
);
165 add_passphrase_to_tail(a
, p
);
168 } else /* There is no passphrase candidate. */
172 passphrase
= p
->passphrase
;
173 else if (a
->passphrases
.callback
!= NULL
) {
174 /* Get a passphrase through a call-back function
175 * since we tried all passphrases out or we don't
177 passphrase
= a
->passphrases
.callback(&a
->archive
,
178 a
->passphrases
.client_data
);
179 if (passphrase
!= NULL
) {
180 p
= new_read_passphrase(a
, passphrase
);
183 insert_passphrase_to_head(a
, p
);
184 a
->passphrases
.candidate
= 1;