1 /*-
2  * Copyright (c) 2009 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 #ifdef HAVE_STDLIB_H
32 #include <stdlib.h>
33 #endif
34 
35 #include "archive.h"
36 #include "archive_endian.h"
37 #include "archive_private.h"
38 #include "archive_read_private.h"
39 
40 struct rpm {
41           int64_t              total_in;
42           uint64_t   hpos;
43           uint64_t   hlen;
44           unsigned char        header[16];
45           enum {
46                     ST_LEAD,  /* Skipping 'Lead' section. */
47                     ST_HEADER,          /* Reading 'Header' section;
48                                          * first 16 bytes. */
49                     ST_HEADER_DATA,     /* Skipping 'Header' section. */
50                     ST_PADDING,         /* Skipping padding data after the
51                                          * 'Header' section. */
52                     ST_ARCHIVE          /* Reading 'Archive' section. */
53           }                    state;
54           int                  first_header;
55 };
56 #define RPM_LEAD_SIZE                   96        /* Size of 'Lead' section. */
57 #define RPM_MIN_HEAD_SIZE     16        /* Minimum size of 'Head'. */
58 
59 static int          rpm_bidder_bid(struct archive_read_filter_bidder *,
60                         struct archive_read_filter *);
61 static int          rpm_bidder_init(struct archive_read_filter *);
62 
63 static ssize_t      rpm_filter_read(struct archive_read_filter *,
64                         const void **);
65 static int          rpm_filter_close(struct archive_read_filter *);
66 
67 static inline size_t rpm_limit_bytes(uint64_t, size_t);
68 
69 #if ARCHIVE_VERSION_NUMBER < 4000000
70 /* Deprecated; remove in libarchive 4.0 */
71 int
archive_read_support_compression_rpm(struct archive * a)72 archive_read_support_compression_rpm(struct archive *a)
73 {
74           return archive_read_support_filter_rpm(a);
75 }
76 #endif
77 
78 static const struct archive_read_filter_bidder_vtable
79 rpm_bidder_vtable = {
80           .bid = rpm_bidder_bid,
81           .init = rpm_bidder_init,
82 };
83 
84 int
archive_read_support_filter_rpm(struct archive * _a)85 archive_read_support_filter_rpm(struct archive *_a)
86 {
87           struct archive_read *a = (struct archive_read *)_a;
88 
89           return __archive_read_register_bidder(a, NULL, "rpm",
90                               &rpm_bidder_vtable);
91 }
92 
93 static int
rpm_bidder_bid(struct archive_read_filter_bidder * self,struct archive_read_filter * filter)94 rpm_bidder_bid(struct archive_read_filter_bidder *self,
95     struct archive_read_filter *filter)
96 {
97           const unsigned char *b;
98           ssize_t avail;
99           int bits_checked;
100 
101           (void)self; /* UNUSED */
102 
103           b = __archive_read_filter_ahead(filter, 8, &avail);
104           if (b == NULL)
105                     return (0);
106 
107           bits_checked = 0;
108           /*
109            * Verify Header Magic Bytes : 0XED 0XAB 0XEE 0XDB
110            */
111           if (memcmp(b, "\xED\xAB\xEE\xDB", 4) != 0)
112                     return (0);
113           bits_checked += 32;
114           /*
115            * Check major version.
116            */
117           if (b[4] != 3 && b[4] != 4)
118                     return (0);
119           bits_checked += 8;
120           /*
121            * Check package type; binary or source.
122            */
123           if (b[6] != 0)
124                     return (0);
125           bits_checked += 8;
126           if (b[7] != 0 && b[7] != 1)
127                     return (0);
128           bits_checked += 8;
129 
130           return (bits_checked);
131 }
132 
133 static const struct archive_read_filter_vtable
134 rpm_reader_vtable = {
135           .read = rpm_filter_read,
136           .close = rpm_filter_close,
137 };
138 
139 static int
rpm_bidder_init(struct archive_read_filter * self)140 rpm_bidder_init(struct archive_read_filter *self)
141 {
142           struct rpm   *rpm;
143 
144           self->code = ARCHIVE_FILTER_RPM;
145           self->name = "rpm";
146 
147           rpm = calloc(1, sizeof(*rpm));
148           if (rpm == NULL) {
149                     archive_set_error(&self->archive->archive, ENOMEM,
150                         "Can't allocate data for rpm");
151                     return (ARCHIVE_FATAL);
152           }
153 
154           self->data = rpm;
155           rpm->state = ST_LEAD;
156           self->vtable = &rpm_reader_vtable;
157 
158           return (ARCHIVE_OK);
159 }
160 
161 static inline size_t
rpm_limit_bytes(uint64_t bytes,size_t max)162 rpm_limit_bytes(uint64_t bytes, size_t max)
163 {
164           return (bytes > max ? max : (size_t)bytes);
165 }
166 
167 static ssize_t
rpm_filter_read(struct archive_read_filter * self,const void ** buff)168 rpm_filter_read(struct archive_read_filter *self, const void **buff)
169 {
170           struct rpm *rpm;
171           const unsigned char *b;
172           ssize_t avail_in, total, used;
173           size_t n;
174           uint64_t section;
175           uint64_t bytes;
176 
177           rpm = (struct rpm *)self->data;
178           *buff = NULL;
179           total = avail_in = 0;
180           b = NULL;
181           used = 0;
182           do {
183                     if (b == NULL) {
184                               b = __archive_read_filter_ahead(self->upstream, 1,
185                                   &avail_in);
186                               if (b == NULL) {
187                                         if (avail_in < 0)
188                                                   return (ARCHIVE_FATAL);
189                                         else
190                                                   break;
191                               }
192                     }
193 
194                     switch (rpm->state) {
195                     case ST_LEAD:
196                               if (rpm->total_in + avail_in < RPM_LEAD_SIZE)
197                                         used += avail_in;
198                               else {
199                                         n = (size_t)(RPM_LEAD_SIZE - rpm->total_in);
200                                         used += n;
201                                         b += n;
202                                         rpm->state = ST_HEADER;
203                                         rpm->hpos = 0;
204                                         rpm->hlen = 0;
205                                         rpm->first_header = 1;
206                               }
207                               break;
208                     case ST_HEADER:
209                               n = rpm_limit_bytes(RPM_MIN_HEAD_SIZE - rpm->hpos,
210                                   avail_in - used);
211                               memcpy(rpm->header+rpm->hpos, b, n);
212                               b += n;
213                               used += n;
214                               rpm->hpos += n;
215 
216                               if (rpm->hpos == RPM_MIN_HEAD_SIZE) {
217                                         if (rpm->header[0] != 0x8e ||
218                                             rpm->header[1] != 0xad ||
219                                             rpm->header[2] != 0xe8 ||
220                                             rpm->header[3] != 0x01) {
221                                                   if (rpm->first_header) {
222                                                             archive_set_error(
223                                                                 &self->archive->archive,
224                                                                 ARCHIVE_ERRNO_FILE_FORMAT,
225                                                                 "Unrecognized rpm header");
226                                                             return (ARCHIVE_FATAL);
227                                                   }
228                                                   rpm->state = ST_ARCHIVE;
229                                                   *buff = rpm->header;
230                                                   total = RPM_MIN_HEAD_SIZE;
231                                                   break;
232                                         }
233                                         /* Calculate 'Header' length. */
234                                         section = archive_be32dec(rpm->header+8);
235                                         bytes = archive_be32dec(rpm->header+12);
236                                         rpm->hlen = rpm->hpos + section * 16 + bytes;
237                                         rpm->state = ST_HEADER_DATA;
238                                         rpm->first_header = 0;
239                               }
240                               break;
241                     case ST_HEADER_DATA:
242                               n = rpm_limit_bytes(rpm->hlen - rpm->hpos,
243                                   avail_in - used);
244                               b += n;
245                               used += n;
246                               rpm->hpos += n;
247                               if (rpm->hpos == rpm->hlen)
248                                         rpm->state = ST_PADDING;
249                               break;
250                     case ST_PADDING:
251                               while (used < avail_in) {
252                                         if (*b != 0) {
253                                                   /* Read next header. */
254                                                   rpm->state = ST_HEADER;
255                                                   rpm->hpos = 0;
256                                                   rpm->hlen = 0;
257                                                   break;
258                                         }
259                                         b++;
260                                         used++;
261                               }
262                               break;
263                     case ST_ARCHIVE:
264                               *buff = b;
265                               total = avail_in;
266                               used = avail_in;
267                               break;
268                     }
269                     if (used == avail_in) {
270                               rpm->total_in += used;
271                               __archive_read_filter_consume(self->upstream, used);
272                               b = NULL;
273                               used = 0;
274                     }
275           } while (total == 0 && avail_in > 0);
276 
277           if (used > 0 && b != NULL) {
278                     rpm->total_in += used;
279                     __archive_read_filter_consume(self->upstream, used);
280           }
281           return (total);
282 }
283 
284 static int
rpm_filter_close(struct archive_read_filter * self)285 rpm_filter_close(struct archive_read_filter *self)
286 {
287           struct rpm *rpm;
288 
289           rpm = (struct rpm *)self->data;
290           free(rpm);
291 
292           return (ARCHIVE_OK);
293 }
294 
295