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