calc: on editing invalidation of view with different zoom is wrong
[LibreOffice.git] / onlineupdate / source / libmar / tool / mar.c
blob3db3bb86e4312aff3b54f29722e721d67f741b5d
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 <stdio.h>
8 #include <stdlib.h>
9 #include <string.h>
10 #include <onlineupdate/mar.h>
11 #include <onlineupdate/mar_cmdline.h>
13 #ifdef _WIN32
14 #include <windows.h>
15 #include <direct.h>
16 #define chdir _chdir
17 #else
18 #include <unistd.h>
19 #include <errno.h>
20 #endif
22 #ifndef APP_VERSION
23 #error "Missing APP_VERSION"
24 #endif
26 #define MAR_CHANNEL_ID "LOOnlineUpdater" /* Dummy value; replace or
27 remove in the future */
29 #if !defined(NO_SIGN_VERIFY) && (!defined(_WIN32) || defined(MAR_NSS))
30 #include "cert.h"
31 #include "pk11pub.h"
32 int NSSInitCryptoContext(const char *NSSConfigDir);
33 #endif
35 int mar_repackage_and_sign(const char *NSSConfigDir,
36 const char * const *certNames,
37 uint32_t certCount,
38 const char *src,
39 const char * dest);
41 static void print_version(void) {
42 printf("Version: %s\n", APP_VERSION);
43 printf("Default Channel ID: %s\n", MAR_CHANNEL_ID);
46 static void print_usage(void) {
47 printf("usage:\n");
48 printf("Create a MAR file:\n");
49 printf(" mar [-H MARChannelID] [-V ProductVersion] [-C workingDir] "
50 "-c archive.mar [files...]\n");
51 printf(" mar [-H MARChannelID] [-V ProductVersion] [-C workingDir] "
52 "-c archive.mar -f input_file.txt\n");
54 printf("Extract a MAR file:\n");
55 printf(" mar [-C workingDir] -x archive.mar\n");
56 #ifndef NO_SIGN_VERIFY
57 printf("Sign a MAR file:\n");
58 printf(" mar [-C workingDir] -d NSSConfigDir -n certname -s "
59 "archive.mar out_signed_archive.mar\n");
61 printf("Strip a MAR signature:\n");
62 printf(" mar [-C workingDir] -r "
63 "signed_input_archive.mar output_archive.mar\n");
65 printf("Extract a MAR signature:\n");
66 printf(" mar [-C workingDir] -n(i) -X "
67 "signed_input_archive.mar base_64_encoded_signature_file\n");
69 printf("Import a MAR signature:\n");
70 printf(" mar [-C workingDir] -n(i) -I "
71 "signed_input_archive.mar base_64_encoded_signature_file "
72 "changed_signed_output.mar\n");
73 printf("(i) is the index of the certificate to extract\n");
74 #if defined(MACOSX) || (defined(_WIN32) && !defined(MAR_NSS))
75 printf("Verify a MAR file:\n");
76 printf(" mar [-C workingDir] -D DERFilePath -v signed_archive.mar\n");
77 printf("At most %d signature certificate DER files are specified by "
78 "-D0 DERFilePath1 -D1 DERFilePath2, ...\n", MAX_SIGNATURES);
79 #else
80 printf("Verify a MAR file:\n");
81 printf(" mar [-C workingDir] -d NSSConfigDir -n certname "
82 "-v signed_archive.mar\n");
83 printf("At most %d signature certificate names are specified by "
84 "-n0 certName -n1 certName2, ...\n", MAX_SIGNATURES);
85 #endif
86 printf("At most %d verification certificate names are specified by "
87 "-n0 certName -n1 certName2, ...\n", MAX_SIGNATURES);
88 #endif
89 printf("Print information on a MAR file:\n");
90 printf(" mar -t archive.mar\n");
92 printf("Print detailed information on a MAR file including signatures:\n");
93 printf(" mar -T archive.mar\n");
95 printf("Refresh the product information block of a MAR file:\n");
96 printf(" mar [-H MARChannelID] [-V ProductVersion] [-C workingDir] "
97 "-i unsigned_archive_to_refresh.mar\n");
99 printf("Print executable version:\n");
100 printf(" mar --version\n");
101 printf("This program does not handle unicode file paths properly\n");
104 static int mar_test_callback(MarFile *mar,
105 const MarItem *item,
106 void *unused) {
107 (void) mar; (void) unused; // avoid warnings
109 printf("%u\t0%o\t%s\n", item->length, item->flags, item->name);
110 return 0;
113 static int mar_test(const char *path) {
114 MarFile *mar;
116 mar = mar_open(path);
117 if (!mar)
118 return -1;
120 printf("SIZE\tMODE\tNAME\n");
121 mar_enum_items(mar, mar_test_callback, NULL);
123 mar_close(mar);
124 return 0;
127 int main(int argc, char **argv) {
128 char *NSSConfigDir = NULL;
129 const char *certNames[MAX_SIGNATURES];
130 char *MARChannelID = MAR_CHANNEL_ID;
131 char *productVersion = APP_VERSION;
132 #ifndef NO_SIGN_VERIFY
133 uint32_t k;
134 #endif
135 int rv = -1;
136 uint32_t certCount = 0;
137 int32_t sigIndex = -1;
139 #if !defined(NO_SIGN_VERIFY)
140 uint32_t fileSizes[MAX_SIGNATURES];
141 const uint8_t* certBuffers[MAX_SIGNATURES];
142 char* DERFilePaths[MAX_SIGNATURES];
143 #if (!defined(_WIN32) && !defined(MACOSX)) || defined(MAR_NSS)
144 CERTCertificate* certs[MAX_SIGNATURES];
145 #endif
146 #endif
148 memset((void*)certNames, 0, sizeof(certNames));
149 #if defined(_WIN32) && !defined(MAR_NSS) && !defined(NO_SIGN_VERIFY)
150 memset((void*)certBuffers, 0, sizeof(certBuffers));
151 #endif
152 #if !defined(NO_SIGN_VERIFY) && ((!defined(MAR_NSS) && defined(_WIN32)) || \
153 defined(MACOSX))
154 memset(DERFilePaths, 0, sizeof(DERFilePaths));
155 memset(fileSizes, 0, sizeof(fileSizes));
156 #endif
158 if (argc > 1 && 0 == strcmp(argv[1], "--version")) {
159 print_version();
160 return 0;
163 if (argc < 3) {
164 print_usage();
165 return -1;
168 while (argc > 0) {
169 if (argv[1][0] == '-' && (argv[1][1] == 'c' ||
170 argv[1][1] == 't' || argv[1][1] == 'x' ||
171 argv[1][1] == 'v' || argv[1][1] == 's' ||
172 argv[1][1] == 'i' || argv[1][1] == 'T' ||
173 argv[1][1] == 'r' || argv[1][1] == 'X' ||
174 argv[1][1] == 'I')) {
175 break;
176 /* -C workingdirectory */
177 } else if (argv[1][0] == '-' && argv[1][1] == 'C') {
178 chdir(argv[2]);
179 argv += 2;
180 argc -= 2;
182 #if !defined(NO_SIGN_VERIFY) && ((!defined(MAR_NSS) && defined(_WIN32)) || \
183 defined(MACOSX))
184 /* -D DERFilePath, also matches -D[index] DERFilePath
185 We allow an index for verifying to be symmetric
186 with the import and export command line arguments. */
187 else if (argv[1][0] == '-' &&
188 argv[1][1] == 'D' &&
189 (argv[1][2] == (char)('0' + certCount) || argv[1][2] == '\0')) {
190 if (certCount >= MAX_SIGNATURES) {
191 print_usage();
192 return -1;
194 DERFilePaths[certCount++] = argv[2];
195 argv += 2;
196 argc -= 2;
198 #endif
199 /* -d NSSConfigdir */
200 else if (argv[1][0] == '-' && argv[1][1] == 'd') {
201 NSSConfigDir = argv[2];
202 argv += 2;
203 argc -= 2;
204 /* -n certName, also matches -n[index] certName
205 We allow an index for verifying to be symmetric
206 with the import and export command line arguments. */
207 } else if (argv[1][0] == '-' &&
208 argv[1][1] == 'n' &&
209 (argv[1][2] == (char)('0' + certCount) ||
210 argv[1][2] == '\0' ||
211 !strcmp(argv[2], "-X") ||
212 !strcmp(argv[2], "-I"))) {
213 if (certCount >= MAX_SIGNATURES) {
214 print_usage();
215 return -1;
217 certNames[certCount++] = argv[2];
218 if (strlen(argv[1]) > 2 &&
219 (!strcmp(argv[2], "-X") || !strcmp(argv[2], "-I")) &&
220 argv[1][2] >= '0' && argv[1][2] <= '9') {
221 sigIndex = argv[1][2] - '0';
222 argv++;
223 argc--;
224 } else {
225 argv += 2;
226 argc -= 2;
228 /* MAR channel ID */
229 } else if (argv[1][0] == '-' && argv[1][1] == 'H') {
230 MARChannelID = argv[2];
231 argv += 2;
232 argc -= 2;
233 /* Product Version */
234 } else if (argv[1][0] == '-' && argv[1][1] == 'V') {
235 productVersion = argv[2];
236 argv += 2;
237 argc -= 2;
239 else {
240 print_usage();
241 return -1;
245 if (argv[1][0] != '-') {
246 print_usage();
247 return -1;
250 switch (argv[1][1]) {
251 case 'c': {
252 struct ProductInformationBlock infoBlock;
253 infoBlock.MARChannelID = MARChannelID;
254 infoBlock.productVersion = productVersion;
255 if (argv[argc - 2][0] == '-' && argv[argc - 2][1] == 'f')
257 char buf[1000];
258 FILE* file;
259 char** files;
260 int num_files = 0;
262 files = (char **)malloc(sizeof(char*)*10000);
263 errno = 0;
264 file = fopen(argv[argc - 1], "r");
265 if (!file)
267 printf("%d %s", errno, strerror(errno));
268 printf("Could not open file: %s", argv[argc - 1]);
269 exit(1);
272 while(fgets(buf, 1000, file) != NULL)
274 int j;
275 size_t str_len;
276 for (j=strlen(buf)-1;j>=0 && (buf[j]=='\n' || buf[j]=='\r');j--)
278 buf[j+1]='\0';
279 str_len = strlen(buf) + 1;
280 files[num_files] = (char*)malloc(sizeof(char)*str_len);
281 strcpy(files[num_files], buf);
282 ++num_files;
284 fclose(file);
285 return mar_create(argv[2], num_files, files, &infoBlock);
287 else
288 return mar_create(argv[2], argc - 3, argv + 3, &infoBlock);
290 case 'i': {
291 struct ProductInformationBlock infoBlock;
292 infoBlock.MARChannelID = MARChannelID;
293 infoBlock.productVersion = productVersion;
294 return refresh_product_info_block(argv[2], &infoBlock);
296 case 'T': {
297 struct ProductInformationBlock infoBlock;
298 uint32_t numSignatures, numAdditionalBlocks;
299 int hasSignatureBlock, hasAdditionalBlock;
300 if (!get_mar_file_info(argv[2],
301 &hasSignatureBlock,
302 &numSignatures,
303 &hasAdditionalBlock,
304 NULL, &numAdditionalBlocks)) {
305 if (hasSignatureBlock) {
306 printf("Signature block found with %d signature%s\n",
307 numSignatures,
308 numSignatures != 1 ? "s" : "");
310 if (hasAdditionalBlock) {
311 printf("%d additional block%s found:\n",
312 numAdditionalBlocks,
313 numAdditionalBlocks != 1 ? "s" : "");
316 rv = read_product_info_block(argv[2], &infoBlock);
317 if (!rv) {
318 printf(" - Product Information Block:\n");
319 printf(" - MAR channel name: %s\n"
320 " - Product version: %s\n",
321 infoBlock.MARChannelID,
322 infoBlock.productVersion);
323 free((void *)infoBlock.MARChannelID);
324 free((void *)infoBlock.productVersion);
327 printf("\n");
328 /* The fall through from 'T' to 't' is intentional */
330 /* Fall through */
331 case 't':
332 return mar_test(argv[2]);
334 /* Extract a MAR file */
335 case 'x':
336 return mar_extract(argv[2]);
338 #ifndef NO_SIGN_VERIFY
339 /* Extract a MAR signature */
340 case 'X':
341 if (sigIndex == -1) {
342 fprintf(stderr, "ERROR: Signature index was not passed.\n");
343 return -1;
345 if (sigIndex >= MAX_SIGNATURES || sigIndex < -1) {
346 fprintf(stderr, "ERROR: Signature index is out of range: %d.\n",
347 sigIndex);
348 return -1;
350 return extract_signature(argv[2], sigIndex, argv[3]);
352 /* Import a MAR signature */
353 case 'I':
354 if (sigIndex == -1) {
355 fprintf(stderr, "ERROR: signature index was not passed.\n");
356 return -1;
358 if (sigIndex >= MAX_SIGNATURES || sigIndex < -1) {
359 fprintf(stderr, "ERROR: Signature index is out of range: %d.\n",
360 sigIndex);
361 return -1;
363 if (argc < 5) {
364 print_usage();
365 return -1;
367 return import_signature(argv[2], sigIndex, argv[3], argv[4]);
369 case 'v':
370 if (certCount == 0) {
371 print_usage();
372 return -1;
375 #if (!defined(_WIN32) && !defined(MACOSX)) || defined(MAR_NSS)
376 if (!NSSConfigDir || certCount == 0) {
377 print_usage();
378 return -1;
381 if (NSSInitCryptoContext(NSSConfigDir)) {
382 fprintf(stderr, "ERROR: Could not initialize crypto library.\n");
383 return -1;
385 #endif
387 rv = 0;
388 for (k = 0; k < certCount; ++k) {
389 #if (defined(_WIN32) || defined(MACOSX)) && !defined(MAR_NSS)
390 rv = mar_read_entire_file(DERFilePaths[k], MAR_MAX_CERT_SIZE,
391 &certBuffers[k], &fileSizes[k]);
392 #else
393 /* It is somewhat circuitous to look up a CERTCertificate and then pass
394 * in its DER encoding just so we can later re-create that
395 * CERTCertificate to extract the public key out of it. However, by doing
396 * things this way, we maximize the reuse of the mar_verify_signatures
397 * function and also we keep the control flow as similar as possible
398 * between programs and operating systems, at least for the functions
399 * that are critically important to security.
401 certs[k] = PK11_FindCertFromNickname(certNames[k], NULL);
402 if (certs[k]) {
403 certBuffers[k] = certs[k]->derCert.data;
404 fileSizes[k] = certs[k]->derCert.len;
405 } else {
406 rv = -1;
408 #endif
409 if (rv) {
410 fprintf(stderr, "ERROR: could not read file %s", DERFilePaths[k]);
411 break;
415 if (!rv) {
416 MarFile *mar = mar_open(argv[2]);
417 if (mar) {
418 rv = mar_verify_signatures(mar, certBuffers, fileSizes, certCount);
419 mar_close(mar);
420 } else {
421 fprintf(stderr, "ERROR: Could not open MAR file.\n");
422 rv = -1;
425 for (k = 0; k < certCount; ++k) {
426 #if (defined(_WIN32) || defined(MACOSX)) && !defined(MAR_NSS)
427 free((void*)certBuffers[k]);
428 #else
429 /* certBuffers[k] is owned by certs[k] so don't free it */
430 CERT_DestroyCertificate(certs[k]);
431 #endif
433 if (rv) {
434 /* Determine if the source MAR file has the new fields for signing */
435 int hasSignatureBlock;
436 if (get_mar_file_info(argv[2], &hasSignatureBlock,
437 NULL, NULL, NULL, NULL)) {
438 fprintf(stderr, "ERROR: could not determine if MAR is old or new.\n");
439 } else if (!hasSignatureBlock) {
440 fprintf(stderr, "ERROR: The MAR file is in the old format so has"
441 " no signature to verify.\n");
443 return -1;
445 return 0;
447 case 's':
448 if (!NSSConfigDir || certCount == 0 || argc < 4) {
449 print_usage();
450 return -1;
452 return mar_repackage_and_sign(NSSConfigDir, certNames, certCount,
453 argv[2], argv[3]);
455 case 'r':
456 return strip_signature_block(argv[2], argv[3]);
457 #endif /* endif NO_SIGN_VERIFY disabled */
459 default:
460 print_usage();
461 return -1;