LibreOffice Module onlineupdate (master) 1
archivereader.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2/* vim:set ts=2 sw=2 sts=2 et cindent: */
3/* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7#include <string.h>
8#include <stdlib.h>
9#include <fcntl.h>
10#include "bzlib.h"
11#include "archivereader.h"
12#include "errors.h"
13#ifdef _WIN32
14#include "updatehelper.h"
15#endif
16
17// These are generated at compile time based on the DER file for the channel
18// being used
19#ifdef VERIFY_MAR_SIGNATURE
20#ifdef TEST_UPDATER
21#include "../xpcshellCert.h"
22#else
23#include "onlineupdate/primaryCert.h"
24#include "onlineupdate/secondaryCert.h"
25#endif
26#endif
27
28#if defined(_WIN32)
29#define UPDATER_NO_STRING_GLUE_STL
30#endif
31#include "nsVersionComparator.h"
32#undef UPDATER_NO_STRING_GLUE_STL
33
34#if defined(UNIX)
35# include <sys/types.h>
36#elif defined(_WIN32)
37# include <io.h>
38#endif
39
40static int inbuf_size = 262144;
41static int outbuf_size = 262144;
42static char *inbuf = nullptr;
43static char *outbuf = nullptr;
44
53template<uint32_t SIZE>
54int
55VerifyLoadedCert(MarFile *archive, const uint8_t (&certData)[SIZE])
56{
57 (void)archive;
58 (void)certData;
59
60#ifdef VERIFY_MAR_SIGNATURE
61 const uint32_t size = SIZE;
62 const uint8_t* const data = &certData[0];
63 if (mar_verify_signatures(archive, &data, &size, 1))
64 {
65 return CERT_VERIFY_ERROR;
66 }
67#endif
68
69 return OK;
70}
71
80int
82{
83 if (!mArchive)
84 {
85 return ARCHIVE_NOT_OPEN;
86 }
87
88#ifndef VERIFY_MAR_SIGNATURE
89 return OK;
90#else
91#ifdef TEST_UPDATER
92 int rv = VerifyLoadedCert(mArchive, xpcshellCertData);
93#else
94 int rv = VerifyLoadedCert(mArchive, primaryCertData);
95 if (rv != OK)
96 {
97 rv = VerifyLoadedCert(mArchive, secondaryCertData);
98 }
99#endif
100 return rv;
101#endif
102}
103
125int
127 const char *appVersion)
128{
129 if (!mArchive)
130 {
131 return ARCHIVE_NOT_OPEN;
132 }
133
134 ProductInformationBlock productInfoBlock;
136 &productInfoBlock);
137 if (rv != OK)
138 {
140 }
141
142 // Only check the MAR channel name if specified, it should be passed in from
143 // the update-settings.ini file.
144 if (MARChannelID && strlen(MARChannelID))
145 {
146 // Check for at least one match in the comma separated list of values.
147 const char *delimiter = " ,\t";
148 // Make a copy of the string in case a read only memory buffer
149 // was specified. strtok modifies the input buffer.
150 char channelCopy[512] = { 0 };
151 strncpy(channelCopy, MARChannelID, sizeof(channelCopy) - 1);
152 char *channel = strtok(channelCopy, delimiter);
154 while (channel)
155 {
156 if (!strcmp(channel, productInfoBlock.MARChannelID))
157 {
158 rv = OK;
159 break;
160 }
161 channel = strtok(nullptr, delimiter);
162 }
163 }
164
165 if (rv == OK)
166 {
167 /* Compare both versions to ensure we don't have a downgrade
168 -1 if appVersion is older than productInfoBlock.productVersion
169 1 if appVersion is newer than productInfoBlock.productVersion
170 0 if appVersion is the same as productInfoBlock.productVersion
171 This even works with strings like:
172 - 12.0a1 being older than 12.0a2
173 - 12.0a2 being older than 12.0b1
174 - 12.0a1 being older than 12.0
175 - 12.0 being older than 12.1a1 */
176 int versionCompareResult =
177 mozilla::CompareVersions(appVersion, productInfoBlock.productVersion);
178 if (1 == versionCompareResult)
179 {
181 }
182 }
183
184 free((void *)productInfoBlock.MARChannelID);
185 free((void *)productInfoBlock.productVersion);
186 return rv;
187}
188
189int
191{
192 if (mArchive)
193 Close();
194
195 if (!inbuf)
196 {
197 inbuf = (char *)malloc(inbuf_size);
198 if (!inbuf)
199 {
200 // Try again with a smaller buffer.
201 inbuf_size = 1024;
202 inbuf = (char *)malloc(inbuf_size);
203 if (!inbuf)
205 }
206 }
207
208 if (!outbuf)
209 {
210 outbuf = (char *)malloc(outbuf_size);
211 if (!outbuf)
212 {
213 // Try again with a smaller buffer.
214 outbuf_size = 1024;
215 outbuf = (char *)malloc(outbuf_size);
216 if (!outbuf)
218 }
219 }
220
221#ifdef _WIN32
222 mArchive = mar_wopen(path);
223#else
224 mArchive = mar_open(path);
225#endif
226 if (!mArchive)
227 return READ_ERROR;
228
229 return OK;
230}
231
232void
234{
235 if (mArchive)
236 {
238 mArchive = nullptr;
239 }
240
241 if (inbuf)
242 {
243 free(inbuf);
244 inbuf = nullptr;
245 }
246
247 if (outbuf)
248 {
249 free(outbuf);
250 outbuf = nullptr;
251 }
252}
253
254int
255ArchiveReader::ExtractFile(const char *name, const NS_tchar *dest)
256{
257 const MarItem *item = mar_find_item(mArchive, name);
258 if (!item)
259 return READ_ERROR;
260
261#ifdef _WIN32
262 FILE* fp = _wfopen(dest, L"wb+");
263#else
264 int fd = creat(dest, item->flags);
265 if (fd == -1)
266 return WRITE_ERROR;
267
268 FILE *fp = fdopen(fd, "wb");
269#endif
270 if (!fp)
271 return WRITE_ERROR;
272
273 int rv = ExtractItemToStream(item, fp);
274
275 fclose(fp);
276 return rv;
277}
278
279int
280ArchiveReader::ExtractFileToStream(const char *name, FILE *fp)
281{
282 const MarItem *item = mar_find_item(mArchive, name);
283 if (!item)
284 return READ_ERROR;
285
286 return ExtractItemToStream(item, fp);
287}
288
289int
291{
292 /* decompress the data chunk by chunk */
293
294 bz_stream strm;
295 int offset, inlen, ret = OK;
296
297 memset(&strm, 0, sizeof(strm));
298 if (BZ2_bzDecompressInit(&strm, 0, 0) != BZ_OK)
300
301 offset = 0;
302 for (;;)
303 {
304 if (!item->length)
305 {
307 break;
308 }
309
310 if (offset < (int) item->length && strm.avail_in == 0)
311 {
312 inlen = mar_read(mArchive, item, offset, inbuf, inbuf_size);
313 if (inlen <= 0)
314 return READ_ERROR;
315 offset += inlen;
316 strm.next_in = inbuf;
317 strm.avail_in = inlen;
318 }
319
320 strm.next_out = outbuf;
321 strm.avail_out = outbuf_size;
322
323 ret = BZ2_bzDecompress(&strm);
324 if (ret != BZ_OK && ret != BZ_STREAM_END)
325 {
327 break;
328 }
329
330 int outlen = outbuf_size - strm.avail_out;
331 if (outlen)
332 {
333 if (fwrite(outbuf, outlen, 1, fp) != 1)
334 {
336 break;
337 }
338 }
339
340 if (ret == BZ_STREAM_END)
341 {
342 ret = OK;
343 break;
344 }
345 }
346
347 BZ2_bzDecompressEnd(&strm);
348 return ret;
349}
static char * outbuf
int VerifyLoadedCert(MarFile *archive, const uint8_t(&certData)[SIZE])
Performs a verification on the opened MAR file with the passed in certificate name ID and type ID.
static int outbuf_size
static int inbuf_size
static char * inbuf
MarFile * mArchive
Definition: archivereader.h:36
int Open(const NS_tchar *path)
int ExtractFile(const char *item, const NS_tchar *destination)
int VerifySignature()
Performs a verification on the opened MAR file.
int ExtractItemToStream(const MarItem *item, FILE *fp)
int ExtractFileToStream(const char *item, FILE *fp)
int VerifyProductInformation(const char *MARChannelID, const char *appVersion)
Verifies that the MAR file matches the current product, channel, and version.
#define UNEXPECTED_MAR_ERROR
Definition: errors.h:62
#define CERT_VERIFY_ERROR
Definition: errors.h:39
#define ARCHIVE_NOT_OPEN
Definition: errors.h:40
#define ARCHIVE_READER_MEM_ERROR
Definition: errors.h:28
#define WRITE_ERROR_EXTRACT
Definition: errors.h:84
#define UNEXPECTED_BZIP_ERROR
Definition: errors.h:61
#define WRITE_ERROR
Definition: errors.h:24
#define OK
Definition: errors.h:10
#define READ_ERROR
Definition: errors.h:23
#define MAR_CHANNEL_MISMATCH_ERROR
Definition: errors.h:42
#define VERSION_DOWNGRADE_ERROR
Definition: errors.h:43
#define COULD_NOT_READ_PRODUCT_INFO_BLOCK_ERROR
Definition: errors.h:41
const char * name
int mar_read(MarFile *mar, const MarItem *item, int offset, char *buf, int bufsize)
Read from MAR item at given offset up to bufsize bytes.
Definition: mar_read.c:514
void mar_close(MarFile *mar)
Close a MAR file that was opened using mar_open.
Definition: mar_read.c:195
MarFile * mar_open(const char *path)
Open a MAR file for reading.
Definition: mar_read.c:167
const MarItem * mar_find_item(MarFile *mar, const char *name)
Find an item in the MAR file by name.
Definition: mar_read.c:484
int mar_read_product_info_block(MarFile *mar, struct ProductInformationBlock *infoBlock)
Reads the product info block from the MAR file's additional block section.
Definition: mar_read.c:394
int mar_verify_signatures(MarFile *mar, const uint8_t *const *certData, const uint32_t *certDataSizes, uint32_t certCount)
Verifies a MAR file by verifying each signature with the corresponding certificate.
Definition: mar_verify.c:136
size
int32_t CompareVersions(const char *aStrA, const char *aStrB)
constexpr tools::Long SIZE
Definition: mar.h:48
The MAR item data structure.
Definition: mar.h:38
uint32_t flags
Definition: mar.h:42
uint32_t length
Definition: mar.h:41
const char * productVersion
Definition: mar.h:32
const char * MARChannelID
Definition: mar.h:31
char NS_tchar
Definition: types.hxx:20