nss: upgrade to release 3.73
[LibreOffice.git] / onlineupdate / source / update / updater / archivereader.cxx
blobd669211437e90f7ddcd558e96bfa09138ea4b465
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/. */
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
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
28 #if defined(_WIN32)
29 #define UPDATER_NO_STRING_GLUE_STL
30 #endif
31 #include "nsVersionComparator.h"
32 #undef UPDATER_NO_STRING_GLUE_STL
34 #if defined(UNIX)
35 # include <sys/types.h>
36 #elif defined(_WIN32)
37 # include <io.h>
38 #endif
40 static int inbuf_size = 262144;
41 static int outbuf_size = 262144;
42 static char *inbuf = nullptr;
43 static char *outbuf = nullptr;
45 /**
46 * Performs a verification on the opened MAR file with the passed in
47 * certificate name ID and type ID.
49 * @param archive The MAR file to verify the signature on.
50 * @param certData The certificate data.
51 * @return OK on success, CERT_VERIFY_ERROR on failure.
53 template<uint32_t SIZE>
54 int
55 VerifyLoadedCert(MarFile *archive, const uint8_t (&certData)[SIZE])
57 (void)archive;
58 (void)certData;
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))
65 return CERT_VERIFY_ERROR;
67 #endif
69 return OK;
72 /**
73 * Performs a verification on the opened MAR file. Both the primary and backup
74 * keys stored are stored in the current process and at least the primary key
75 * will be tried. Success will be returned as long as one of the two
76 * signatures verify.
78 * @return OK on success
80 int
81 ArchiveReader::VerifySignature()
83 if (!mArchive)
85 return ARCHIVE_NOT_OPEN;
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)
97 rv = VerifyLoadedCert(mArchive, secondaryCertData);
99 #endif
100 return rv;
101 #endif
105 * Verifies that the MAR file matches the current product, channel, and version
107 * @param MARChannelID The MAR channel name to use, only updates from MARs
108 * with a matching MAR channel name will succeed.
109 * If an empty string is passed, no check will be done
110 * for the channel name in the product information block.
111 * If a comma separated list of values is passed then
112 * one value must match.
113 * @param appVersion The application version to use, only MARs with an
114 * application version >= to appVersion will be applied.
115 * @return OK on success
116 * COULD_NOT_READ_PRODUCT_INFO_BLOCK if the product info block
117 * could not be read.
118 * MARCHANNEL_MISMATCH_ERROR if update-settings.ini's MAR
119 * channel ID doesn't match the MAR
120 * file's MAR channel ID.
121 * VERSION_DOWNGRADE_ERROR if the application version for
122 * this updater is newer than the
123 * one in the MAR.
126 ArchiveReader::VerifyProductInformation(const char *MARChannelID,
127 const char *appVersion)
129 if (!mArchive)
131 return ARCHIVE_NOT_OPEN;
134 ProductInformationBlock productInfoBlock;
135 int rv = mar_read_product_info_block(mArchive,
136 &productInfoBlock);
137 if (rv != OK)
139 return COULD_NOT_READ_PRODUCT_INFO_BLOCK_ERROR;
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))
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);
153 rv = MAR_CHANNEL_MISMATCH_ERROR;
154 while (channel)
156 if (!strcmp(channel, productInfoBlock.MARChannelID))
158 rv = OK;
159 break;
161 channel = strtok(nullptr, delimiter);
165 if (rv == OK)
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)
180 rv = VERSION_DOWNGRADE_ERROR;
184 free((void *)productInfoBlock.MARChannelID);
185 free((void *)productInfoBlock.productVersion);
186 return rv;
190 ArchiveReader::Open(const NS_tchar *path)
192 if (mArchive)
193 Close();
195 if (!inbuf)
197 inbuf = (char *)malloc(inbuf_size);
198 if (!inbuf)
200 // Try again with a smaller buffer.
201 inbuf_size = 1024;
202 inbuf = (char *)malloc(inbuf_size);
203 if (!inbuf)
204 return ARCHIVE_READER_MEM_ERROR;
208 if (!outbuf)
210 outbuf = (char *)malloc(outbuf_size);
211 if (!outbuf)
213 // Try again with a smaller buffer.
214 outbuf_size = 1024;
215 outbuf = (char *)malloc(outbuf_size);
216 if (!outbuf)
217 return ARCHIVE_READER_MEM_ERROR;
221 #ifdef _WIN32
222 mArchive = mar_wopen(path);
223 #else
224 mArchive = mar_open(path);
225 #endif
226 if (!mArchive)
227 return READ_ERROR;
229 return OK;
232 void
233 ArchiveReader::Close()
235 if (mArchive)
237 mar_close(mArchive);
238 mArchive = nullptr;
241 if (inbuf)
243 free(inbuf);
244 inbuf = nullptr;
247 if (outbuf)
249 free(outbuf);
250 outbuf = nullptr;
255 ArchiveReader::ExtractFile(const char *name, const NS_tchar *dest)
257 const MarItem *item = mar_find_item(mArchive, name);
258 if (!item)
259 return READ_ERROR;
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;
268 FILE *fp = fdopen(fd, "wb");
269 #endif
270 if (!fp)
271 return WRITE_ERROR;
273 int rv = ExtractItemToStream(item, fp);
275 fclose(fp);
276 return rv;
280 ArchiveReader::ExtractFileToStream(const char *name, FILE *fp)
282 const MarItem *item = mar_find_item(mArchive, name);
283 if (!item)
284 return READ_ERROR;
286 return ExtractItemToStream(item, fp);
290 ArchiveReader::ExtractItemToStream(const MarItem *item, FILE *fp)
292 /* decompress the data chunk by chunk */
294 bz_stream strm;
295 int offset, inlen, ret = OK;
297 memset(&strm, 0, sizeof(strm));
298 if (BZ2_bzDecompressInit(&strm, 0, 0) != BZ_OK)
299 return UNEXPECTED_BZIP_ERROR;
301 offset = 0;
302 for (;;)
304 if (!item->length)
306 ret = UNEXPECTED_MAR_ERROR;
307 break;
310 if (offset < (int) item->length && strm.avail_in == 0)
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;
320 strm.next_out = outbuf;
321 strm.avail_out = outbuf_size;
323 ret = BZ2_bzDecompress(&strm);
324 if (ret != BZ_OK && ret != BZ_STREAM_END)
326 ret = UNEXPECTED_BZIP_ERROR;
327 break;
330 int outlen = outbuf_size - strm.avail_out;
331 if (outlen)
333 if (fwrite(outbuf, outlen, 1, fp) != 1)
335 ret = WRITE_ERROR_EXTRACT;
336 break;
340 if (ret == BZ_STREAM_END)
342 ret = OK;
343 break;
347 BZ2_bzDecompressEnd(&strm);
348 return ret;