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
;
62 static struct archive_read_passphrase
*
63 new_read_passphrase(struct archive_read
*a
, const char *passphrase
)
65 struct archive_read_passphrase
*p
;
67 p
= malloc(sizeof(*p
));
69 archive_set_error(&a
->archive
, ENOMEM
,
70 "Can't allocate memory");
73 p
->passphrase
= strdup(passphrase
);
74 if (p
->passphrase
== NULL
) {
76 archive_set_error(&a
->archive
, ENOMEM
,
77 "Can't allocate memory");
84 archive_read_add_passphrase(struct archive
*_a
, const char *passphrase
)
86 struct archive_read
*a
= (struct archive_read
*)_a
;
87 struct archive_read_passphrase
*p
;
89 archive_check_magic(_a
, ARCHIVE_READ_MAGIC
, ARCHIVE_STATE_NEW
,
90 "archive_read_add_passphrase");
92 if (passphrase
== NULL
|| passphrase
[0] == '\0') {
93 archive_set_error(&a
->archive
, ARCHIVE_ERRNO_MISC
,
94 "Empty passphrase is unacceptable");
95 return (ARCHIVE_FAILED
);
98 p
= new_read_passphrase(a
, passphrase
);
100 return (ARCHIVE_FATAL
);
101 add_passphrase_to_tail(a
, p
);
107 archive_read_set_passphrase_callback(struct archive
*_a
, void *client_data
,
108 archive_passphrase_callback
*cb
)
110 struct archive_read
*a
= (struct archive_read
*)_a
;
112 archive_check_magic(_a
, ARCHIVE_READ_MAGIC
, ARCHIVE_STATE_NEW
,
113 "archive_read_set_passphrase_callback");
115 a
->passphrases
.callback
= cb
;
116 a
->passphrases
.client_data
= client_data
;
121 * Call this in advance when you start to get a passphrase for decryption
125 __archive_read_reset_passphrase(struct archive_read
*a
)
128 a
->passphrases
.candiate
= -1;
132 * Get a passphrase for decryption.
135 __archive_read_next_passphrase(struct archive_read
*a
)
137 struct archive_read_passphrase
*p
;
138 const char *passphrase
;
140 if (a
->passphrases
.candiate
< 0) {
141 /* Count out how many passphrases we have. */
144 for (p
= a
->passphrases
.first
; p
!= NULL
; p
= p
->next
)
146 a
->passphrases
.candiate
= cnt
;
147 p
= a
->passphrases
.first
;
148 } else if (a
->passphrases
.candiate
> 1) {
149 /* Rotate a passphrase list. */
150 a
->passphrases
.candiate
--;
151 p
= remove_passphrases_from_head(a
);
152 add_passphrase_to_tail(a
, p
);
153 /* Pick a new passphrase candiate up. */
154 p
= a
->passphrases
.first
;
155 } else if (a
->passphrases
.candiate
== 1) {
156 /* This case is that all cadiates failed to decryption. */
157 a
->passphrases
.candiate
= 0;
158 if (a
->passphrases
.first
->next
!= NULL
) {
159 /* Rotate a passphrase list. */
160 p
= remove_passphrases_from_head(a
);
161 add_passphrase_to_tail(a
, p
);
164 } else /* There is no passphrase candaite. */
168 passphrase
= p
->passphrase
;
169 else if (a
->passphrases
.callback
!= NULL
) {
170 /* Get a passphrase through a call-back function
171 * since we tried all passphrases out or we don't
173 passphrase
= a
->passphrases
.callback(&a
->archive
,
174 a
->passphrases
.client_data
);
175 if (passphrase
!= NULL
) {
176 p
= new_read_passphrase(a
, passphrase
);
179 insert_passphrase_to_head(a
, p
);
180 a
->passphrases
.candiate
= 1;