1 /*
2   zip_fopen_index_encrypted.c -- open file for reading by index w/ password
3   Copyright (C) 1999-2009 Dieter Baron and Thomas Klausner
4 
5   This file is part of libzip, a library to manipulate ZIP archives.
6   The authors can be contacted at <libzip@nih.at>
7 
8   Redistribution and use in source and binary forms, with or without
9   modification, are permitted provided that the following conditions
10   are met:
11   1. Redistributions of source code must retain the above copyright
12      notice, this list of conditions and the following disclaimer.
13   2. Redistributions in binary form must reproduce the above copyright
14      notice, this list of conditions and the following disclaimer in
15      the documentation and/or other materials provided with the
16      distribution.
17   3. The names of the authors may not be used to endorse or promote
18      products derived from this software without specific prior
19      written permission.
20 
21   THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS
22   OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
23   WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24   ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
25   DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26   DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
27   GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
29   IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
30   OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
31   IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 */
33 
34 
35 
36 #include <errno.h>
37 #include <stdio.h>
38 #include <stdlib.h>
39 
40 #include "zipint.h"
41 
42 static struct zip_file *_zip_file_new(struct zip *za);
43 
44 
45 
46 ZIP_EXTERN(struct zip_file *)
zip_fopen_index_encrypted(struct zip * za,zip_uint64_t fileno,int flags,const char * password)47 zip_fopen_index_encrypted(struct zip *za, zip_uint64_t fileno, int flags,
48 			  const char *password)
49 {
50     struct zip_file *zf;
51     zip_compression_implementation comp_impl;
52     zip_encryption_implementation enc_impl;
53     struct zip_source *src, *s2;
54     zip_uint64_t start;
55     struct zip_stat st;
56 
57     if (fileno >= za->nentry) {
58 	_zip_error_set(&za->error, ZIP_ER_INVAL, 0);
59 	return NULL;
60     }
61 
62     if ((flags & ZIP_FL_UNCHANGED) == 0
63 	&& ZIP_ENTRY_DATA_CHANGED(za->entry+fileno)) {
64 	_zip_error_set(&za->error, ZIP_ER_CHANGED, 0);
65 	return NULL;
66     }
67 
68     if (fileno >= za->cdir->nentry) {
69 	_zip_error_set(&za->error, ZIP_ER_INVAL, 0);
70 	return NULL;
71     }
72 
73     if (flags & ZIP_FL_ENCRYPTED)
74 	flags |= ZIP_FL_COMPRESSED;
75 
76     zip_stat_index(za, fileno, flags, &st);
77 
78     enc_impl = NULL;
79     if ((flags & ZIP_FL_ENCRYPTED) == 0) {
80 	if (st.encryption_method != ZIP_EM_NONE) {
81 	    if (password == NULL) {
82 		_zip_error_set(&za->error, ZIP_ER_NOPASSWD, 0);
83 		return NULL;
84 	    }
85 	    if ((enc_impl=zip_get_encryption_implementation(
86 		     st.encryption_method)) == NULL) {
87 		_zip_error_set(&za->error, ZIP_ER_ENCRNOTSUPP, 0);
88 		return NULL;
89 	    }
90 	}
91     }
92 
93     comp_impl = NULL;
94     if ((flags & ZIP_FL_COMPRESSED) == 0) {
95 	if (st.comp_method != ZIP_CM_STORE) {
96 	    if ((comp_impl=zip_get_compression_implementation(
97 		     st.comp_method)) == NULL) {
98 		_zip_error_set(&za->error, ZIP_ER_COMPNOTSUPP, 0);
99 		return NULL;
100 	    }
101 	}
102     }
103 
104     if ((start=_zip_file_get_offset(za, fileno)) == 0)
105 	return NULL;
106 
107     if (st.comp_size == 0) {
108 	if ((src=zip_source_buffer(za, NULL, 0, 0)) == NULL)
109 	    return NULL;
110     }
111     else {
112 	if ((src=_zip_source_file_or_p(za, NULL, za->zp, start, st.comp_size,
113 				       0, &st)) == NULL)
114 	    return NULL;
115 	if (enc_impl) {
116 	    if ((s2=enc_impl(za, src, ZIP_EM_TRAD_PKWARE, 0,
117 			     password)) == NULL) {
118 		zip_source_free(src);
119 		/* XXX: set error (how?) */
120 		return NULL;
121 	    }
122 	    src = s2;
123 	}
124 	if (comp_impl) {
125 	    if ((s2=comp_impl(za, src, za->cdir->entry[fileno].comp_method,
126 			      0)) == NULL) {
127 		zip_source_free(src);
128 		/* XXX: set error (how?) */
129 		return NULL;
130 	    }
131 	    src = s2;
132 	}
133 	if ((flags & ZIP_FL_COMPRESSED) == 0
134 	    || st.comp_method == ZIP_CM_STORE ) {
135 	    if ((s2=zip_source_crc(za, src, 1)) == NULL) {
136 		zip_source_free(src);
137 		/* XXX: set error (how?) */
138 		return NULL;
139 	    }
140 	    src = s2;
141 	}
142     }
143 
144     if (zip_source_open(src) < 0) {
145 	_zip_error_set_from_source(&za->error, src);
146 	zip_source_free(src);
147 	return NULL;
148     }
149 
150     zf = _zip_file_new(za);
151 
152     zf->src = src;
153 
154     return zf;
155 }
156 
157 
158 
159 static struct zip_file *
_zip_file_new(struct zip * za)160 _zip_file_new(struct zip *za)
161 {
162     struct zip_file *zf, **file;
163     int n;
164 
165     if ((zf=(struct zip_file *)malloc(sizeof(struct zip_file))) == NULL) {
166 	_zip_error_set(&za->error, ZIP_ER_MEMORY, 0);
167 	return NULL;
168     }
169 
170     if (za->nfile >= za->nfile_alloc-1) {
171 	n = za->nfile_alloc + 10;
172 	file = (struct zip_file **)realloc(za->file,
173 					   n*sizeof(struct zip_file *));
174 	if (file == NULL) {
175 	    _zip_error_set(&za->error, ZIP_ER_MEMORY, 0);
176 	    free(zf);
177 	    return NULL;
178 	}
179 	za->nfile_alloc = n;
180 	za->file = file;
181     }
182 
183     za->file[za->nfile++] = zf;
184 
185     zf->za = za;
186     _zip_error_init(&zf->error);
187     zf->eof = 0;
188     zf->src = NULL;
189 
190     return zf;
191 }
192