1 /*************************************************************************** 2 * _ _ ____ _ 3 * Project ___| | | | _ \| | 4 * / __| | | | |_) | | 5 * | (__| |_| | _ <| |___ 6 * \___|\___/|_| \_\_____| 7 * 8 * Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel (at) haxx.se>, et al. 9 * 10 * This software is licensed as described in the file COPYING, which 11 * you should have received as part of this distribution. The terms 12 * are also available at https://curl.haxx.se/docs/copyright.html. 13 * 14 * You may opt to use, copy, modify, merge, publish, distribute and/or sell 15 * copies of the Software, and permit persons to whom the Software is 16 * furnished to do so, under the terms of the COPYING file. 17 * 18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 19 * KIND, either express or implied. 20 * 21 ***************************************************************************/ 22 #include "tool_setup.h" 23 24 #ifdef USE_METALINK 25 26 #include <sys/stat.h> 27 #include <stdlib.h> 28 29 #ifdef HAVE_FCNTL_H 30 # include <fcntl.h> 31 #endif 32 33 #undef HAVE_NSS_CONTEXT 34 35 #ifdef USE_OPENSSL 36 # include <openssl/md5.h> 37 # include <openssl/sha.h> 38 #elif defined(USE_GNUTLS_NETTLE) 39 # include <nettle/md5.h> 40 # include <nettle/sha.h> 41 # define MD5_CTX struct md5_ctx 42 # define SHA_CTX struct sha1_ctx 43 # define SHA256_CTX struct sha256_ctx 44 #elif defined(USE_GNUTLS) 45 # include <gcrypt.h> 46 # define MD5_CTX gcry_md_hd_t 47 # define SHA_CTX gcry_md_hd_t 48 # define SHA256_CTX gcry_md_hd_t 49 #elif defined(USE_NSS) 50 # include <nss.h> 51 # include <pk11pub.h> 52 # define MD5_CTX void * 53 # define SHA_CTX void * 54 # define SHA256_CTX void * 55 # define HAVE_NSS_CONTEXT 56 static NSSInitContext *nss_context; 57 #elif defined(USE_POLARSSL) 58 # include <polarssl/md5.h> 59 # include <polarssl/sha1.h> 60 # include <polarssl/sha256.h> 61 # define MD5_CTX md5_context 62 # define SHA_CTX sha1_context 63 # define SHA256_CTX sha256_context 64 #elif (defined(__MAC_OS_X_VERSION_MAX_ALLOWED) && \ 65 (__MAC_OS_X_VERSION_MAX_ALLOWED >= 1040)) || \ 66 (defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && \ 67 (__IPHONE_OS_VERSION_MAX_ALLOWED >= 20000)) 68 /* For Apple operating systems: CommonCrypto has the functions we need. 69 The library's headers are even backward-compatible with OpenSSL's 70 headers as long as we define COMMON_DIGEST_FOR_OPENSSL first. 71 72 These functions are available on Tiger and later, as well as iOS 2.0 73 and later. If you're building for an older cat, well, sorry. */ 74 # define COMMON_DIGEST_FOR_OPENSSL 75 # include <CommonCrypto/CommonDigest.h> 76 #elif defined(_WIN32) 77 /* For Windows: If no other crypto library is provided, we fallback 78 to the hash functions provided within the Microsoft Windows CryptoAPI */ 79 # include <wincrypt.h> 80 /* Custom structure in order to store the required provider and hash handle */ 81 struct win32_crypto_hash { 82 HCRYPTPROV hCryptProv; 83 HCRYPTHASH hHash; 84 }; 85 /* Custom Microsoft AES Cryptographic Provider defines required for MinGW */ 86 # ifndef ALG_SID_SHA_256 87 # define ALG_SID_SHA_256 12 88 # endif 89 # ifndef CALG_SHA_256 90 # define CALG_SHA_256 (ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_SHA_256) 91 # endif 92 # define MD5_CTX struct win32_crypto_hash 93 # define SHA_CTX struct win32_crypto_hash 94 # define SHA256_CTX struct win32_crypto_hash 95 #else 96 # error "Can't compile METALINK support without a crypto library." 97 #endif 98 99 #define ENABLE_CURLX_PRINTF 100 /* use our own printf() functions */ 101 #include "curlx.h" 102 103 #include "tool_getparam.h" 104 #include "tool_paramhlp.h" 105 #include "tool_cfgable.h" 106 #include "tool_metalink.h" 107 #include "tool_msgs.h" 108 109 #include "memdebug.h" /* keep this as LAST include */ 110 111 /* Copied from tool_getparam.c */ 112 #define GetStr(str,val) do { \ 113 if(*(str)) { \ 114 free(*(str)); \ 115 *(str) = NULL; \ 116 } \ 117 if((val)) \ 118 *(str) = strdup((val)); \ 119 if(!(val)) \ 120 return PARAM_NO_MEM; \ 121 } WHILE_FALSE 122 123 #if defined(USE_OPENSSL) 124 /* Functions are already defined */ 125 #elif defined(USE_GNUTLS_NETTLE) 126 127 static int MD5_Init(MD5_CTX *ctx) 128 { 129 md5_init(ctx); 130 return 1; 131 } 132 133 static void MD5_Update(MD5_CTX *ctx, 134 const unsigned char *input, 135 unsigned int inputLen) 136 { 137 md5_update(ctx, inputLen, input); 138 } 139 140 static void MD5_Final(unsigned char digest[16], MD5_CTX *ctx) 141 { 142 md5_digest(ctx, 16, digest); 143 } 144 145 static int SHA1_Init(SHA_CTX *ctx) 146 { 147 sha1_init(ctx); 148 return 1; 149 } 150 151 static void SHA1_Update(SHA_CTX *ctx, 152 const unsigned char *input, 153 unsigned int inputLen) 154 { 155 sha1_update(ctx, inputLen, input); 156 } 157 158 static void SHA1_Final(unsigned char digest[20], SHA_CTX *ctx) 159 { 160 sha1_digest(ctx, 20, digest); 161 } 162 163 static int SHA256_Init(SHA256_CTX *ctx) 164 { 165 sha256_init(ctx); 166 return 1; 167 } 168 169 static void SHA256_Update(SHA256_CTX *ctx, 170 const unsigned char *input, 171 unsigned int inputLen) 172 { 173 sha256_update(ctx, inputLen, input); 174 } 175 176 static void SHA256_Final(unsigned char digest[32], SHA256_CTX *ctx) 177 { 178 sha256_digest(ctx, 32, digest); 179 } 180 181 #elif defined(USE_GNUTLS) 182 183 static int MD5_Init(MD5_CTX *ctx) 184 { 185 gcry_md_open(ctx, GCRY_MD_MD5, 0); 186 return 1; 187 } 188 189 static void MD5_Update(MD5_CTX *ctx, 190 const unsigned char *input, 191 unsigned int inputLen) 192 { 193 gcry_md_write(*ctx, input, inputLen); 194 } 195 196 static void MD5_Final(unsigned char digest[16], MD5_CTX *ctx) 197 { 198 memcpy(digest, gcry_md_read(*ctx, 0), 16); 199 gcry_md_close(*ctx); 200 } 201 202 static int SHA1_Init(SHA_CTX *ctx) 203 { 204 gcry_md_open(ctx, GCRY_MD_SHA1, 0); 205 return 1; 206 } 207 208 static void SHA1_Update(SHA_CTX *ctx, 209 const unsigned char *input, 210 unsigned int inputLen) 211 { 212 gcry_md_write(*ctx, input, inputLen); 213 } 214 215 static void SHA1_Final(unsigned char digest[20], SHA_CTX *ctx) 216 { 217 memcpy(digest, gcry_md_read(*ctx, 0), 20); 218 gcry_md_close(*ctx); 219 } 220 221 static int SHA256_Init(SHA256_CTX *ctx) 222 { 223 gcry_md_open(ctx, GCRY_MD_SHA256, 0); 224 return 1; 225 } 226 227 static void SHA256_Update(SHA256_CTX *ctx, 228 const unsigned char *input, 229 unsigned int inputLen) 230 { 231 gcry_md_write(*ctx, input, inputLen); 232 } 233 234 static void SHA256_Final(unsigned char digest[32], SHA256_CTX *ctx) 235 { 236 memcpy(digest, gcry_md_read(*ctx, 0), 32); 237 gcry_md_close(*ctx); 238 } 239 240 #elif defined(USE_NSS) 241 242 static int nss_hash_init(void **pctx, SECOidTag hash_alg) 243 { 244 PK11Context *ctx; 245 246 /* we have to initialize NSS if not initialized already */ 247 if(!NSS_IsInitialized() && !nss_context) { 248 static NSSInitParameters params; 249 params.length = sizeof(params); 250 nss_context = NSS_InitContext("", "", "", "", ¶ms, NSS_INIT_READONLY 251 | NSS_INIT_NOCERTDB | NSS_INIT_NOMODDB | NSS_INIT_FORCEOPEN 252 | NSS_INIT_NOROOTINIT | NSS_INIT_OPTIMIZESPACE | NSS_INIT_PK11RELOAD); 253 } 254 255 ctx = PK11_CreateDigestContext(hash_alg); 256 if(!ctx) 257 return /* failure */ 0; 258 259 if(PK11_DigestBegin(ctx) != SECSuccess) { 260 PK11_DestroyContext(ctx, PR_TRUE); 261 return /* failure */ 0; 262 } 263 264 *pctx = ctx; 265 return /* success */ 1; 266 } 267 268 static void nss_hash_final(void **pctx, unsigned char *out, unsigned int len) 269 { 270 PK11Context *ctx = *pctx; 271 unsigned int outlen; 272 PK11_DigestFinal(ctx, out, &outlen, len); 273 PK11_DestroyContext(ctx, PR_TRUE); 274 } 275 276 static int MD5_Init(MD5_CTX *pctx) 277 { 278 return nss_hash_init(pctx, SEC_OID_MD5); 279 } 280 281 static void MD5_Update(MD5_CTX *pctx, 282 const unsigned char *input, 283 unsigned int input_len) 284 { 285 PK11_DigestOp(*pctx, input, input_len); 286 } 287 288 static void MD5_Final(unsigned char digest[16], MD5_CTX *pctx) 289 { 290 nss_hash_final(pctx, digest, 16); 291 } 292 293 static int SHA1_Init(SHA_CTX *pctx) 294 { 295 return nss_hash_init(pctx, SEC_OID_SHA1); 296 } 297 298 static void SHA1_Update(SHA_CTX *pctx, 299 const unsigned char *input, 300 unsigned int input_len) 301 { 302 PK11_DigestOp(*pctx, input, input_len); 303 } 304 305 static void SHA1_Final(unsigned char digest[20], SHA_CTX *pctx) 306 { 307 nss_hash_final(pctx, digest, 20); 308 } 309 310 static int SHA256_Init(SHA256_CTX *pctx) 311 { 312 return nss_hash_init(pctx, SEC_OID_SHA256); 313 } 314 315 static void SHA256_Update(SHA256_CTX *pctx, 316 const unsigned char *input, 317 unsigned int input_len) 318 { 319 PK11_DigestOp(*pctx, input, input_len); 320 } 321 322 static void SHA256_Final(unsigned char digest[32], SHA256_CTX *pctx) 323 { 324 nss_hash_final(pctx, digest, 32); 325 } 326 327 #elif defined(USE_POLARSSL) 328 329 static int MD5_Init(MD5_CTX *ctx) 330 { 331 md5_starts(ctx); 332 return 1; 333 } 334 335 static void MD5_Update(MD5_CTX *ctx, 336 const unsigned char *input, 337 unsigned int inputLen) 338 { 339 md5_update(ctx, input, inputLen); 340 } 341 342 static void MD5_Final(unsigned char digest[16], MD5_CTX *ctx) 343 { 344 md5_finish(ctx, digest); 345 } 346 347 static int SHA1_Init(SHA_CTX *ctx) 348 { 349 sha1_starts(ctx); 350 return 1; 351 } 352 353 static void SHA1_Update(SHA_CTX *ctx, 354 const unsigned char *input, 355 unsigned int inputLen) 356 { 357 sha1_update(ctx, input, inputLen); 358 } 359 360 static void SHA1_Final(unsigned char digest[20], SHA_CTX *ctx) 361 { 362 sha1_finish(ctx, digest); 363 } 364 365 static int SHA256_Init(SHA256_CTX *ctx) 366 { 367 sha256_starts(ctx, 0); /* 0 = sha256 */ 368 return 1; 369 } 370 371 static void SHA256_Update(SHA256_CTX *ctx, 372 const unsigned char *input, 373 unsigned int inputLen) 374 { 375 sha256_update(ctx, input, inputLen); 376 } 377 378 static void SHA256_Final(unsigned char digest[32], SHA256_CTX *ctx) 379 { 380 sha256_finish(ctx, digest); 381 } 382 383 #elif defined(_WIN32) 384 385 static void win32_crypto_final(struct win32_crypto_hash *ctx, 386 unsigned char *digest, 387 unsigned int digestLen) 388 { 389 unsigned long length; 390 CryptGetHashParam(ctx->hHash, HP_HASHVAL, NULL, &length, 0); 391 if(length == digestLen) 392 CryptGetHashParam(ctx->hHash, HP_HASHVAL, digest, &length, 0); 393 if(ctx->hHash) 394 CryptDestroyHash(ctx->hHash); 395 if(ctx->hCryptProv) 396 CryptReleaseContext(ctx->hCryptProv, 0); 397 } 398 399 static int MD5_Init(MD5_CTX *ctx) 400 { 401 if(CryptAcquireContext(&ctx->hCryptProv, NULL, NULL, 402 PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) { 403 CryptCreateHash(ctx->hCryptProv, CALG_MD5, 0, 0, &ctx->hHash); 404 } 405 return 1; 406 } 407 408 static void MD5_Update(MD5_CTX *ctx, 409 const unsigned char *input, 410 unsigned int inputLen) 411 { 412 CryptHashData(ctx->hHash, (unsigned char *)input, inputLen, 0); 413 } 414 415 static void MD5_Final(unsigned char digest[16], MD5_CTX *ctx) 416 { 417 win32_crypto_final(ctx, digest, 16); 418 } 419 420 static int SHA1_Init(SHA_CTX *ctx) 421 { 422 if(CryptAcquireContext(&ctx->hCryptProv, NULL, NULL, 423 PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) { 424 CryptCreateHash(ctx->hCryptProv, CALG_SHA1, 0, 0, &ctx->hHash); 425 } 426 return 1; 427 } 428 429 static void SHA1_Update(SHA_CTX *ctx, 430 const unsigned char *input, 431 unsigned int inputLen) 432 { 433 CryptHashData(ctx->hHash, (unsigned char *)input, inputLen, 0); 434 } 435 436 static void SHA1_Final(unsigned char digest[20], SHA_CTX *ctx) 437 { 438 win32_crypto_final(ctx, digest, 20); 439 } 440 441 static int SHA256_Init(SHA256_CTX *ctx) 442 { 443 if(CryptAcquireContext(&ctx->hCryptProv, NULL, NULL, 444 PROV_RSA_AES, CRYPT_VERIFYCONTEXT)) { 445 CryptCreateHash(ctx->hCryptProv, CALG_SHA_256, 0, 0, &ctx->hHash); 446 } 447 return 1; 448 } 449 450 static void SHA256_Update(SHA256_CTX *ctx, 451 const unsigned char *input, 452 unsigned int inputLen) 453 { 454 CryptHashData(ctx->hHash, (unsigned char *)input, inputLen, 0); 455 } 456 457 static void SHA256_Final(unsigned char digest[32], SHA256_CTX *ctx) 458 { 459 win32_crypto_final(ctx, digest, 32); 460 } 461 462 #endif /* CRYPTO LIBS */ 463 464 const digest_params MD5_DIGEST_PARAMS[] = { 465 { 466 CURLX_FUNCTION_CAST(Curl_digest_init_func, MD5_Init), 467 CURLX_FUNCTION_CAST(Curl_digest_update_func, MD5_Update), 468 CURLX_FUNCTION_CAST(Curl_digest_final_func, MD5_Final), 469 sizeof(MD5_CTX), 470 16 471 } 472 }; 473 474 const digest_params SHA1_DIGEST_PARAMS[] = { 475 { 476 CURLX_FUNCTION_CAST(Curl_digest_init_func, SHA1_Init), 477 CURLX_FUNCTION_CAST(Curl_digest_update_func, SHA1_Update), 478 CURLX_FUNCTION_CAST(Curl_digest_final_func, SHA1_Final), 479 sizeof(SHA_CTX), 480 20 481 } 482 }; 483 484 const digest_params SHA256_DIGEST_PARAMS[] = { 485 { 486 CURLX_FUNCTION_CAST(Curl_digest_init_func, SHA256_Init), 487 CURLX_FUNCTION_CAST(Curl_digest_update_func, SHA256_Update), 488 CURLX_FUNCTION_CAST(Curl_digest_final_func, SHA256_Final), 489 sizeof(SHA256_CTX), 490 32 491 } 492 }; 493 494 static const metalink_digest_def SHA256_DIGEST_DEF[] = { 495 {"sha-256", SHA256_DIGEST_PARAMS} 496 }; 497 498 static const metalink_digest_def SHA1_DIGEST_DEF[] = { 499 {"sha-1", SHA1_DIGEST_PARAMS} 500 }; 501 502 static const metalink_digest_def MD5_DIGEST_DEF[] = { 503 {"md5", MD5_DIGEST_PARAMS} 504 }; 505 506 /* 507 * The alias of supported hash functions in the order by preference 508 * (basically stronger hash comes first). We included "sha-256" and 509 * "sha256". The former is the name defined in the IANA registry named 510 * "Hash Function Textual Names". The latter is widely (and 511 * historically) used in Metalink version 3. 512 */ 513 static const metalink_digest_alias digest_aliases[] = { 514 {"sha-256", SHA256_DIGEST_DEF}, 515 {"sha256", SHA256_DIGEST_DEF}, 516 {"sha-1", SHA1_DIGEST_DEF}, 517 {"sha1", SHA1_DIGEST_DEF}, 518 {"md5", MD5_DIGEST_DEF}, 519 {NULL, NULL} 520 }; 521 522 digest_context *Curl_digest_init(const digest_params *dparams) 523 { 524 digest_context *ctxt; 525 526 /* Create digest context */ 527 ctxt = malloc(sizeof(*ctxt)); 528 529 if(!ctxt) 530 return ctxt; 531 532 ctxt->digest_hashctx = malloc(dparams->digest_ctxtsize); 533 534 if(!ctxt->digest_hashctx) { 535 free(ctxt); 536 return NULL; 537 } 538 539 ctxt->digest_hash = dparams; 540 541 if(dparams->digest_init(ctxt->digest_hashctx) != 1) { 542 free(ctxt->digest_hashctx); 543 free(ctxt); 544 return NULL; 545 } 546 547 return ctxt; 548 } 549 550 int Curl_digest_update(digest_context *context, 551 const unsigned char *data, 552 unsigned int len) 553 { 554 (*context->digest_hash->digest_update)(context->digest_hashctx, data, len); 555 556 return 0; 557 } 558 559 int Curl_digest_final(digest_context *context, unsigned char *result) 560 { 561 if(result) 562 (*context->digest_hash->digest_final)(result, context->digest_hashctx); 563 564 free(context->digest_hashctx); 565 free(context); 566 567 return 0; 568 } 569 570 static unsigned char hex_to_uint(const char *s) 571 { 572 char buf[3]; 573 unsigned long val; 574 buf[0] = s[0]; 575 buf[1] = s[1]; 576 buf[2] = 0; 577 val = strtoul(buf, NULL, 16); 578 return (unsigned char)(val&0xff); 579 } 580 581 /* 582 * Check checksum of file denoted by filename. The expected hash value 583 * is given in hex_hash which is hex-encoded string. 584 * 585 * This function returns 1 if it succeeds or one of the following 586 * integers: 587 * 588 * 0: 589 * Checksum didn't match. 590 * -1: 591 * Could not open file; or could not read data from file. 592 * -2: 593 * Hash algorithm not available. 594 */ 595 static int check_hash(const char *filename, 596 const metalink_digest_def *digest_def, 597 const unsigned char *digest, FILE *error) 598 { 599 unsigned char *result; 600 digest_context *dctx; 601 int check_ok, flags, fd; 602 603 flags = O_RDONLY; 604 #ifdef O_BINARY 605 /* O_BINARY is required in order to avoid binary EOF in text mode */ 606 flags |= O_BINARY; 607 #endif 608 609 fd = open(filename, flags); 610 if(fd == -1) { 611 fprintf(error, "Metalink: validating (%s) [%s] FAILED (%s)\n", filename, 612 digest_def->hash_name, strerror(errno)); 613 return -1; 614 } 615 616 dctx = Curl_digest_init(digest_def->dparams); 617 if(!dctx) { 618 fprintf(error, "Metalink: validating (%s) [%s] FAILED (%s)\n", filename, 619 digest_def->hash_name, "failed to initialize hash algorithm"); 620 close(fd); 621 return -2; 622 } 623 624 result = malloc(digest_def->dparams->digest_resultlen); 625 if(!result) { 626 close(fd); 627 Curl_digest_final(dctx, NULL); 628 return -1; 629 } 630 while(1) { 631 unsigned char buf[4096]; 632 ssize_t len = read(fd, buf, sizeof(buf)); 633 if(len == 0) { 634 break; 635 } 636 else if(len == -1) { 637 fprintf(error, "Metalink: validating (%s) [%s] FAILED (%s)\n", filename, 638 digest_def->hash_name, strerror(errno)); 639 Curl_digest_final(dctx, result); 640 close(fd); 641 return -1; 642 } 643 Curl_digest_update(dctx, buf, (unsigned int)len); 644 } 645 Curl_digest_final(dctx, result); 646 check_ok = memcmp(result, digest, 647 digest_def->dparams->digest_resultlen) == 0; 648 /* sha*sum style verdict output */ 649 if(check_ok) 650 fprintf(error, "Metalink: validating (%s) [%s] OK\n", filename, 651 digest_def->hash_name); 652 else 653 fprintf(error, "Metalink: validating (%s) [%s] FAILED (digest mismatch)\n", 654 filename, digest_def->hash_name); 655 656 free(result); 657 close(fd); 658 return check_ok; 659 } 660 661 int metalink_check_hash(struct GlobalConfig *config, 662 metalinkfile *mlfile, 663 const char *filename) 664 { 665 int rv; 666 fprintf(config->errors, "Metalink: validating (%s)...\n", filename); 667 if(mlfile->checksum == NULL) { 668 fprintf(config->errors, 669 "Metalink: validating (%s) FAILED (digest missing)\n", filename); 670 return -2; 671 } 672 rv = check_hash(filename, mlfile->checksum->digest_def, 673 mlfile->checksum->digest, config->errors); 674 return rv; 675 } 676 677 static metalink_checksum *new_metalink_checksum_from_hex_digest 678 (const metalink_digest_def *digest_def, const char *hex_digest) 679 { 680 metalink_checksum *chksum; 681 unsigned char *digest; 682 size_t i; 683 size_t len = strlen(hex_digest); 684 digest = malloc(len/2); 685 if(!digest) 686 return 0; 687 688 for(i = 0; i < len; i += 2) { 689 digest[i/2] = hex_to_uint(hex_digest + i); 690 } 691 chksum = malloc(sizeof(metalink_checksum)); 692 if(chksum) { 693 chksum->digest_def = digest_def; 694 chksum->digest = digest; 695 } 696 else 697 free(digest); 698 return chksum; 699 } 700 701 static metalink_resource *new_metalink_resource(const char *url) 702 { 703 metalink_resource *res; 704 res = malloc(sizeof(metalink_resource)); 705 if(res) { 706 res->next = NULL; 707 res->url = strdup(url); 708 if(!res->url) { 709 free(res); 710 return NULL; 711 } 712 } 713 return res; 714 } 715 716 /* Returns nonzero if hex_digest is properly formatted; that is each 717 letter is in [0-9A-Za-z] and the length of the string equals to the 718 result length of digest * 2. */ 719 static int check_hex_digest(const char *hex_digest, 720 const metalink_digest_def *digest_def) 721 { 722 size_t i; 723 for(i = 0; hex_digest[i]; ++i) { 724 char c = hex_digest[i]; 725 if(!(('0' <= c && c <= '9') || ('a' <= c && c <= 'z') || 726 ('A' <= c && c <= 'Z'))) { 727 return 0; 728 } 729 } 730 return digest_def->dparams->digest_resultlen * 2 == i; 731 } 732 733 static metalinkfile *new_metalinkfile(metalink_file_t *fileinfo) 734 { 735 metalinkfile *f; 736 f = (metalinkfile*)malloc(sizeof(metalinkfile)); 737 if(!f) 738 return NULL; 739 740 f->next = NULL; 741 f->filename = strdup(fileinfo->name); 742 if(!f->filename) { 743 free(f); 744 return NULL; 745 } 746 f->checksum = NULL; 747 f->resource = NULL; 748 if(fileinfo->checksums) { 749 const metalink_digest_alias *digest_alias; 750 for(digest_alias = digest_aliases; digest_alias->alias_name; 751 ++digest_alias) { 752 metalink_checksum_t **p; 753 for(p = fileinfo->checksums; *p; ++p) { 754 if(curl_strequal(digest_alias->alias_name, (*p)->type) && 755 check_hex_digest((*p)->hash, digest_alias->digest_def)) { 756 f->checksum = 757 new_metalink_checksum_from_hex_digest(digest_alias->digest_def, 758 (*p)->hash); 759 break; 760 } 761 } 762 if(f->checksum) { 763 break; 764 } 765 } 766 } 767 if(fileinfo->resources) { 768 metalink_resource_t **p; 769 metalink_resource root, *tail; 770 root.next = NULL; 771 tail = &root; 772 for(p = fileinfo->resources; *p; ++p) { 773 metalink_resource *res; 774 /* Filter by type if it is non-NULL. In Metalink v3, type 775 includes the type of the resource. In curl, we are only 776 interested in HTTP, HTTPS and FTP. In addition to them, 777 Metalink v3 file may contain bittorrent type URL, which 778 points to the BitTorrent metainfo file. We ignore it here. 779 In Metalink v4, type was deprecated and all 780 fileinfo->resources point to the target file. BitTorrent 781 metainfo file URL may be appeared in fileinfo->metaurls. 782 */ 783 if((*p)->type == NULL || 784 curl_strequal((*p)->type, "http") || 785 curl_strequal((*p)->type, "https") || 786 curl_strequal((*p)->type, "ftp") || 787 curl_strequal((*p)->type, "ftps")) { 788 res = new_metalink_resource((*p)->url); 789 if(res) { 790 tail->next = res; 791 tail = res; 792 } 793 else { 794 tail = root.next; 795 796 /* clean up the linked list */ 797 while(tail) { 798 res = tail->next; 799 free(tail->url); 800 free(tail); 801 tail = res; 802 } 803 free(f->filename); 804 free(f); 805 return NULL; 806 } 807 } 808 } 809 f->resource = root.next; 810 } 811 return f; 812 } 813 814 int parse_metalink(struct OperationConfig *config, struct OutStruct *outs, 815 const char *metalink_url) 816 { 817 metalink_error_t r; 818 metalink_t* metalink; 819 metalink_file_t **files; 820 bool warnings = FALSE; 821 822 /* metlaink_parse_final deletes outs->metalink_parser */ 823 r = metalink_parse_final(outs->metalink_parser, NULL, 0, &metalink); 824 outs->metalink_parser = NULL; 825 if(r != 0) { 826 return -1; 827 } 828 if(metalink->files == NULL) { 829 fprintf(config->global->errors, "Metalink: parsing (%s) WARNING " 830 "(missing or invalid file name)\n", 831 metalink_url); 832 metalink_delete(metalink); 833 return -1; 834 } 835 for(files = metalink->files; *files; ++files) { 836 struct getout *url; 837 /* Skip an entry which has no resource. */ 838 if(!(*files)->resources) { 839 fprintf(config->global->errors, "Metalink: parsing (%s) WARNING " 840 "(missing or invalid resource)\n", 841 metalink_url); 842 continue; 843 } 844 if(config->url_get || 845 ((config->url_get = config->url_list) != NULL)) { 846 /* there's a node here, if it already is filled-in continue to 847 find an "empty" node */ 848 while(config->url_get && (config->url_get->flags & GETOUT_URL)) 849 config->url_get = config->url_get->next; 850 } 851 852 /* now there might or might not be an available node to fill in! */ 853 854 if(config->url_get) 855 /* existing node */ 856 url = config->url_get; 857 else 858 /* there was no free node, create one! */ 859 url = new_getout(config); 860 861 if(url) { 862 metalinkfile *mlfile = new_metalinkfile(*files); 863 if(!mlfile) 864 break; 865 866 if(!mlfile->checksum) { 867 warnings = TRUE; 868 fprintf(config->global->errors, 869 "Metalink: parsing (%s) WARNING (digest missing)\n", 870 metalink_url); 871 } 872 /* Set name as url */ 873 GetStr(&url->url, mlfile->filename); 874 875 /* set flag metalink here */ 876 url->flags |= GETOUT_URL | GETOUT_METALINK; 877 878 if(config->metalinkfile_list) { 879 config->metalinkfile_last->next = mlfile; 880 config->metalinkfile_last = mlfile; 881 } 882 else { 883 config->metalinkfile_list = config->metalinkfile_last = mlfile; 884 } 885 } 886 } 887 metalink_delete(metalink); 888 return (warnings) ? -2 : 0; 889 } 890 891 size_t metalink_write_cb(void *buffer, size_t sz, size_t nmemb, 892 void *userdata) 893 { 894 struct OutStruct *outs = userdata; 895 struct OperationConfig *config = outs->config; 896 int rv; 897 898 /* 899 * Once that libcurl has called back tool_write_cb() the returned value 900 * is checked against the amount that was intended to be written, if 901 * it does not match then it fails with CURLE_WRITE_ERROR. So at this 902 * point returning a value different from sz*nmemb indicates failure. 903 */ 904 const size_t failure = (sz && nmemb) ? 0 : 1; 905 906 if(!config) 907 return failure; 908 909 rv = metalink_parse_update(outs->metalink_parser, buffer, sz * nmemb); 910 if(rv == 0) 911 return sz * nmemb; 912 else { 913 fprintf(config->global->errors, "Metalink: parsing FAILED\n"); 914 return failure; 915 } 916 } 917 918 /* 919 * Returns nonzero if content_type includes mediatype. 920 */ 921 static int check_content_type(const char *content_type, const char *media_type) 922 { 923 const char *ptr = content_type; 924 size_t media_type_len = strlen(media_type); 925 for(; *ptr && (*ptr == ' ' || *ptr == '\t'); ++ptr); 926 if(!*ptr) { 927 return 0; 928 } 929 return curl_strnequal(ptr, media_type, media_type_len) && 930 (*(ptr + media_type_len) == '\0' || *(ptr + media_type_len) == ' ' || 931 *(ptr + media_type_len) == '\t' || *(ptr + media_type_len) == ';'); 932 } 933 934 int check_metalink_content_type(const char *content_type) 935 { 936 return check_content_type(content_type, "application/metalink+xml"); 937 } 938 939 int count_next_metalink_resource(metalinkfile *mlfile) 940 { 941 int count = 0; 942 metalink_resource *res; 943 for(res = mlfile->resource; res; res = res->next, ++count); 944 return count; 945 } 946 947 static void delete_metalink_checksum(metalink_checksum *chksum) 948 { 949 if(chksum == NULL) { 950 return; 951 } 952 Curl_safefree(chksum->digest); 953 Curl_safefree(chksum); 954 } 955 956 static void delete_metalink_resource(metalink_resource *res) 957 { 958 if(res == NULL) { 959 return; 960 } 961 Curl_safefree(res->url); 962 Curl_safefree(res); 963 } 964 965 static void delete_metalinkfile(metalinkfile *mlfile) 966 { 967 metalink_resource *res; 968 if(mlfile == NULL) { 969 return; 970 } 971 Curl_safefree(mlfile->filename); 972 delete_metalink_checksum(mlfile->checksum); 973 for(res = mlfile->resource; res;) { 974 metalink_resource *next; 975 next = res->next; 976 delete_metalink_resource(res); 977 res = next; 978 } 979 Curl_safefree(mlfile); 980 } 981 982 void clean_metalink(struct OperationConfig *config) 983 { 984 while(config->metalinkfile_list) { 985 metalinkfile *mlfile = config->metalinkfile_list; 986 config->metalinkfile_list = config->metalinkfile_list->next; 987 delete_metalinkfile(mlfile); 988 } 989 config->metalinkfile_last = 0; 990 } 991 992 void metalink_cleanup(void) 993 { 994 #ifdef HAVE_NSS_CONTEXT 995 if(nss_context) { 996 NSS_ShutdownContext(nss_context); 997 nss_context = NULL; 998 } 999 #endif 1000 } 1001 1002 #endif /* USE_METALINK */ 1003