1 /* 2 * Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 #include <sys/types.h> 27 #include <sys/stat.h> 28 #include <fcntl.h> 29 #include <stdio.h> 30 #include <stdlib.h> 31 #include <string.h> 32 #include "jli_util.h" 33 34 #include <zlib.h> 35 #include "manifest_info.h" 36 37 static char *manifest; 38 39 static const char *manifest_name = "META-INF/MANIFEST.MF"; 40 41 /* 42 * Inflate the manifest file (or any file for that matter). 43 * 44 * fd: File descriptor of the jar file. 45 * entry: Contains the information necessary to perform the inflation 46 * (the compressed and uncompressed sizes and the offset in 47 * the file where the compressed data is located). 48 * size_out: Returns the size of the inflated file. 49 * 50 * Upon success, it returns a pointer to a NUL-terminated malloc'd buffer 51 * containing the inflated manifest file. When the caller is done with it, 52 * this buffer should be released by a call to free(). Upon failure, 53 * returns NULL. 54 */ 55 static char * 56 inflate_file(int fd, zentry *entry, int *size_out) 57 { 58 char *in; 59 char *out; 60 z_stream zs; 61 62 if (entry->csize == (size_t) -1 || entry->isize == (size_t) -1 ) 63 return (NULL); 64 if (JLI_Lseek(fd, entry->offset, SEEK_SET) < (jlong)0) 65 return (NULL); 66 if ((in = malloc(entry->csize + 1)) == NULL) 67 return (NULL); 68 if ((size_t)(read(fd, in, (unsigned int)entry->csize)) != entry->csize) { 69 free(in); 70 return (NULL); 71 } 72 if (entry->how == STORED) { 73 *(char *)((size_t)in + entry->csize) = '\0'; 74 if (size_out) { 75 *size_out = (int)entry->csize; 76 } 77 return (in); 78 } else if (entry->how == DEFLATED) { 79 zs.zalloc = (alloc_func)Z_NULL; 80 zs.zfree = (free_func)Z_NULL; 81 zs.opaque = (voidpf)Z_NULL; 82 zs.next_in = (Byte*)in; 83 zs.avail_in = (uInt)entry->csize; 84 if (inflateInit2(&zs, -MAX_WBITS) < 0) { 85 free(in); 86 return (NULL); 87 } 88 if ((out = malloc(entry->isize + 1)) == NULL) { 89 free(in); 90 return (NULL); 91 } 92 zs.next_out = (Byte*)out; 93 zs.avail_out = (uInt)entry->isize; 94 if (inflate(&zs, Z_PARTIAL_FLUSH) < 0) { 95 free(in); 96 free(out); 97 return (NULL); 98 } 99 *(char *)((size_t)out + entry->isize) = '\0'; 100 free(in); 101 if (inflateEnd(&zs) < 0) { 102 free(out); 103 return (NULL); 104 } 105 if (size_out) { 106 *size_out = (int)entry->isize; 107 } 108 return (out); 109 } 110 free(in); 111 return (NULL); 112 } 113 114 static jboolean zip64_present = JNI_FALSE; 115 116 /* 117 * Checks to see if we have ZIP64 archive, and save 118 * the check for later use 119 */ 120 static int 121 haveZIP64(Byte *p) { 122 jlong cenlen, cenoff, centot; 123 cenlen = ENDSIZ(p); 124 cenoff = ENDOFF(p); 125 centot = ENDTOT(p); 126 zip64_present = (cenlen == ZIP64_MAGICVAL || 127 cenoff == ZIP64_MAGICVAL || 128 centot == ZIP64_MAGICCOUNT); 129 return zip64_present; 130 } 131 132 static jlong 133 find_end64(int fd, Byte *ep, jlong pos) 134 { 135 jlong end64pos; 136 jlong bytes; 137 if ((end64pos = JLI_Lseek(fd, pos - ZIP64_LOCHDR, SEEK_SET)) < (jlong)0) 138 return -1; 139 if ((bytes = read(fd, ep, ZIP64_LOCHDR)) < 0) 140 return -1; 141 if (ZIP64_LOCSIG_AT(ep)) 142 return end64pos; 143 return -1; 144 } 145 146 /* 147 * A very little used routine to handle the case that zip file has 148 * a comment at the end. Believe it or not, the only way to find the 149 * END record is to walk backwards, byte by bloody byte looking for 150 * the END record signature. 151 * 152 * fd: File descriptor of the jar file. 153 * eb: Pointer to a buffer to receive a copy of the END header. 154 * 155 * Returns the offset of the END record in the file on success, 156 * -1 on failure. 157 */ 158 static jlong 159 find_end(int fd, Byte *eb) 160 { 161 jlong len; 162 jlong pos; 163 jlong flen; 164 int bytes; 165 Byte *cp; 166 Byte *endpos; 167 Byte *buffer; 168 169 /* 170 * 99.44% (or more) of the time, there will be no comment at the 171 * end of the zip file. Try reading just enough to read the END 172 * record from the end of the file, at this time we should also 173 * check to see if we have a ZIP64 archive. 174 */ 175 if ((pos = JLI_Lseek(fd, -ENDHDR, SEEK_END)) < (jlong)0) 176 return (-1); 177 if ((bytes = read(fd, eb, ENDHDR)) < 0) 178 return (-1); 179 if (ENDSIG_AT(eb)) { 180 return haveZIP64(eb) ? find_end64(fd, eb, pos) : pos; 181 } 182 183 /* 184 * Shucky-Darn,... There is a comment at the end of the zip file. 185 * 186 * Allocate and fill a buffer with enough of the zip file 187 * to meet the specification for a maximal comment length. 188 */ 189 if ((flen = JLI_Lseek(fd, 0, SEEK_END)) < (jlong)0) 190 return (-1); 191 len = (flen < END_MAXLEN) ? flen : END_MAXLEN; 192 if (JLI_Lseek(fd, -len, SEEK_END) < (jlong)0) 193 return (-1); 194 if ((buffer = malloc(END_MAXLEN)) == NULL) 195 return (-1); 196 if ((bytes = read(fd, buffer, len)) < 0) { 197 free(buffer); 198 return (-1); 199 } 200 201 /* 202 * Search backwards from the end of file stopping when the END header 203 * signature is found. 204 */ 205 endpos = &buffer[bytes]; 206 for (cp = &buffer[bytes - ENDHDR]; cp >= &buffer[0]; cp--) 207 if (ENDSIG_AT(cp) && (cp + ENDHDR + ENDCOM(cp) == endpos)) { 208 (void) memcpy(eb, cp, ENDHDR); 209 free(buffer); 210 pos = flen - (endpos - cp); 211 return haveZIP64(eb) ? find_end64(fd, eb, pos) : pos; 212 } 213 free(buffer); 214 return (-1); 215 } 216 217 #define BUFSIZE (3 * 65536 + CENHDR + SIGSIZ) 218 #define MINREAD 1024 219 220 /* 221 * Computes and positions at the start of the CEN header, ie. the central 222 * directory, this will also return the offset if there is a zip file comment 223 * at the end of the archive, for most cases this would be 0. 224 */ 225 static jlong 226 compute_cen(int fd, Byte *bp) 227 { 228 int bytes; 229 Byte *p; 230 jlong base_offset; 231 jlong offset; 232 char buffer[MINREAD]; 233 p = (Byte*) buffer; 234 /* 235 * Read the END Header, which is the starting point for ZIP files. 236 * (Clearly designed to make writing a zip file easier than reading 237 * one. Now isn't that precious...) 238 */ 239 if ((base_offset = find_end(fd, bp)) == -1) { 240 return (-1); 241 } 242 p = bp; 243 /* 244 * There is a historical, but undocumented, ability to allow for 245 * additional "stuff" to be prepended to the zip/jar file. It seems 246 * that this has been used to prepend an actual java launcher 247 * executable to the jar on Windows. Although this is just another 248 * form of statically linking a small piece of the JVM to the 249 * application, we choose to continue to support it. Note that no 250 * guarantees have been made (or should be made) to the customer that 251 * this will continue to work. 252 * 253 * Therefore, calculate the base offset of the zip file (within the 254 * expanded file) by assuming that the central directory is followed 255 * immediately by the end record. 256 */ 257 if (zip64_present) { 258 if ((offset = ZIP64_LOCOFF(p)) < (jlong)0) { 259 return -1; 260 } 261 if (JLI_Lseek(fd, offset, SEEK_SET) < (jlong) 0) { 262 return (-1); 263 } 264 if ((bytes = read(fd, buffer, MINREAD)) < 0) { 265 return (-1); 266 } 267 if (!ZIP64_ENDSIG_AT(buffer)) { 268 return -1; 269 } 270 if ((offset = ZIP64_ENDOFF(buffer)) < (jlong)0) { 271 return -1; 272 } 273 if (JLI_Lseek(fd, offset, SEEK_SET) < (jlong)0) { 274 return (-1); 275 } 276 p = (Byte*) buffer; 277 base_offset = base_offset - ZIP64_ENDSIZ(p) - ZIP64_ENDOFF(p) - ZIP64_ENDHDR; 278 } else { 279 base_offset = base_offset - ENDSIZ(p) - ENDOFF(p); 280 /* 281 * The END Header indicates the start of the Central Directory 282 * Headers. Remember that the desired Central Directory Header (CEN) 283 * will almost always be the second one and the first one is a small 284 * directory entry ("META-INF/"). Keep the code optimized for 285 * that case. 286 * 287 * Seek to the beginning of the Central Directory. 288 */ 289 if (JLI_Lseek(fd, base_offset + ENDOFF(p), SEEK_SET) < (jlong) 0) { 290 return (-1); 291 } 292 } 293 return base_offset; 294 } 295 296 /* 297 * Locate the manifest file with the zip/jar file. 298 * 299 * fd: File descriptor of the jar file. 300 * entry: To be populated with the information necessary to perform 301 * the inflation (the compressed and uncompressed sizes and 302 * the offset in the file where the compressed data is located). 303 * 304 * Returns zero upon success. Returns a negative value upon failure. 305 * 306 * The buffer for reading the Central Directory if the zip/jar file needs 307 * to be large enough to accommodate the largest possible single record 308 * and the signature of the next record which is: 309 * 310 * 3*2**16 + CENHDR + SIGSIZ 311 * 312 * Each of the three variable sized fields (name, comment and extension) 313 * has a maximum possible size of 64k. 314 * 315 * Typically, only a small bit of this buffer is used with bytes shuffled 316 * down to the beginning of the buffer. It is one thing to allocate such 317 * a large buffer and another thing to actually start faulting it in. 318 * 319 * In most cases, all that needs to be read are the first two entries in 320 * a typical jar file (META-INF and META-INF/MANIFEST.MF). Keep this factoid 321 * in mind when optimizing this code. 322 */ 323 static int 324 find_file(int fd, zentry *entry, const char *file_name) 325 { 326 int bytes; 327 int res; 328 int entry_size; 329 int read_size; 330 jlong base_offset; 331 Byte *p; 332 Byte *bp; 333 Byte *buffer; 334 Byte locbuf[LOCHDR]; 335 336 if ((buffer = (Byte*)malloc(BUFSIZE)) == NULL) { 337 return(-1); 338 } 339 340 bp = buffer; 341 base_offset = compute_cen(fd, bp); 342 if (base_offset == -1) { 343 free(buffer); 344 return -1; 345 } 346 347 if ((bytes = read(fd, bp, MINREAD)) < 0) { 348 free(buffer); 349 return (-1); 350 } 351 p = bp; 352 /* 353 * Loop through the Central Directory Headers. Note that a valid zip/jar 354 * must have an ENDHDR (with ENDSIG) after the Central Directory. 355 */ 356 while (CENSIG_AT(p)) { 357 358 /* 359 * If a complete header isn't in the buffer, shift the contents 360 * of the buffer down and refill the buffer. Note that the check 361 * for "bytes < CENHDR" must be made before the test for the entire 362 * size of the header, because if bytes is less than CENHDR, the 363 * actual size of the header can't be determined. The addition of 364 * SIGSIZ guarantees that the next signature is also in the buffer 365 * for proper loop termination. 366 */ 367 if (bytes < CENHDR) { 368 p = memmove(bp, p, bytes); 369 if ((res = read(fd, bp + bytes, MINREAD)) <= 0) { 370 free(buffer); 371 return (-1); 372 } 373 bytes += res; 374 } 375 entry_size = CENHDR + CENNAM(p) + CENEXT(p) + CENCOM(p); 376 if (bytes < entry_size + SIGSIZ) { 377 if (p != bp) 378 p = memmove(bp, p, bytes); 379 read_size = entry_size - bytes + SIGSIZ; 380 read_size = (read_size < MINREAD) ? MINREAD : read_size; 381 if ((res = read(fd, bp + bytes, read_size)) <= 0) { 382 free(buffer); 383 return (-1); 384 } 385 bytes += res; 386 } 387 388 /* 389 * Check if the name is the droid we are looking for; the jar file 390 * manifest. If so, build the entry record from the data found in 391 * the header located and return success. 392 */ 393 if ((size_t)CENNAM(p) == JLI_StrLen(file_name) && 394 memcmp((p + CENHDR), file_name, JLI_StrLen(file_name)) == 0) { 395 if (JLI_Lseek(fd, base_offset + CENOFF(p), SEEK_SET) < (jlong)0) { 396 free(buffer); 397 return (-1); 398 } 399 if (read(fd, locbuf, LOCHDR) < 0) { 400 free(buffer); 401 return (-1); 402 } 403 if (!LOCSIG_AT(locbuf)) { 404 free(buffer); 405 return (-1); 406 } 407 entry->isize = CENLEN(p); 408 entry->csize = CENSIZ(p); 409 entry->offset = base_offset + CENOFF(p) + LOCHDR + 410 LOCNAM(locbuf) + LOCEXT(locbuf); 411 entry->how = CENHOW(p); 412 free(buffer); 413 return (0); 414 } 415 416 /* 417 * Point to the next entry and decrement the count of valid remaining 418 * bytes. 419 */ 420 bytes -= entry_size; 421 p += entry_size; 422 } 423 free(buffer); 424 return (-1); /* Fell off the end the loop without a Manifest */ 425 } 426 427 /* 428 * Parse a Manifest file header entry into a distinct "name" and "value". 429 * Continuation lines are joined into a single "value". The documented 430 * syntax for a header entry is: 431 * 432 * header: name ":" value 433 * 434 * name: alphanum *headerchar 435 * 436 * value: SPACE *otherchar newline *continuation 437 * 438 * continuation: SPACE *otherchar newline 439 * 440 * newline: CR LF | LF | CR (not followed by LF) 441 * 442 * alphanum: {"A"-"Z"} | {"a"-"z"} | {"0"-"9"} 443 * 444 * headerchar: alphanum | "-" | "_" 445 * 446 * otherchar: any UTF-8 character except NUL, CR and LF 447 * 448 * Note that a manifest file may be composed of multiple sections, 449 * each of which may contain multiple headers. 450 * 451 * section: *header +newline 452 * 453 * nonempty-section: +header +newline 454 * 455 * (Note that the point of "nonempty-section" is unclear, because it isn't 456 * referenced elsewhere in the full specification for the Manifest file.) 457 * 458 * Arguments: 459 * lp pointer to a character pointer which points to the start 460 * of a valid header. 461 * name pointer to a character pointer which will be set to point 462 * to the name portion of the header (nul terminated). 463 * value pointer to a character pointer which will be set to point 464 * to the value portion of the header (nul terminated). 465 * 466 * Returns: 467 * 1 Successful parsing of an NV pair. lp is updated to point to the 468 * next character after the terminating newline in the string 469 * representing the Manifest file. name and value are updated to 470 * point to the strings parsed. 471 * 0 A valid end of section indicator was encountered. lp, name, and 472 * value are not modified. 473 * -1 lp does not point to a valid header. Upon return, the values of 474 * lp, name, and value are undefined. 475 */ 476 static int 477 parse_nv_pair(char **lp, char **name, char **value) 478 { 479 char *nl; 480 char *cp; 481 482 /* 483 * End of the section - return 0. The end of section condition is 484 * indicated by either encountering a blank line or the end of the 485 * Manifest "string" (EOF). 486 */ 487 if (**lp == '\0' || **lp == '\n' || **lp == '\r') 488 return (0); 489 490 /* 491 * Getting to here, indicates that *lp points to an "otherchar". 492 * Turn the "header" into a string on its own. 493 */ 494 nl = JLI_StrPBrk(*lp, "\n\r"); 495 if (nl == NULL) { 496 nl = JLI_StrChr(*lp, (int)'\0'); 497 } else { 498 cp = nl; /* For merging continuation lines */ 499 if (*nl == '\r' && *(nl+1) == '\n') 500 *nl++ = '\0'; 501 *nl++ = '\0'; 502 503 /* 504 * Process any "continuation" line(s), by making them part of the 505 * "header" line. Yes, I know that we are "undoing" the NULs we 506 * just placed here, but continuation lines are the fairly rare 507 * case, so we shouldn't unnecessarily complicate the code above. 508 * 509 * Note that an entire continuation line is processed each iteration 510 * through the outer while loop. 511 */ 512 while (*nl == ' ') { 513 nl++; /* First character to be moved */ 514 while (*nl != '\n' && *nl != '\r' && *nl != '\0') 515 *cp++ = *nl++; /* Shift string */ 516 if (*nl == '\0') 517 return (-1); /* Error: newline required */ 518 *cp = '\0'; 519 if (*nl == '\r' && *(nl+1) == '\n') 520 *nl++ = '\0'; 521 *nl++ = '\0'; 522 } 523 } 524 525 /* 526 * Separate the name from the value; 527 */ 528 cp = JLI_StrChr(*lp, (int)':'); 529 if (cp == NULL) 530 return (-1); 531 *cp++ = '\0'; /* The colon terminates the name */ 532 if (*cp != ' ') 533 return (-1); 534 *cp++ = '\0'; /* Eat the required space */ 535 *name = *lp; 536 *value = cp; 537 *lp = nl; 538 return (1); 539 } 540 541 /* 542 * Read the manifest from the specified jar file and fill in the manifest_info 543 * structure with the information found within. 544 * 545 * Error returns are as follows: 546 * 0 Success 547 * -1 Unable to open jarfile 548 * -2 Error accessing the manifest from within the jarfile (most likely 549 * a manifest is not present, or this isn't a valid zip/jar file). 550 */ 551 int 552 JLI_ParseManifest(char *jarfile, manifest_info *info) 553 { 554 int fd; 555 zentry entry; 556 char *lp; 557 char *name; 558 char *value; 559 int rc; 560 char *splashscreen_name = NULL; 561 562 if ((fd = open(jarfile, O_RDONLY 563 #ifdef O_LARGEFILE 564 | O_LARGEFILE /* large file mode */ 565 #endif 566 #ifdef O_BINARY 567 | O_BINARY /* use binary mode on windows */ 568 #endif 569 )) == -1) { 570 return (-1); 571 } 572 info->manifest_version = NULL; 573 info->main_class = NULL; 574 info->jre_version = NULL; 575 info->jre_restrict_search = 0; 576 info->splashscreen_image_file_name = NULL; 577 if (rc = find_file(fd, &entry, manifest_name) != 0) { 578 close(fd); 579 return (-2); 580 } 581 manifest = inflate_file(fd, &entry, NULL); 582 if (manifest == NULL) { 583 close(fd); 584 return (-2); 585 } 586 lp = manifest; 587 while ((rc = parse_nv_pair(&lp, &name, &value)) > 0) { 588 if (JLI_StrCaseCmp(name, "Manifest-Version") == 0) { 589 info->manifest_version = value; 590 } else if (JLI_StrCaseCmp(name, "Main-Class") == 0) { 591 info->main_class = value; 592 } else if (JLI_StrCaseCmp(name, "JRE-Version") == 0) { 593 /* 594 * Manifest specification overridden by command line option 595 * so we will silently override there with no specification. 596 */ 597 info->jre_version = 0; 598 } else if (JLI_StrCaseCmp(name, "Splashscreen-Image") == 0) { 599 info->splashscreen_image_file_name = value; 600 } 601 } 602 close(fd); 603 if (rc == 0) 604 return (0); 605 else 606 return (-2); 607 } 608 609 /* 610 * Opens the jar file and unpacks the specified file from its contents. 611 * Returns NULL on failure. 612 */ 613 void * 614 JLI_JarUnpackFile(const char *jarfile, const char *filename, int *size) { 615 int fd; 616 zentry entry; 617 void *data = NULL; 618 619 if ((fd = open(jarfile, O_RDONLY 620 #ifdef O_LARGEFILE 621 | O_LARGEFILE /* large file mode */ 622 #endif 623 #ifdef O_BINARY 624 | O_BINARY /* use binary mode on windows */ 625 #endif 626 )) == -1) { 627 return NULL; 628 } 629 if (find_file(fd, &entry, filename) == 0) { 630 data = inflate_file(fd, &entry, size); 631 } 632 close(fd); 633 return (data); 634 } 635 636 /* 637 * Specialized "free" function. 638 */ 639 void 640 JLI_FreeManifest() 641 { 642 if (manifest) 643 free(manifest); 644 } 645 646 /* 647 * Iterate over the manifest of the specified jar file and invoke the provided 648 * closure function for each attribute encountered. 649 * 650 * Error returns are as follows: 651 * 0 Success 652 * -1 Unable to open jarfile 653 * -2 Error accessing the manifest from within the jarfile (most likely 654 * this means a manifest is not present, or it isn't a valid zip/jar file). 655 */ 656 int 657 JLI_ManifestIterate(const char *jarfile, attribute_closure ac, void *user_data) 658 { 659 int fd; 660 zentry entry; 661 char *mp; /* manifest pointer */ 662 char *lp; /* pointer into manifest, updated during iteration */ 663 char *name; 664 char *value; 665 int rc; 666 667 if ((fd = open(jarfile, O_RDONLY 668 #ifdef O_LARGEFILE 669 | O_LARGEFILE /* large file mode */ 670 #endif 671 #ifdef O_BINARY 672 | O_BINARY /* use binary mode on windows */ 673 #endif 674 )) == -1) { 675 return (-1); 676 } 677 678 if (rc = find_file(fd, &entry, manifest_name) != 0) { 679 close(fd); 680 return (-2); 681 } 682 683 mp = inflate_file(fd, &entry, NULL); 684 if (mp == NULL) { 685 close(fd); 686 return (-2); 687 } 688 689 lp = mp; 690 while ((rc = parse_nv_pair(&lp, &name, &value)) > 0) { 691 (*ac)(name, value, user_data); 692 } 693 free(mp); 694 close(fd); 695 return (rc == 0) ? 0 : -2; 696 }