/src/libarchive/libarchive/archive_read_add_passphrase.c
Line | Count | Source |
1 | | /*- |
2 | | * Copyright (c) 2014 Michihiro NAKAJIMA |
3 | | * All rights reserved. |
4 | | * |
5 | | * Redistribution and use in source and binary forms, with or without |
6 | | * modification, are permitted provided that the following conditions |
7 | | * are met: |
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. |
13 | | * |
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. |
24 | | */ |
25 | | |
26 | | #include "archive_platform.h" |
27 | | |
28 | | #ifdef HAVE_ERRNO_H |
29 | | #include <errno.h> |
30 | | #endif |
31 | | #include "archive_read_private.h" |
32 | | |
33 | | static void |
34 | | add_passphrase_to_tail(struct archive_read *a, |
35 | | struct archive_read_passphrase *p) |
36 | 16.8k | { |
37 | 16.8k | *a->passphrases.last = p; |
38 | 16.8k | a->passphrases.last = &p->next; |
39 | 16.8k | p->next = NULL; |
40 | 16.8k | } |
41 | | |
42 | | static struct archive_read_passphrase * |
43 | | remove_passphrases_from_head(struct archive_read *a) |
44 | 0 | { |
45 | 0 | struct archive_read_passphrase *p; |
46 | |
|
47 | 0 | p = a->passphrases.first; |
48 | 0 | if (p != NULL) |
49 | 0 | a->passphrases.first = p->next; |
50 | 0 | return (p); |
51 | 0 | } |
52 | | |
53 | | static void |
54 | | insert_passphrase_to_head(struct archive_read *a, |
55 | | struct archive_read_passphrase *p) |
56 | 0 | { |
57 | 0 | p->next = a->passphrases.first; |
58 | 0 | a->passphrases.first = p; |
59 | 0 | if (&a->passphrases.first == a->passphrases.last) { |
60 | 0 | a->passphrases.last = &p->next; |
61 | 0 | p->next = NULL; |
62 | 0 | } |
63 | 0 | } |
64 | | |
65 | | static struct archive_read_passphrase * |
66 | | new_read_passphrase(struct archive_read *a, const char *passphrase) |
67 | 16.8k | { |
68 | 16.8k | struct archive_read_passphrase *p; |
69 | | |
70 | 16.8k | p = malloc(sizeof(*p)); |
71 | 16.8k | if (p == NULL) { |
72 | 0 | archive_set_error(&a->archive, ENOMEM, |
73 | 0 | "Can't allocate memory"); |
74 | 0 | return (NULL); |
75 | 0 | } |
76 | 16.8k | p->passphrase = strdup(passphrase); |
77 | 16.8k | if (p->passphrase == NULL) { |
78 | 0 | free(p); |
79 | 0 | archive_set_error(&a->archive, ENOMEM, |
80 | 0 | "Can't allocate memory"); |
81 | 0 | return (NULL); |
82 | 0 | } |
83 | 16.8k | return (p); |
84 | 16.8k | } |
85 | | |
86 | | int |
87 | | archive_read_add_passphrase(struct archive *_a, const char *passphrase) |
88 | 16.8k | { |
89 | 16.8k | struct archive_read *a = (struct archive_read *)_a; |
90 | 16.8k | struct archive_read_passphrase *p; |
91 | | |
92 | 16.8k | archive_check_magic(_a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_NEW, |
93 | 16.8k | "archive_read_add_passphrase"); |
94 | | |
95 | 16.8k | if (passphrase == NULL || passphrase[0] == '\0') { |
96 | 0 | archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, |
97 | 0 | "Empty passphrase is unacceptable"); |
98 | 0 | return (ARCHIVE_FAILED); |
99 | 0 | } |
100 | | |
101 | 16.8k | p = new_read_passphrase(a, passphrase); |
102 | 16.8k | if (p == NULL) |
103 | 0 | return (ARCHIVE_FATAL); |
104 | 16.8k | add_passphrase_to_tail(a, p); |
105 | | |
106 | 16.8k | return (ARCHIVE_OK); |
107 | 16.8k | } |
108 | | |
109 | | int |
110 | | archive_read_set_passphrase_callback(struct archive *_a, void *client_data, |
111 | | archive_passphrase_callback *cb) |
112 | 0 | { |
113 | 0 | struct archive_read *a = (struct archive_read *)_a; |
114 | |
|
115 | 0 | archive_check_magic(_a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_NEW, |
116 | 0 | "archive_read_set_passphrase_callback"); |
117 | | |
118 | 0 | a->passphrases.callback = cb; |
119 | 0 | a->passphrases.client_data = client_data; |
120 | 0 | return (ARCHIVE_OK); |
121 | 0 | } |
122 | | |
123 | | /* |
124 | | * Call this in advance when you start to get a passphrase for decryption |
125 | | * for a entry. |
126 | | */ |
127 | | void |
128 | | __archive_read_reset_passphrase(struct archive_read *a) |
129 | 48.1k | { |
130 | | |
131 | 48.1k | a->passphrases.candidate = -1; |
132 | 48.1k | } |
133 | | |
134 | | /* |
135 | | * Get a passphrase for decryption. |
136 | | */ |
137 | | const char * |
138 | | __archive_read_next_passphrase(struct archive_read *a) |
139 | 13.3k | { |
140 | 13.3k | struct archive_read_passphrase *p; |
141 | 13.3k | const char *passphrase; |
142 | | |
143 | 13.3k | if (a->passphrases.candidate < 0) { |
144 | | /* Count out how many passphrases we have. */ |
145 | 8.82k | int cnt = 0; |
146 | | |
147 | 17.6k | for (p = a->passphrases.first; p != NULL; p = p->next) |
148 | 8.82k | cnt++; |
149 | 8.82k | a->passphrases.candidate = cnt; |
150 | 8.82k | p = a->passphrases.first; |
151 | 8.82k | } else if (a->passphrases.candidate > 1) { |
152 | | /* Rotate a passphrase list. */ |
153 | 0 | a->passphrases.candidate--; |
154 | 0 | p = remove_passphrases_from_head(a); |
155 | 0 | add_passphrase_to_tail(a, p); |
156 | | /* Pick a new passphrase candidate up. */ |
157 | 0 | p = a->passphrases.first; |
158 | 4.51k | } else if (a->passphrases.candidate == 1) { |
159 | | /* This case is that all candidates failed to decrypt. */ |
160 | 2.56k | a->passphrases.candidate = 0; |
161 | 2.56k | if (a->passphrases.first->next != NULL) { |
162 | | /* Rotate a passphrase list. */ |
163 | 0 | p = remove_passphrases_from_head(a); |
164 | 0 | add_passphrase_to_tail(a, p); |
165 | 0 | } |
166 | 2.56k | p = NULL; |
167 | 2.56k | } else /* There is no passphrase candidate. */ |
168 | 1.95k | p = NULL; |
169 | | |
170 | 13.3k | if (p != NULL) |
171 | 8.82k | passphrase = p->passphrase; |
172 | 4.51k | else if (a->passphrases.callback != NULL) { |
173 | | /* Get a passphrase through a call-back function |
174 | | * since we tried all passphrases out or we don't |
175 | | * have it. */ |
176 | 0 | passphrase = a->passphrases.callback(&a->archive, |
177 | 0 | a->passphrases.client_data); |
178 | 0 | if (passphrase != NULL) { |
179 | 0 | p = new_read_passphrase(a, passphrase); |
180 | 0 | if (p == NULL) |
181 | 0 | return (NULL); |
182 | 0 | insert_passphrase_to_head(a, p); |
183 | 0 | a->passphrases.candidate = 1; |
184 | 0 | } |
185 | 0 | } else |
186 | 4.51k | passphrase = NULL; |
187 | | |
188 | 13.3k | return (passphrase); |
189 | 13.3k | } |