Coverage Report

Created: 2026-10-10 07:18

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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
}