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