1/* 2 * Copyright (c) 2005 Rob Braun 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 * 3. Neither the name of Rob Braun nor the names of his contributors 14 * may be used to endorse or promote products derived from this software 15 * without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 27 * POSSIBILITY OF SUCH DAMAGE. 28 */ 29/* 30 * 03-Apr-2005 31 * DRI: Rob Braun <bbraun@opendarwin.org> 32 */ 33 34#include <stdlib.h> 35#include <stdio.h> 36#include <string.h> 37#include <sys/types.h> 38#include <sys/stat.h> 39#include <fts.h> 40#include <unistd.h> 41#include <fcntl.h> 42#include <inttypes.h> 43#include <netinet/in.h> 44#include <libxml/xmlreader.h> 45#include <libxml/xmlwriter.h> 46#include <libxml/xmlstring.h> 47#include <limits.h> 48#include <getopt.h> 49#include <regex.h> 50#include <errno.h> 51#ifdef XARSIG_BUILDING_WITH_XAR 52#include "xar.h" 53#else 54#include <xar/xar.h> 55#endif // XARSIG_BUILDING_WITH_XAR 56#include "filetree.h" 57 58#define SYMBOLIC 1 59#define NUMERIC 2 60 61// error codes for B&I 62#define E_NOSIG 60 63#define E_SIGEXISTS 61 64 65static int Perms = 0; 66static int Local = 0; 67static char *Subdoc = NULL; 68static char *SubdocName = NULL; 69static char *Toccksum = NULL; 70static char *Filecksum = NULL; 71static char *Compression = NULL; 72static char *Rsize = NULL; 73static char *DataToSignDumpPath = NULL; 74static char *SigOffsetDumpPath = NULL; 75static char *LeafCertPath = NULL; 76static char *IntermediateCertPath = NULL; 77static char *RootCertPath = NULL; 78 79static int Err = 0; 80static int Verbose = 0; 81static int Coalesce = 0; 82static int LinkSame = 0; 83static int DoSign = 0; 84 85static long SigSize = 0; 86 87struct lnode { 88 char *str; 89 regex_t reg; 90 struct lnode *next; 91}; 92struct __stack_element { 93 struct __stack_element *prev; 94 struct __stack_element *next; 95 void *data; 96}; 97struct __stack { 98 struct __stack_element *bottom; 99 struct __stack_element *top; 100}; 101 102typedef struct __stack_element *stack_element; 103typedef struct __stack *stack; 104 105struct lnode *Exclude = NULL; 106struct lnode *Exclude_Tail = NULL; 107struct lnode *NoCompress = NULL; 108struct lnode *NoCompress_Tail = NULL; 109 110static int32_t err_callback(int32_t sev, int32_t err, xar_errctx_t ctx, void *usrctx); 111static int32_t signingCallback(xar_signature_t sig, void *context, uint8_t *data, uint32_t length, uint8_t **signed_data, uint32_t *signed_len); 112static void insert_cert(xar_signature_t sig, const char *cert_path); 113static void add_subdoc(xar_t x); 114 115static void _set_xarsig_opts_from_args(xar_t x) { 116 // Update checksum algorithms before we start messing with the heap length in xar_signature_new() 117 if( Toccksum ) 118 xar_opt_set(x, XAR_OPT_TOCCKSUM, Toccksum); 119 120 if( Filecksum ) 121 xar_opt_set(x, XAR_OPT_FILECKSUM, Filecksum); 122 123 if ( SigSize ) { 124 xar_signature_t sig = xar_signature_new(x, "RSA", SigSize, &signingCallback, NULL); 125 if ( LeafCertPath ) 126 insert_cert(sig, LeafCertPath); 127 if ( IntermediateCertPath ) 128 insert_cert(sig, IntermediateCertPath); 129 if ( RootCertPath ) 130 insert_cert(sig, RootCertPath); 131 } 132 133 if( Compression ) 134 xar_opt_set(x, XAR_OPT_COMPRESSION, Compression); 135 136 if( Coalesce ) 137 xar_opt_set(x, XAR_OPT_COALESCE, "true"); 138 139 if( LinkSame ) 140 xar_opt_set(x, XAR_OPT_LINKSAME, "true"); 141 142 if ( Rsize != NULL ) 143 xar_opt_set(x, XAR_OPT_RSIZE, Rsize); 144 145 xar_register_errhandler(x, err_callback, NULL); 146 147 if( Subdoc ) 148 add_subdoc(x); 149 150 if( Perms == SYMBOLIC ) { 151 xar_opt_set(x, XAR_OPT_OWNERSHIP, XAR_OPT_VAL_SYMBOLIC); 152 } 153 if( Perms == NUMERIC ) { 154 xar_opt_set(x, XAR_OPT_OWNERSHIP, XAR_OPT_VAL_NUMERIC); 155 } 156} 157 158static void print_file(xar_file_t f) { 159 if( Verbose ) { 160 char *path = xar_get_path(f); 161 printf("%s\n", path); 162 free(path); 163 } 164} 165 166static void add_subdoc(xar_t x) { 167 xar_subdoc_t s; 168 int fd; 169 unsigned char *buf; 170 unsigned int len; 171 struct stat sb; 172 173 if( SubdocName == NULL ) SubdocName = "subdoc"; 174 s = xar_subdoc_new(x, (const char *)SubdocName); 175 176 fd = open(Subdoc, O_RDONLY); 177 if( fd < 0 ) 178 return; 179 fstat(fd, &sb); 180 len = sb.st_size; 181 buf = malloc(len+1); 182 if( buf == NULL ) { 183 close(fd); 184 return; 185 } 186 memset(buf, 0, len+1); 187 read(fd, buf, len); 188 close(fd); 189 190 xar_subdoc_copyin(s, buf, len); 191 192 193 return; 194} 195 196static void extract_subdoc(xar_t x, const char *name) { 197 xar_subdoc_t i; 198 199 for( i = xar_subdoc_first(x); i; i = xar_subdoc_next(i) ) { 200 const char *sname = xar_subdoc_name(i); 201 unsigned char *sdoc; 202 int fd, size; 203 if( name && strcmp(name, sname) != 0 ) 204 continue; 205 xar_subdoc_copyout(i, &sdoc, (unsigned int *)&size); 206 fd = open(Subdoc, O_WRONLY|O_CREAT|O_TRUNC, 0644); 207 if( fd < 0 ) return; 208 write(fd, sdoc, size); 209 close(fd); 210 free(sdoc); 211 } 212 213 return; 214} 215 216static void extract_data_to_sign(const char *filename) { 217 xar_signature_t sig; 218 off_t signatureOffset; 219 FILE *file; 220 xar_t x; 221 int i; 222 uint32_t dataToSignOffset = 0; 223 uint32_t dataToSignSize = 0; 224 char *buffer = NULL; 225 const char *value; 226 227 // find signature stub 228 x = xar_open(filename, READ); 229 if ( x == NULL ) { 230 fprintf(stderr, "Could not open %s to extract data to sign!\n", filename); 231 exit(1); 232 } 233 sig = xar_signature_first(x); 234 if ( !sig ) { 235 fprintf(stderr, "No signatures found to extract data from.\n"); 236 exit(E_NOSIG); 237 } 238 239 // locate data to sign 240 if( 0 != xar_prop_get((xar_file_t)x, "checksum/offset" ,&value) ) { 241 fprintf(stderr, "Could not locate checksum/offset in archive.\n"); 242 exit(1); 243 } 244 dataToSignOffset = xar_get_heap_offset(x); 245 dataToSignOffset += strtoull(value, (char **)NULL, 10); 246 if( 0 != xar_prop_get((xar_file_t)x, "checksum/size" ,&value) ) { 247 fprintf(stderr, "Could not locate checksum/size in archive.\n"); 248 exit(1); 249 } 250 dataToSignSize = strtoull(value, (char **)NULL, 10); 251 252 // get signature offset (inject signature here) 253 xar_signature_copy_signed_data(sig, NULL, NULL, NULL, NULL, &signatureOffset); 254 signatureOffset += xar_get_heap_offset(x); 255 xar_close(x); 256 257 // now get data to be signed, using offset and size 258 file = fopen(filename, "r"); 259 if (!file) { 260 fprintf(stderr, "Could not open %s for reading data to sign!\n", filename); 261 exit(1); 262 } 263 fseek(file, dataToSignOffset, SEEK_SET); 264 buffer = malloc(dataToSignSize); 265 i = fread(buffer, dataToSignSize, 1, file); 266 if (i != 1) { 267 fprintf(stderr, "Failed to read data to sign from %s!\n", filename); 268 exit(1); 269 } 270 fclose(file); 271 272 // save data to sign 273 file = fopen(DataToSignDumpPath, "w"); 274 if (!file) { 275 fprintf(stderr, "Could not open %s for saving data to sign!\n", DataToSignDumpPath); 276 exit(1); 277 } 278 i = fwrite(buffer, dataToSignSize, 1, file); 279 if (i != 1) { 280 fprintf(stderr, "Failed to write data to sign to %s (fwrite() returned %i)!\n", DataToSignDumpPath, i); 281 exit(1); 282 } 283 fclose(file); 284 285 // save signature offset 286 file = fopen(SigOffsetDumpPath, "w"); 287 if (!file) { 288 fprintf(stderr, "Could not open %s for saving signature offset!\n", SigOffsetDumpPath); 289 exit(1); 290 } 291 i = fprintf(file, "%lli\n", signatureOffset); 292 if (i < 0) { 293 fprintf(stderr, "Failed to write signature offset to %s (fprintf() returned %i)!\n", SigOffsetDumpPath, i); 294 exit(1); 295 } 296 fclose(file); 297 298 free(buffer); 299} 300 301static void extract_certs(char *filename, char *cert_base_path) { 302 xar_signature_t sig; 303 xar_t x; 304 int32_t count; 305 int i; 306 const uint8_t *cert_data; 307 uint32_t cert_len; 308 FILE *file; 309 char *cert_path; 310 311 // open xar, get signature 312 x = xar_open(filename, READ); 313 if ( x == NULL ) { 314 fprintf(stderr, "Could not open %s to extract certificates!\n", filename); 315 exit(1); 316 } 317 sig = xar_signature_first(x); 318 if ( !sig ) { 319 fprintf(stderr, "No signatures found to extract data from.\n"); 320 exit(E_NOSIG); 321 } 322 323 // iterate through all certificates associated with that signature, write them to disk 324 count = xar_signature_get_x509certificate_count(sig); 325 if (!count) { 326 fprintf(stderr, "Signature bears no certificates. Odd.\n"); 327 exit(1); 328 } 329 for (i=0; i<count; i++) { 330 xar_signature_get_x509certificate_data(sig, i, &cert_data, &cert_len); 331 asprintf(&cert_path, "%s/cert%02i", cert_base_path, i); 332 file = fopen(cert_path, "w"); 333 if (!file) { 334 fprintf(stderr, "Could not save certificate %i to %s.\n", i, cert_path); 335 exit(1); 336 } 337 int n = fwrite(cert_data, cert_len, 1, file); 338 if (n < 0) { 339 fprintf(stderr, "Failed to write certificate to %s (fwrite() returned %i)!\n", cert_path, n); 340 exit(1); 341 } 342 fclose(file); 343 free(cert_path); 344 } 345 346 // clean up 347 xar_close(x); 348} 349 350static off_t get_sig_offset(xar_t x) { 351 off_t signedDataOffset = 0; 352 353 xar_signature_t sig = xar_signature_first(x); 354 xar_signature_copy_signed_data(sig,NULL,NULL,NULL,NULL,&signedDataOffset); 355 signedDataOffset += xar_get_heap_offset(x); 356 return signedDataOffset; 357} 358 359static int extract_sig_offset(xar_t x, const char *filename) { 360 off_t signedDataOffset; 361 FILE *file; 362 int i; 363 364 // get offset 365 signedDataOffset = get_sig_offset(x); 366 367 // and save it to file 368 file = fopen(filename, "w"); 369 if (!file) { 370 fprintf(stderr, "Could not open %s for saving signature offset!\n", filename); 371 return 1; 372 } 373 i = fprintf(file, "%lli\n", signedDataOffset); 374 if (i < 0) { 375 fprintf(stderr, "Failed to write signature offset to %s (fprintf() returned %i)!\n", filename, i); 376 return 1; 377 } 378 fclose(file); 379 380 return 0; 381} 382 383stack stack_new() { 384 stack s = (stack)malloc(sizeof(struct __stack)); 385 s->bottom = s->top = NULL; 386 return s; 387} 388void stack_free(stack s) { 389 free(s); 390} 391void stack_push(stack s, void *data) { 392 stack_element e = malloc(sizeof(struct __stack_element)); 393 e->data = data; 394 if (s->top) { 395 s->top->next = e; 396 e->prev = s->top; 397 } else { 398 s->top = s->bottom = e; 399 e->prev = NULL; 400 } 401 e->next = NULL; 402 s->top = e; 403} 404void *stack_pop(stack s) { 405 if (!s->top) 406 return NULL; 407 void *ret = s->top->data; 408 stack_element temp = s->top; 409 s->top = s->top->prev; 410 free(temp); 411 if (s->top) 412 s->top->next = NULL; 413 else 414 s->bottom = NULL; 415 return ret; 416} 417 418/* replace_sign: rip out all current signatures and certs and insert a new pair 419 Since libxar is currently not capable of doing this directly, we have to create a new xar archive, 420 copy all the files and options from the current archive, and sign the new archive 421*/ 422static void replace_sign(const char *filename) { 423 424 xar_t old_xar, new_xar; 425 xar_signature_t sig; 426 char *new_xar_path = (char *)malloc(15); 427 strncpy(new_xar_path, "/tmp/xar.XXXXX", 15); 428 new_xar_path = mktemp(new_xar_path); 429 char *systemcall; 430 int err; 431 432 // open the first archive 433 old_xar = xar_open(filename, READ); 434 if ( old_xar == NULL ) { 435 fprintf(stderr, "Could not open archive %s!\n", filename); 436 exit(1); 437 } 438 439 // use command-line arguments to set xar opts; the copy operation below won't work unless they're set in the first place! 440 _set_xarsig_opts_from_args(old_xar); 441 442 // open the second archive 443 new_xar = xar_open(new_xar_path, WRITE); 444 if( !new_xar ) { 445 fprintf(stderr, "Error creating new archive %s\n", new_xar_path); 446 exit(1); 447 } 448 449 // copy options 450 char *opts[7] = {XAR_OPT_TOCCKSUM, XAR_OPT_FILECKSUM, XAR_OPT_COMPRESSION, XAR_OPT_COALESCE, XAR_OPT_LINKSAME, XAR_OPT_RSIZE, XAR_OPT_OWNERSHIP}; 451 int i; 452 const char *opt; 453 for (i=0; i<7; i++) { 454 opt = xar_opt_get(old_xar, opts[i]); 455 if (opt) 456 xar_opt_set(new_xar, opts[i], opt); 457 } 458 459 // install new signature and new certs in new_xar 460 sig = xar_signature_new(new_xar, "RSA", SigSize, &signingCallback, NULL); 461 if ( LeafCertPath ) 462 insert_cert(sig, LeafCertPath); 463 if ( IntermediateCertPath ) 464 insert_cert(sig, IntermediateCertPath); 465 if ( RootCertPath ) 466 insert_cert(sig, RootCertPath); 467 468 // skip copy subdocs for now since we don't use them yet 469 470 // copy files 471 xar_iter_t iter = xar_iter_new(); 472 xar_file_t f = xar_file_first(old_xar, iter); 473 // xar_file_next iterates the archive depth-first, i.e. all children are enumerated before the siblings. 474 const char *name; 475 stack s_new = stack_new(); 476 stack s_old = stack_new(); 477 xar_file_t last_copied = NULL, last_added; 478 479 xar_iter_t loopIter = xar_iter_new(); 480 xar_file_t current_xar_file; 481 for (current_xar_file = xar_file_first(old_xar, loopIter); current_xar_file; current_xar_file = xar_file_next(loopIter)) 482 { 483 printf("old_xar -> %s (parent: %s)\n",xar_get_path(current_xar_file),XAR_FILE(current_xar_file)->parent?xar_get_path(XAR_FILE(current_xar_file)->parent):"(nil)"); 484 } 485 486 do { 487 // parent is the parent in the new archive! 488 // 3 cases: 489 // 1. the file has no parent. Happens for every file at the top level of the archive. 490 // 2. the file's parent is the last file we added. Happens while descending down a path 491 // 3. the file's parent is one of the ancestors of the last file (and not NULL, that would be case 1) 492 // that means we either go back up the tree and add a sibling of one of the ancestors, or we add a 493 // sibling on the same level 494 xar_prop_get(f, "name", &name); // filename, without any path info 495 if (!XAR_FILE(f)->parent) { // case 1 496 printf("root: %s\n",xar_get_path(f)); 497 last_added = xar_add_from_archive(new_xar, NULL, name, old_xar, f); 498 last_copied = f; 499 stack_push(s_new, (void *)last_added); 500 stack_push(s_old, (void *)last_copied); 501 } else if (f->parent == last_copied) { // case 2 502 printf("child: %s -> %s\n",xar_get_path(f->parent),xar_get_path(f)); 503 last_added = xar_add_from_archive(new_xar, last_added, name, old_xar, f); 504 last_copied = f; 505 stack_push(s_new, (void *)last_added); 506 stack_push(s_old, (void *)last_copied); 507 } else { // case 3 508 printf("searching for parent: %s ?\n",xar_get_path(f)); 509 while (XAR_FILE(f)->parent != XAR_FILE(s_old->top->data)->parent) { 510 printf("popping: %s\n",xar_get_path(XAR_FILE(s_old->top->data))); 511 stack_pop(s_new); 512 stack_pop(s_old); 513 } 514 printf("found: %s -> %s\n",xar_get_path(XAR_FILE(s_new->top->data)),xar_get_path(f)); 515 stack_pop(s_new); 516 stack_pop(s_old); 517 last_added = xar_add_from_archive(new_xar, (xar_file_t)(s_new->top->data), name, old_xar, f); 518 last_copied = f; 519 stack_push(s_new, (void *)last_added); 520 stack_push(s_old, (void *)last_copied); 521 } 522 } while ((f = xar_file_next(iter))); 523 524 loopIter = xar_iter_new(); 525 for (current_xar_file = xar_file_first(new_xar, loopIter); current_xar_file; current_xar_file = xar_file_next(loopIter)) 526 { 527 char * current_path = xar_get_path(current_xar_file); 528 printf("new_xar -> %s\n",current_path); 529 } 530 531 xar_iter_free(iter); 532 stack_free(s_new); 533 stack_free(s_old); 534 if( xar_close(new_xar) != 0 ) { 535 fprintf(stderr, "Error creating the archive\n"); 536 if( !Err ) 537 Err = 42; 538 } 539 xar_close(old_xar); 540 541 // write signature offset to file (have to re-open so xar_close can figure out the correct offset) 542 new_xar = xar_open(new_xar_path, READ); 543 if( !new_xar ) { 544 fprintf(stderr, "Error re-opening new archive %s\n", new_xar_path); 545 unlink(new_xar_path); 546 exit(1); 547 } 548 549 if (extract_sig_offset(new_xar, SigOffsetDumpPath)) { 550 xar_close(new_xar); 551 unlink(new_xar_path); 552 exit(1); 553 } 554 555 xar_close(new_xar); 556 557 // delete old archive, move new in its place 558 unlink(filename); 559 asprintf(&systemcall, "cp \"%s\" \"%s\"", new_xar_path, filename); 560 err = system(systemcall); 561 if (err) { 562 fprintf(stderr, "Could not copy new archive to final location (system() returned %i)\n", err); 563 unlink(new_xar_path); 564 exit(1); 565 } 566 567 // Delete the tmp archive 568 unlink(new_xar_path); 569 570 free(systemcall); 571} 572 573/* belated_sign 574 Prepare a previously unsigned archive for signing by creating a signature placeholder and inserting the certificates. 575 Since libxar is currently not capable of doing this directly, we have to create a new xar archive, 576 copy all the files and options from the current archive, and sign the new archive 577*/ 578static void belated_sign(const char *filename) { 579 xar_t x = xar_open(filename, READ); 580 if ( x == NULL ) { 581 fprintf(stderr, "Could not open archive %s!\n", filename); 582 exit(1); 583 } 584 xar_signature_t sig = xar_signature_first(x); 585 if ( sig ) { 586 fprintf(stderr, "Archive has already been signed. Use --replace-sign instead.\n"); 587 exit(E_SIGEXISTS); 588 } 589 xar_close(x); 590 replace_sign(filename); 591} 592 593static int32_t signingCallback(xar_signature_t sig, void *context, uint8_t *data, uint32_t length, uint8_t **signed_data, uint32_t *signed_len) { 594 595 // save data to file for later signature 596 if (DataToSignDumpPath) { 597 FILE *file = fopen(DataToSignDumpPath, "w"); 598 if (!file) { 599 fprintf(stderr, "Could not open %s for saving data to sign!\n", DataToSignDumpPath); 600 exit(1); 601 } 602 int i = fwrite(data, length, 1, file); 603 if (i != 1) { 604 fprintf(stderr, "Failed to write data to sign to %s (fwrite() returned %i)!\n", DataToSignDumpPath, i); 605 exit(1); 606 } 607 fclose(file); 608 } 609 610 // now return blank placeholder data 611 *signed_data = (uint8_t *)malloc(SigSize); 612 memset(*signed_data, 0, SigSize); 613 strncpy((char *)*signed_data, "helloworld", 10); // debug 614 *signed_len = SigSize; 615 return 0; // no error 616} 617 618static void insert_cert(xar_signature_t sig, const char *cert_path) { 619 struct stat *s = malloc(sizeof(struct stat)); 620 if (stat(cert_path, s) == -1) { 621 fprintf(stderr, "Could not stat() certificate file %s (errno == %i)\n", cert_path, errno); 622 exit(1); 623 } 624 void *cert = malloc(s->st_size); 625 FILE *file = fopen(cert_path, "r"); 626 if (!file) { 627 fprintf(stderr, "Could not open %s for reading certificate!\n", cert_path); 628 exit(1); 629 } 630 int i = fread(cert, s->st_size, 1, file); 631 if (i != 1) { 632 fprintf(stderr, "Failed to read certificate from %s!\n", cert_path); 633 exit(1); 634 } 635 fclose(file); 636 xar_signature_add_x509certificate(sig, cert, s->st_size); 637 free(s); 638 free(cert); 639} 640 641static void inject_signature(const char *xar_path, const char *sig_path) { 642 // since there is no API to insert a signature other than during signingCallback time, we have to 643 // inject it by editing the raw file 644 int buffer_size = 1024; 645 void *buffer = malloc(buffer_size); 646 FILE *sig, *xar; 647 off_t signedDataOffset; 648 xar_t x; 649 int i; 650 651 printf("inject_signature(%s, %s)",xar_path,sig_path); 652 653 // open xar via the API first to determine the signature offset 654 x = xar_open(xar_path, READ); 655 if ( x == NULL ) { 656 fprintf(stderr, "Could not open xar archive %s to get signature offset!\n", xar_path); 657 exit(1); 658 } 659 signedDataOffset = get_sig_offset(x); 660 xar_close(x); 661 662 // then re-open xar and signature files raw... 663 sig = fopen(sig_path, "r"); 664 if (!sig) { 665 fprintf(stderr, "Could not open %s for reading signature!\n", sig_path); 666 exit(1); 667 } 668 xar = fopen(xar_path, "r+"); 669 if (!xar) { 670 fprintf(stderr, "Could not open xar archive %s for injecting signature!\n", xar_path); 671 exit(1); 672 } 673 674 // ...and inject the signature 675 fseek(xar, signedDataOffset, SEEK_SET); 676 do { 677 i = fread(buffer, 1, buffer_size, sig); 678 if (ferror(sig)) { 679 fprintf(stderr, "Failed to read signature from %s!\n", sig_path); 680 exit(1); 681 } 682 fwrite(buffer, 1, i, xar); 683 } while (!feof(sig)); 684 fclose(sig); 685 fclose(xar); 686 687 free(buffer); 688} 689 690static int archive(const char *filename, int arglen, char *args[]) { 691 xar_t x; 692 FTS *fts; 693 FTSENT *ent; 694 int flags; 695 struct lnode *i; 696 const char *default_compression; 697 698 x = xar_open(filename, WRITE); 699 if( !x ) { 700 fprintf(stderr, "Error creating archive %s\n", filename); 701 exit(1); 702 } 703 704 _set_xarsig_opts_from_args(x); 705 706 default_compression = strdup(xar_opt_get(x, XAR_OPT_COMPRESSION)); 707 if( !default_compression ) 708 default_compression = strdup(XAR_OPT_VAL_GZIP); 709 710 flags = FTS_PHYSICAL|FTS_NOSTAT|FTS_NOCHDIR; 711 if( Local ) 712 flags |= FTS_XDEV; 713 fts = fts_open(args, flags, NULL); 714 if( !fts ) { 715 fprintf(stderr, "Error traversing file tree\n"); 716 exit(1); 717 } 718 719 while( (ent = fts_read(fts)) ) { 720 xar_file_t f; 721 int exclude_match = 1; 722 int nocompress_match = 1; 723 if( ent->fts_info == FTS_DP ) 724 continue; 725 726 if( strcmp(ent->fts_path, "/") == 0 ) 727 continue; 728 if( strcmp(ent->fts_path, ".") == 0 ) 729 continue; 730 731 for( i = Exclude; i; i=i->next ) { 732 exclude_match = regexec(&i->reg, ent->fts_path, 0, NULL, 0); 733 if( !exclude_match ) 734 break; 735 } 736 if( !exclude_match ) { 737 if( Verbose ) 738 printf("Excluding %s\n", ent->fts_path); 739 continue; 740 } 741 742 for( i = NoCompress; i; i=i->next ) { 743 nocompress_match = regexec(&i->reg, ent->fts_path, 0, NULL, 0); 744 if( !nocompress_match ) { 745 xar_opt_set(x, XAR_OPT_COMPRESSION, XAR_OPT_VAL_NONE); 746 break; 747 } 748 } 749 f = xar_add(x, ent->fts_path); 750 if( !f ) { 751 fprintf(stderr, "Error adding file %s\n", ent->fts_path); 752 } else { 753 print_file(f); 754 } 755 if( !nocompress_match ) 756 xar_opt_set(x, XAR_OPT_COMPRESSION, default_compression); 757 } 758 fts_close(fts); 759 if( xar_close(x) != 0 ) { 760 fprintf(stderr, "Error creating the archive\n"); 761 if( !Err ) 762 Err = 42; 763 } 764 765 free((char *)default_compression); 766 for( i = Exclude; i; ) { 767 struct lnode *tmp; 768 regfree(&i->reg); 769 tmp = i; 770 i = i->next; 771 free(tmp); 772 } 773 for( i = NoCompress; i; ) { 774 struct lnode *tmp; 775 regfree(&i->reg); 776 tmp = i; 777 i = i->next; 778 free(tmp); 779 } 780 781 if ( SigOffsetDumpPath ) { 782 x = xar_open(filename, READ); 783 if( !x ) { 784 fprintf(stderr, "Error re-opening archive %s\n", filename); 785 exit(1); 786 } 787 if (extract_sig_offset(x, SigOffsetDumpPath)) 788 exit(1); 789 } 790 791 return Err; 792} 793 794static int extract(const char *filename, int arglen, char *args[]) { 795 xar_t x; 796 xar_iter_t i; 797 xar_file_t f; 798 int files_extracted = 0; 799 800 x = xar_open(filename, READ); 801 if( !x ) { 802 fprintf(stderr, "Error opening xar archive: %s\n", filename); 803 exit(1); 804 } 805 806 xar_register_errhandler(x, err_callback, NULL); 807 808 if( Perms == SYMBOLIC ) { 809 xar_opt_set(x, XAR_OPT_OWNERSHIP, XAR_OPT_VAL_SYMBOLIC); 810 } 811 if( Perms == NUMERIC ) { 812 xar_opt_set(x, XAR_OPT_OWNERSHIP, XAR_OPT_VAL_NUMERIC); 813 } 814 if ( Rsize != NULL ) { 815 xar_opt_set(x, XAR_OPT_RSIZE, Rsize); 816 } 817 818 i = xar_iter_new(); 819 if( !i ) { 820 fprintf(stderr, "Error creating xar iterator\n"); 821 exit(1); 822 } 823 824 for(f = xar_file_first(x, i); f; f = xar_file_next(i)) { 825 int matched = 0; 826 int exclude_match = 1; 827 struct lnode *i; 828 829 char *path = xar_get_path(f); 830 831 if( args[0] ) { 832 int i; 833 for(i = 0; args[i]; i++) { 834 if( strcmp(path, args[i]) == 0 ) { 835 matched = 1; 836 break; 837 } 838 } 839 } else { 840 matched = 1; 841 } 842 843 for( i = Exclude; i; i=i->next ) { 844 exclude_match = regexec(&i->reg, path, 0, NULL, 0); 845 if( !exclude_match ) 846 break; 847 } 848 if( !exclude_match ) { 849 if( Verbose ) 850 printf("Excluding %s\n", path); 851 free(path); 852 continue; 853 } 854 855 if( matched ) { 856 files_extracted++; 857 print_file(f); 858 xar_extract(x, f); 859 } 860 free(path); 861 } 862 if( args[0] && (files_extracted == 0) ) { 863 fprintf(stderr, "No files matched extraction criteria.\n"); 864 Err = 3; 865 } 866 867 if( Subdoc ) 868 extract_subdoc(x, NULL); 869 870 xar_iter_free(i); 871 if( xar_close(x) != 0 ) { 872 fprintf(stderr, "Error extracting the archive\n"); 873 if( !Err ) 874 Err = 42; 875 } 876 return Err; 877} 878 879static int list_subdocs(const char *filename) { 880 xar_t x; 881 xar_subdoc_t s; 882 883 x = xar_open(filename, READ); 884 if( !x ) { 885 fprintf(stderr, "Error opening xar archive: %s\n", filename); 886 exit(1); 887 } 888 889 for(s = xar_subdoc_first(x); s; s = xar_subdoc_next(s)) { 890 printf("%s\n", xar_subdoc_name(s)); 891 } 892 xar_close(x); 893 894 return Err; 895} 896 897static int list(const char *filename, int arglen, char *args[]) { 898 xar_t x; 899 xar_iter_t i; 900 xar_file_t f; 901 902 x = xar_open(filename, READ); 903 if( !x ) { 904 fprintf(stderr, "Error opening xar archive: %s\n", filename); 905 exit(1); 906 } 907 908 i = xar_iter_new(); 909 if( !i ) { 910 fprintf(stderr, "Error creating xar iterator\n"); 911 exit(1); 912 } 913 914 for(f = xar_file_first(x, i); f; f = xar_file_next(i)) { 915 print_file(f); 916 } 917 918 xar_iter_free(i); 919 xar_close(x); 920 921 return Err; 922} 923 924static int dumptoc(const char *filename, const char* tocfile) { 925 xar_t x; 926 x = xar_open(filename, READ); 927 if( !x ) { 928 fprintf(stderr, "Error opening xar archive: %s\n", filename); 929 exit(1); 930 } 931 932 xar_serialize(x, tocfile); 933 xar_close(x); 934 return Err; 935} 936 937static int dump_header(const char *filename) { 938 int fd; 939 xar_header_t xh; 940 941 if(filename == NULL) 942 fd = 0; 943 else { 944 fd = open(filename, O_RDONLY); 945 if( fd < 0 ) { 946 perror("open"); 947 exit(1); 948 } 949 } 950 951 if( read(fd, &xh, sizeof(xh)) < sizeof(xh) ) { 952 fprintf(stderr, "error reading header\n"); 953 exit(1); 954 } 955 956 printf("magic: 0x%x ", ntohl(xh.magic)); 957 if( ntohl(xh.magic) != XAR_HEADER_MAGIC ) 958 printf("(BAD)\n"); 959 else 960 printf("(OK)\n"); 961 printf("size: %d\n", ntohs(xh.size)); 962 printf("version: %d\n", ntohs(xh.version)); 963 printf("Compressed TOC length: %" PRId64 "\n", xar_ntoh64(xh.toc_length_compressed)); 964 printf("Uncompressed TOC length: %" PRId64 "\n", xar_ntoh64(xh.toc_length_uncompressed)); 965 printf("Checksum algorithm: %d ", ntohl(xh.cksum_alg)); 966 switch( ntohl(xh.cksum_alg) ) { 967 case XAR_CKSUM_NONE: printf("(none)\n"); 968 break; 969 case XAR_CKSUM_SHA1: printf("(SHA1)\n"); 970 break; 971 case XAR_CKSUM_SHA256: printf("(SHA256)\n"); 972 break; 973 case XAR_CKSUM_SHA512: printf("(SHA512)\n"); 974 break; 975 case XAR_CKSUM_MD5: printf("(MD5)\n"); 976 break; 977 default: printf("(unknown)\n"); 978 break; 979 }; 980 981 return 0; 982} 983 984static int32_t err_callback(int32_t sev, int32_t err, xar_errctx_t ctx, void *usrctx) { 985 xar_file_t f; 986 const char *str; 987 int e; 988 989 f = xar_err_get_file(ctx); 990 str = xar_err_get_string(ctx); 991 e = xar_err_get_errno(ctx); 992 993 switch(sev) { 994 case XAR_SEVERITY_DEBUG: 995 case XAR_SEVERITY_INFO: 996 break; 997 case XAR_SEVERITY_WARNING: 998 printf("%s\n", str); 999 break; 1000 case XAR_SEVERITY_NORMAL: 1001 if( (err = XAR_ERR_ARCHIVE_CREATION) && f ) 1002 print_file(f); 1003 break; 1004 case XAR_SEVERITY_NONFATAL: 1005 case XAR_SEVERITY_FATAL: 1006 Err = 2; 1007 printf("Error while "); 1008 if( err == XAR_ERR_ARCHIVE_CREATION ) printf("creating"); 1009 if( err == XAR_ERR_ARCHIVE_EXTRACTION ) printf("extracting"); 1010 printf(" archive"); 1011 if( f ) { 1012 const char *file = xar_get_path(f); 1013 if( file ) printf(":(%s)", file); 1014 free((char *)file); 1015 } 1016 if( str ) printf(": %s", str); 1017 if( err ) printf(" (%s)", strerror(e)); 1018 if( sev == XAR_SEVERITY_NONFATAL ) { 1019 printf(" - ignored"); 1020 printf("\n"); 1021 } else { 1022 printf("\n"); 1023 exit(1); 1024 } 1025 break; 1026 } 1027 return 0; 1028} 1029 1030static void usage(const char *prog) { 1031 fprintf(stderr, "Usage: %s -[ctx][v] -f <archive> ...\n", prog); 1032 fprintf(stderr, "\t-c Creates an archive\n"); 1033 fprintf(stderr, "\t-x Extracts an archive\n"); 1034 fprintf(stderr, "\t-t Lists an archive\n"); 1035 fprintf(stderr, "\t--sign Creates a placeholder signature and saves\n"); 1036 fprintf(stderr, "\t the data to sign to disk. Works with -c or -f, requires\n"); 1037 fprintf(stderr, "\t --sig-size, --leaf-cert-loc and \n"); 1038 fprintf(stderr, "\t --intermediate-cert-loc to be set. Setting\n"); 1039 fprintf(stderr, "\t --data-to-sign and --sig-offset is optional.\n"); 1040 fprintf(stderr, "\t Fails with error code %i if the archive has already\n", E_SIGEXISTS); 1041 fprintf(stderr, "\t been signed.\n"); 1042 fprintf(stderr, "\t--replace-sign Rips out existing signature(s) and makes a new one.\n"); 1043 fprintf(stderr, "\t Same required parameter set as --sign, \n"); 1044 fprintf(stderr, "\t but -f instead of -c.\n"); 1045 fprintf(stderr, "\t--extract-data-to-sign Extracts data to be signed from an\n"); 1046 fprintf(stderr, "\t existing archive. Requires --data-to-sign\n"); 1047 fprintf(stderr, "\t and --sig-offset (and -f) to be set.\n"); 1048 fprintf(stderr, "\t--extract-certs <dir> Extracts all certificates into the\n"); 1049 fprintf(stderr, "\t specified directory, naming them 'cert1', 'cert2' etc.\n"); 1050 fprintf(stderr, "\t Requires -f.\n"); 1051 fprintf(stderr, "\t--inject-sig <filename> After extracting the data to be signed and\n"); 1052 fprintf(stderr, "\t doing the signing externally, injects.\n"); 1053 fprintf(stderr, "\t the signature. Requires -f\n"); 1054 fprintf(stderr, "\t-f <filename> Specifies an archive to operate on [REQUIRED!]\n"); 1055 fprintf(stderr, "\t-v Print filenames as they are archived\n"); 1056 fprintf(stderr, "\t-n name Provides a name for a subdocument\n"); 1057 fprintf(stderr, "\t-s <filename> On extract, specifies the file to extract\n"); 1058 fprintf(stderr, "\t subdocuments to.\n"); 1059 fprintf(stderr, "\t On archival, specifies an xml file to add\n"); 1060 fprintf(stderr, "\t as a subdocument.\n"); 1061 fprintf(stderr, "\t-l On archival, stay on the local device.\n"); 1062 fprintf(stderr, "\t-p On extract, set ownership based on symbolic\n"); 1063 fprintf(stderr, "\t names, if possible.\n"); 1064 fprintf(stderr, "\t-P On extract, set ownership based on uid/gid.\n"); 1065 fprintf(stderr, "\t--toc-cksum Specifies the hashing algorithm to use for\n"); 1066 fprintf(stderr, "\t xml header verification.\n"); 1067 fprintf(stderr, "\t Valid values: none, md5, sha1, sha256, and sha512\n"); 1068 fprintf(stderr, "\t Default: sha1\n"); 1069 fprintf(stderr, "\t--file-cksum Specifies the hashing algorithm to use for\n"); 1070 fprintf(stderr, "\t xml header verification.\n"); 1071 fprintf(stderr, "\t Valid values: none, md5, sha1, sha256, and sha512\n"); 1072 fprintf(stderr, "\t Default: sha1\n"); 1073 fprintf(stderr, "\t--dump-toc=<filename> Has xar dump the xml header into the\n"); 1074 fprintf(stderr, "\t specified file.\n"); 1075 fprintf(stderr, "\t--dump-header Prints out the xar binary header information\n"); 1076 fprintf(stderr, "\t--compression Specifies the compression type to use.\n"); 1077 fprintf(stderr, "\t Valid values: none, gzip, bzip2\n"); 1078 fprintf(stderr, "\t Default: gzip\n"); 1079 fprintf(stderr, "\t--list-subdocs List the subdocuments in the xml header\n"); 1080 fprintf(stderr, "\t--extract-subdoc=name Extracts the specified subdocument\n"); 1081 fprintf(stderr, "\t to a document in cwd named <name>.xml\n"); 1082 fprintf(stderr, "\t--exclude POSIX regular expression of files to \n"); 1083 fprintf(stderr, "\t ignore while archiving.\n"); 1084 fprintf(stderr, "\t--rsize Specifies the size of the buffer used\n"); 1085 fprintf(stderr, "\t for read IO operations in bytes.\n"); 1086 fprintf(stderr, "\t--coalesce-heap When archived files are identical, only store one copy\n"); 1087 fprintf(stderr, "\t This option creates an archive which\n"); 1088 fprintf(stderr, "\t is not streamable\n"); 1089 fprintf(stderr, "\t--link-same Hardlink identical files\n"); 1090 fprintf(stderr, "\t--no-compress POSIX regular expression of files\n"); 1091 fprintf(stderr, "\t not to archive, but not compress.\n"); 1092 fprintf(stderr, "\t--sig-size n Size (in bytes) of the signature placeholder\n"); 1093 fprintf(stderr, "\t to generate.\n"); 1094 fprintf(stderr, "\t--data-to-sign=file Path where to dump the data to be signed.\n"); 1095 fprintf(stderr, "\t--sig-offset=file Path where to dump the signature's offset\n"); 1096 fprintf(stderr, "\t within the xar.\n"); 1097 fprintf(stderr, "\t--leaf-cert-loc=file Location of the leaf certificate\n"); 1098 fprintf(stderr, "\t--intermediate-cert-loc=file Location of the intermediate certificate\n"); 1099 fprintf(stderr, "\t--root-cert-loc=file Location of the root certificate\n"); 1100 fprintf(stderr, "\t--version Print xar's version number\n"); 1101 1102 return; 1103} 1104 1105static void print_version() { 1106 printf("xar %s\n", XAR_VERSION); 1107} 1108 1109int main(int argc, char *argv[]) { 1110 char *filename = NULL; 1111 char *sig_path = NULL; 1112 char *cert_path = NULL; 1113 char command = 0, c; 1114 char **args; 1115 const char *tocfile = NULL; 1116 int arglen, i, err; 1117 xar_t x; 1118 int loptind = 0; 1119 int required_dash_f = 0; /* This release requires us to use -f */ 1120 struct lnode *tmp; 1121 long int longtmp; 1122 struct stat stat_struct; 1123 struct option o[] = { 1124 {"toc-cksum", 1, 0, 1}, 1125 {"file-cksum", 1, 0, 22}, // note out-of-order argument number 1126 {"dump-toc", 1, 0, 'd'}, 1127 {"compression", 1, 0, 2}, 1128 {"list-subdocs", 0, 0, 3}, 1129 {"help", 0, 0, 'h'}, 1130 {"version", 0, 0, 4}, 1131 {"dump-header", 0, 0, 5}, 1132 {"extract-subdoc", 1, 0, 6}, 1133 {"exclude", 1, 0, 7}, 1134 {"rsize", 1, 0, 8}, 1135 {"coalesce-heap", 0, 0, 9}, 1136 {"link-same", 0, 0, 10}, 1137 {"no-compress", 1, 0, 11}, 1138 {"sig-size", 1, 0, 12}, 1139 {"data-to-sign", 1, 0, 13}, 1140 {"sig-offset", 1, 0, 14}, 1141 {"leaf-cert-loc", 1, 0, 15}, 1142 {"intermediate-cert-loc", 1, 0, 16}, 1143 {"extract-data-to-sign", 0, 0, 17}, 1144 {"sign", 0, 0, 18}, 1145 {"replace-sign", 0, 0, 19}, 1146 {"inject-sig", 1, 0, 20}, 1147 {"extract-certs", 1, 0, 21}, 1148 {"root-cert-loc", 1, 0, 23}, 1149 { 0, 0, 0, 0} 1150 }; 1151 1152 if( argc < 2 ) { 1153 usage(argv[0]); 1154 exit(1); 1155 } 1156 1157 while( (c = getopt_long(argc, argv, "xcvtf:hpPln:s:d:v", o, &loptind)) != -1 ) { 1158 switch(c) { 1159 case 1 : if( !optarg ) { 1160 usage(argv[0]); 1161 exit(1); 1162 } 1163 if( (strcmp(optarg, XAR_OPT_VAL_NONE) != 0) && 1164 (strcmp(optarg, XAR_OPT_VAL_SHA1) != 0) && 1165 (strcmp(optarg, XAR_OPT_VAL_SHA256) != 0) && 1166 (strcmp(optarg, XAR_OPT_VAL_SHA512) != 0) && 1167 (strcmp(optarg, XAR_OPT_VAL_MD5) != 0) ) { 1168 usage(argv[0]); 1169 exit(1); 1170 } 1171 Toccksum = optarg; 1172 break; 1173 case 22: if( !optarg ) { 1174 usage(argv[0]); 1175 exit(1); 1176 } 1177 if( (strcmp(optarg, XAR_OPT_VAL_NONE) != 0) && 1178 (strcmp(optarg, XAR_OPT_VAL_SHA1) != 0) && 1179 (strcmp(optarg, XAR_OPT_VAL_SHA256) != 0) && 1180 (strcmp(optarg, XAR_OPT_VAL_SHA512) != 0) && 1181 (strcmp(optarg, XAR_OPT_VAL_MD5) != 0) ) { 1182 usage(argv[0]); 1183 exit(1); 1184 } 1185 Filecksum = optarg; 1186 break; 1187 case 2 : if( !optarg ) { 1188 usage(argv[0]); 1189 exit(1); 1190 } 1191 if( (strcmp(optarg, XAR_OPT_VAL_NONE) != 0) && 1192 (strcmp(optarg, XAR_OPT_VAL_GZIP) != 0) && 1193 (strcmp(optarg, XAR_OPT_VAL_BZIP) != 0) ) { 1194 usage(argv[0]); 1195 exit(1); 1196 } 1197 Compression = optarg; 1198 break; 1199 case 3 : if( command && (command != 3) ) { 1200 fprintf(stderr, "Conflicting commands specified\n"); 1201 exit(1); 1202 } 1203 command = 3; 1204 break; 1205 case 4 : print_version(); 1206 exit(0); 1207 case 'd': 1208 if( !optarg ) { 1209 usage(argv[0]); 1210 exit(1); 1211 } 1212 tocfile = optarg; 1213 command = 'd'; 1214 break; 1215 case 5 : command = 5; 1216 break; 1217 case 6 : 1218 SubdocName = optarg; 1219 asprintf(&Subdoc, "%s.xml", SubdocName); 1220 if( !command ) 1221 command = 6; 1222 break; 1223 case 7 : 1224 tmp = malloc(sizeof(struct lnode)); 1225 tmp->str = optarg; 1226 tmp->next = NULL; 1227 err = regcomp(&tmp->reg, tmp->str, REG_NOSUB); 1228 if( err ) { 1229 char errstr[1024]; 1230 regerror(err, &tmp->reg, errstr, sizeof(errstr)); 1231 printf("Error with regular expression %s: %s\n", tmp->str, errstr); 1232 exit(1); 1233 } 1234 if( Exclude == NULL ) { 1235 Exclude = tmp; 1236 Exclude_Tail = tmp; 1237 } else { 1238 Exclude_Tail->next = tmp; 1239 Exclude_Tail = tmp; 1240 } 1241 break; 1242 case 8 : 1243 if ( !optarg ) { 1244 usage(argv[0]); 1245 exit(1); 1246 } 1247 longtmp = strtol(optarg, NULL, 10); 1248 if( (((longtmp == LONG_MIN) || (longtmp == LONG_MAX)) && (errno == ERANGE)) || (longtmp < 1) ) { 1249 fprintf(stderr, "Invalid rsize value: %s\n", optarg); 1250 exit(5); 1251 } 1252 Rsize = optarg; 1253 break; 1254 case 9 : Coalesce = 1; break; 1255 case 10 : LinkSame = 1; break; 1256 case 11 : 1257 tmp = malloc(sizeof(struct lnode)); 1258 tmp->str = optarg; 1259 tmp->next = NULL; 1260 err = regcomp(&tmp->reg, tmp->str, REG_NOSUB); 1261 if( err ) { 1262 char errstr[1024]; 1263 regerror(err, &tmp->reg, errstr, sizeof(errstr)); 1264 printf("Error with regular expression %s: %s\n", tmp->str, errstr); 1265 exit(1); 1266 } 1267 if( NoCompress == NULL ) { 1268 NoCompress = tmp; 1269 NoCompress_Tail = tmp; 1270 } else { 1271 NoCompress_Tail->next = tmp; 1272 NoCompress_Tail = tmp; 1273 } 1274 break; 1275 case 12 : 1276 if( !optarg ) { 1277 usage(argv[0]); 1278 exit(1); 1279 } 1280 SigSize = strtol(optarg, (char **)NULL, 10); 1281 break; 1282 case 13 : 1283 if( !optarg ) { 1284 usage(argv[0]); 1285 exit(1); 1286 } 1287 DataToSignDumpPath = optarg; 1288 break; 1289 case 14 : 1290 if( !optarg ) { 1291 usage(argv[0]); 1292 exit(1); 1293 } 1294 SigOffsetDumpPath = optarg; 1295 break; 1296 case 15 : 1297 if( !optarg ) { 1298 usage(argv[0]); 1299 exit(1); 1300 } 1301 LeafCertPath = optarg; 1302 break; 1303 case 16 : 1304 if( !optarg ) { 1305 usage(argv[0]); 1306 exit(1); 1307 } 1308 IntermediateCertPath = optarg; 1309 break; 1310 case 17 : // extract-data-to-sign 1311 command = 'e'; 1312 break; 1313 case 18 : // sign 1314 DoSign = 1; 1315 break; 1316 case 19 : // replace-sign 1317 command = 'r'; 1318 break; 1319 case 20 : // inject signature 1320 if( !optarg ) { 1321 usage(argv[0]); 1322 exit(1); 1323 } 1324 sig_path = optarg; 1325 command = 'i'; 1326 break; 1327 case 21 : // extract-certs 1328 if( !optarg ) { 1329 usage(argv[0]); 1330 exit(1); 1331 } 1332 cert_path = optarg; 1333 stat(cert_path, &stat_struct); 1334 if (!(stat_struct.st_mode & S_IFDIR)) { 1335 usage(argv[0]); 1336 fprintf(stderr, "%s is not a directory.\n", cert_path); 1337 exit(1); 1338 } 1339 command = 'j'; 1340 break; 1341 case 23 : 1342 if( !optarg ) { 1343 usage(argv[0]); 1344 exit(1); 1345 } 1346 RootCertPath = optarg; 1347 break; 1348 case 'c': 1349 case 'x': 1350 case 't': 1351 if( command && (command != 's') ) { 1352 usage(argv[0]); 1353 fprintf(stderr, "Conflicting command flags: %c and %c specified\n", c, command); 1354 exit(1); 1355 } 1356 if( c == 't' ) 1357 Verbose++; 1358 command = c; 1359 break; 1360 case 'f': 1361 required_dash_f = 1; 1362 filename = optarg; 1363 break; 1364 case 'p': 1365 Perms = SYMBOLIC; 1366 break; 1367 case 'P': 1368 Perms = NUMERIC; 1369 break; 1370 case 'l': 1371 Local = 1; 1372 break; 1373 case 'n': 1374 SubdocName = optarg; 1375 break; 1376 case 's': 1377 Subdoc = optarg; 1378 if( !command ) 1379 command = 's'; 1380 break; 1381 case 'v': 1382 Verbose++; 1383 break; 1384 case 'h': 1385 default: 1386 usage(argv[0]); 1387 exit(1); 1388 } 1389 } 1390 1391 if (! required_dash_f) { 1392 usage(argv[0]); 1393 fprintf(stderr, "\n -f option is REQUIRED\n"); 1394 exit(1); 1395 } 1396 1397 // extract-data-to-sign 1398 if ( (command == 'e') && ((!filename) || (!DataToSignDumpPath) || (!SigOffsetDumpPath)) ) { 1399 usage(argv[0]); 1400 exit(1); 1401 } 1402 1403 if ( DoSign ) { // XXX: should we require RootCertPath as well? 1404 if ( ( !SigSize || !LeafCertPath || !IntermediateCertPath ) 1405 || ((command != 'c') && (!filename)) ) { 1406 usage(argv[0]); 1407 exit(1); 1408 } 1409 if (!command) 1410 command = 'n'; 1411 } 1412 1413 if (command == 'r') { 1414 /*if ( !SigSize || !LeafCertPath || !IntermediateCertPath || !filename) { 1415 usage(argv[0]); 1416 exit(1); 1417 } 1418 xar_t x = xar_open(filename, READ); 1419 if ( x == NULL ) { 1420 fprintf(stderr, "Could not open archive %s!\n", filename); 1421 exit(1); 1422 } 1423 xar_signature_t sig = xar_signature_first(x); 1424 if ( !sig ) { 1425 fprintf(stderr, "No signature found to replace.\n"); 1426 exit(E_NOSIG); 1427 } 1428 xar_close(x);*/ 1429 } 1430 1431 if ((command == 'i') && ((!filename) || (!sig_path))) { 1432 usage(argv[0]); 1433 exit(1); 1434 } 1435 1436 if ((command == 'j') && (!filename)) { 1437 usage(argv[0]); 1438 exit(1); 1439 } 1440 1441 switch(command) { 1442 case 5 : 1443 return dump_header(filename); 1444 case 3 : 1445 return list_subdocs(filename); 1446 case 'c': 1447 if( optind == argc ) { 1448 usage(argv[0]); 1449 fprintf(stderr, "No files to operate on.\n"); 1450 exit(1); 1451 } 1452 arglen = argc - optind; 1453 args = malloc(sizeof(char*) * (arglen+1)); 1454 memset(args, 0, sizeof(char*) * (arglen+1)); 1455 for( i = 0; i < arglen; i++ ) 1456 args[i] = strdup(argv[optind + i]); 1457 1458 return archive(filename, arglen, args); 1459 case 'd': 1460 if( !tocfile ) { 1461 usage(argv[0]); 1462 exit(1); 1463 } 1464 return dumptoc(filename, tocfile); 1465 case 'x': 1466 arglen = argc - optind; 1467 args = malloc(sizeof(char*) * (arglen+1)); 1468 for( i = 0; i < arglen; i++ ) 1469 args[i] = strdup(argv[optind + i]); 1470 args[i] = NULL; 1471 return extract(filename, arglen, args); 1472 case 't': 1473 arglen = argc - optind; 1474 args = malloc(sizeof(char*) * (arglen+1)); 1475 for( i = 0; i < arglen; i++ ) 1476 args[i] = strdup(argv[optind + i]); 1477 return list(filename, arglen, args); 1478 case 6 : 1479 case 's': 1480 x = xar_open(filename, READ); 1481 if( !x ) { 1482 fprintf(stderr, "Error opening xar archive: %s\n", filename); 1483 exit(1); 1484 } 1485 xar_register_errhandler(x, err_callback, NULL); 1486 extract_subdoc(x, SubdocName); 1487 xar_close(x); 1488 exit(Err); 1489 break; 1490 case 'e': 1491 extract_data_to_sign(filename); 1492 exit(Err); 1493 case 'r': 1494 replace_sign(filename); 1495 exit(Err); 1496 case 'i': 1497 inject_signature(filename, sig_path); 1498 exit(Err); 1499 case 'n': 1500 belated_sign(filename); 1501 exit(Err); 1502 case 'j': 1503 extract_certs(filename, cert_path); 1504 exit(Err); 1505 default: 1506 usage(argv[0]); 1507 fprintf(stderr, "Unrecognized command.\n"); 1508 exit(1); 1509 } 1510 1511 /* unreached */ 1512 exit(0); 1513} 1514