1299425Smm/*-
2299425Smm * Copyright (c) 2014 Michihiro NAKAJIMA
3299425Smm * All rights reserved.
4299425Smm *
5299425Smm * Redistribution and use in source and binary forms, with or without
6299425Smm * modification, are permitted provided that the following conditions
7299425Smm * are met:
8299425Smm * 1. Redistributions of source code must retain the above copyright
9299425Smm *    notice, this list of conditions and the following disclaimer.
10299425Smm * 2. Redistributions in binary form must reproduce the above copyright
11299425Smm *    notice, this list of conditions and the following disclaimer in the
12299425Smm *    documentation and/or other materials provided with the distribution.
13299425Smm *
14299425Smm * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
15299425Smm * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16299425Smm * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17299425Smm * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
18299425Smm * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19299425Smm * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20299425Smm * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21299425Smm * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22299425Smm * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23299425Smm * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24299425Smm */
25299425Smm
26299425Smm#include "archive_platform.h"
27299425Smm__FBSDID("$FreeBSD: stable/10/contrib/libarchive/libarchive/archive_read_add_passphrase.c 362134 2020-06-12 23:02:34Z mm $");
28299425Smm
29299425Smm#ifdef HAVE_ERRNO_H
30299425Smm#include <errno.h>
31299425Smm#endif
32299425Smm#include "archive_read_private.h"
33299425Smm
34299425Smmstatic void
35299425Smmadd_passphrase_to_tail(struct archive_read *a,
36299425Smm    struct archive_read_passphrase *p)
37299425Smm{
38299425Smm	*a->passphrases.last = p;
39299425Smm	a->passphrases.last = &p->next;
40299425Smm	p->next = NULL;
41299425Smm}
42299425Smm
43299425Smmstatic struct archive_read_passphrase *
44299425Smmremove_passphrases_from_head(struct archive_read *a)
45299425Smm{
46299425Smm	struct archive_read_passphrase *p;
47299425Smm
48299425Smm	p = a->passphrases.first;
49299425Smm	if (p != NULL)
50299425Smm		a->passphrases.first = p->next;
51299425Smm	return (p);
52299425Smm}
53299425Smm
54299425Smmstatic void
55299425Smminsert_passphrase_to_head(struct archive_read *a,
56299425Smm    struct archive_read_passphrase *p)
57299425Smm{
58299425Smm	p->next = a->passphrases.first;
59299425Smm	a->passphrases.first = p;
60362134Smm	if (&a->passphrases.first == a->passphrases.last) {
61362134Smm		a->passphrases.last = &p->next;
62362134Smm		p->next = NULL;
63362134Smm	}
64299425Smm}
65299425Smm
66299425Smmstatic struct archive_read_passphrase *
67299425Smmnew_read_passphrase(struct archive_read *a, const char *passphrase)
68299425Smm{
69299425Smm	struct archive_read_passphrase *p;
70299425Smm
71299425Smm	p = malloc(sizeof(*p));
72299425Smm	if (p == NULL) {
73299425Smm		archive_set_error(&a->archive, ENOMEM,
74299425Smm		    "Can't allocate memory");
75299425Smm		return (NULL);
76299425Smm	}
77299425Smm	p->passphrase = strdup(passphrase);
78299425Smm	if (p->passphrase == NULL) {
79299425Smm		free(p);
80299425Smm		archive_set_error(&a->archive, ENOMEM,
81299425Smm		    "Can't allocate memory");
82299425Smm		return (NULL);
83299425Smm	}
84299425Smm	return (p);
85299425Smm}
86299425Smm
87299425Smmint
88299425Smmarchive_read_add_passphrase(struct archive *_a, const char *passphrase)
89299425Smm{
90299425Smm	struct archive_read *a = (struct archive_read *)_a;
91299425Smm	struct archive_read_passphrase *p;
92299425Smm
93299425Smm	archive_check_magic(_a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_NEW,
94299425Smm		"archive_read_add_passphrase");
95299425Smm
96299425Smm	if (passphrase == NULL || passphrase[0] == '\0') {
97299425Smm		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
98299425Smm		    "Empty passphrase is unacceptable");
99299425Smm		return (ARCHIVE_FAILED);
100299425Smm	}
101299425Smm
102299425Smm	p = new_read_passphrase(a, passphrase);
103299425Smm	if (p == NULL)
104299425Smm		return (ARCHIVE_FATAL);
105299425Smm	add_passphrase_to_tail(a, p);
106299425Smm
107299425Smm	return (ARCHIVE_OK);
108299425Smm}
109299425Smm
110299425Smmint
111299425Smmarchive_read_set_passphrase_callback(struct archive *_a, void *client_data,
112299425Smm    archive_passphrase_callback *cb)
113299425Smm{
114299425Smm	struct archive_read *a = (struct archive_read *)_a;
115299425Smm
116299425Smm	archive_check_magic(_a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_NEW,
117299425Smm		"archive_read_set_passphrase_callback");
118299425Smm
119299425Smm	a->passphrases.callback = cb;
120299425Smm	a->passphrases.client_data = client_data;
121299425Smm	return (ARCHIVE_OK);
122299425Smm}
123299425Smm
124299425Smm/*
125299425Smm * Call this in advance when you start to get a passphrase for decryption
126299425Smm * for a entry.
127299425Smm */
128299425Smmvoid
129299425Smm__archive_read_reset_passphrase(struct archive_read *a)
130299425Smm{
131299425Smm
132305192Smm	a->passphrases.candidate = -1;
133299425Smm}
134299425Smm
135299425Smm/*
136299425Smm * Get a passphrase for decryption.
137299425Smm */
138299425Smmconst char *
139299425Smm__archive_read_next_passphrase(struct archive_read *a)
140299425Smm{
141299425Smm	struct archive_read_passphrase *p;
142299425Smm	const char *passphrase;
143299425Smm
144305192Smm	if (a->passphrases.candidate < 0) {
145299425Smm		/* Count out how many passphrases we have. */
146299425Smm		int cnt = 0;
147299425Smm
148299425Smm		for (p = a->passphrases.first; p != NULL; p = p->next)
149299425Smm			cnt++;
150305192Smm		a->passphrases.candidate = cnt;
151299425Smm		p = a->passphrases.first;
152305192Smm	} else if (a->passphrases.candidate > 1) {
153299425Smm		/* Rotate a passphrase list. */
154305192Smm		a->passphrases.candidate--;
155299425Smm		p = remove_passphrases_from_head(a);
156299425Smm		add_passphrase_to_tail(a, p);
157305192Smm		/* Pick a new passphrase candidate up. */
158299425Smm		p = a->passphrases.first;
159305192Smm	} else if (a->passphrases.candidate == 1) {
160305192Smm		/* This case is that all candidates failed to decrypt. */
161305192Smm		a->passphrases.candidate = 0;
162299425Smm		if (a->passphrases.first->next != NULL) {
163299425Smm			/* Rotate a passphrase list. */
164299425Smm			p = remove_passphrases_from_head(a);
165299425Smm			add_passphrase_to_tail(a, p);
166299425Smm		}
167299425Smm		p = NULL;
168305192Smm	} else  /* There is no passphrase candidate. */
169299425Smm		p = NULL;
170299425Smm
171299425Smm	if (p != NULL)
172299425Smm		passphrase = p->passphrase;
173299425Smm	else if (a->passphrases.callback != NULL) {
174299425Smm		/* Get a passphrase through a call-back function
175299425Smm		 * since we tried all passphrases out or we don't
176299425Smm		 * have it. */
177299425Smm		passphrase = a->passphrases.callback(&a->archive,
178299425Smm		    a->passphrases.client_data);
179299425Smm		if (passphrase != NULL) {
180299425Smm			p = new_read_passphrase(a, passphrase);
181299425Smm			if (p == NULL)
182299425Smm				return (NULL);
183299425Smm			insert_passphrase_to_head(a, p);
184305192Smm			a->passphrases.candidate = 1;
185299425Smm		}
186299425Smm	} else
187299425Smm		passphrase = NULL;
188299425Smm
189299425Smm	return (passphrase);
190299425Smm}
191