Annotation of embedaddon/curl/src/tool_metalink.c, revision 1.1
1.1 ! misho 1: /***************************************************************************
! 2: * _ _ ____ _
! 3: * Project ___| | | | _ \| |
! 4: * / __| | | | |_) | |
! 5: * | (__| |_| | _ <| |___
! 6: * \___|\___/|_| \_\_____|
! 7: *
! 8: * Copyright (C) 1998 - 2020, 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 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(__MAC_OS_X_VERSION_MAX_ALLOWED) && \
! 58: (__MAC_OS_X_VERSION_MAX_ALLOWED >= 1040)) || \
! 59: (defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && \
! 60: (__IPHONE_OS_VERSION_MAX_ALLOWED >= 20000))
! 61: /* For Apple operating systems: CommonCrypto has the functions we need.
! 62: The library's headers are even backward-compatible with OpenSSL's
! 63: headers as long as we define COMMON_DIGEST_FOR_OPENSSL first.
! 64:
! 65: These functions are available on Tiger and later, as well as iOS 2.0
! 66: and later. If you're building for an older cat, well, sorry. */
! 67: # define COMMON_DIGEST_FOR_OPENSSL
! 68: # include <CommonCrypto/CommonDigest.h>
! 69: #elif defined(USE_WIN32_CRYPTO)
! 70: /* For Windows: If no other crypto library is provided, we fallback
! 71: to the hash functions provided within the Microsoft Windows CryptoAPI */
! 72: # include <wincrypt.h>
! 73: /* Custom structure in order to store the required provider and hash handle */
! 74: struct win32_crypto_hash {
! 75: HCRYPTPROV hCryptProv;
! 76: HCRYPTHASH hHash;
! 77: };
! 78: /* Custom Microsoft AES Cryptographic Provider defines required for MinGW */
! 79: # ifndef ALG_SID_SHA_256
! 80: # define ALG_SID_SHA_256 12
! 81: # endif
! 82: # ifndef CALG_SHA_256
! 83: # define CALG_SHA_256 (ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_SHA_256)
! 84: # endif
! 85: # define MD5_CTX struct win32_crypto_hash
! 86: # define SHA_CTX struct win32_crypto_hash
! 87: # define SHA256_CTX struct win32_crypto_hash
! 88: #else
! 89: # error "Can't compile METALINK support without a crypto library."
! 90: #endif
! 91:
! 92: #define ENABLE_CURLX_PRINTF
! 93: /* use our own printf() functions */
! 94: #include "curlx.h"
! 95:
! 96: #include "tool_getparam.h"
! 97: #include "tool_paramhlp.h"
! 98: #include "tool_cfgable.h"
! 99: #include "tool_metalink.h"
! 100: #include "tool_operate.h"
! 101: #include "tool_msgs.h"
! 102:
! 103: #include "memdebug.h" /* keep this as LAST include */
! 104:
! 105: /* Copied from tool_getparam.c */
! 106: #define GetStr(str,val) do { \
! 107: if(*(str)) { \
! 108: free(*(str)); \
! 109: *(str) = NULL; \
! 110: } \
! 111: if((val)) \
! 112: *(str) = strdup((val)); \
! 113: if(!(val)) \
! 114: return PARAM_NO_MEM; \
! 115: } while(0)
! 116:
! 117: #if defined(USE_OPENSSL)
! 118: /* Functions are already defined */
! 119: #elif defined(USE_GNUTLS_NETTLE)
! 120:
! 121: static int MD5_Init(MD5_CTX *ctx)
! 122: {
! 123: md5_init(ctx);
! 124: return 1;
! 125: }
! 126:
! 127: static void MD5_Update(MD5_CTX *ctx,
! 128: const unsigned char *input,
! 129: unsigned int inputLen)
! 130: {
! 131: md5_update(ctx, inputLen, input);
! 132: }
! 133:
! 134: static void MD5_Final(unsigned char digest[16], MD5_CTX *ctx)
! 135: {
! 136: md5_digest(ctx, 16, digest);
! 137: }
! 138:
! 139: static int SHA1_Init(SHA_CTX *ctx)
! 140: {
! 141: sha1_init(ctx);
! 142: return 1;
! 143: }
! 144:
! 145: static void SHA1_Update(SHA_CTX *ctx,
! 146: const unsigned char *input,
! 147: unsigned int inputLen)
! 148: {
! 149: sha1_update(ctx, inputLen, input);
! 150: }
! 151:
! 152: static void SHA1_Final(unsigned char digest[20], SHA_CTX *ctx)
! 153: {
! 154: sha1_digest(ctx, 20, digest);
! 155: }
! 156:
! 157: static int SHA256_Init(SHA256_CTX *ctx)
! 158: {
! 159: sha256_init(ctx);
! 160: return 1;
! 161: }
! 162:
! 163: static void SHA256_Update(SHA256_CTX *ctx,
! 164: const unsigned char *input,
! 165: unsigned int inputLen)
! 166: {
! 167: sha256_update(ctx, inputLen, input);
! 168: }
! 169:
! 170: static 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:
! 177: static int MD5_Init(MD5_CTX *ctx)
! 178: {
! 179: gcry_md_open(ctx, GCRY_MD_MD5, 0);
! 180: return 1;
! 181: }
! 182:
! 183: static 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:
! 190: static 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:
! 196: static int SHA1_Init(SHA_CTX *ctx)
! 197: {
! 198: gcry_md_open(ctx, GCRY_MD_SHA1, 0);
! 199: return 1;
! 200: }
! 201:
! 202: static 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:
! 209: static 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:
! 215: static int SHA256_Init(SHA256_CTX *ctx)
! 216: {
! 217: gcry_md_open(ctx, GCRY_MD_SHA256, 0);
! 218: return 1;
! 219: }
! 220:
! 221: static 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:
! 228: static 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:
! 236: static int nss_hash_init(void **pctx, SECOidTag hash_alg)
! 237: {
! 238: PK11Context *ctx;
! 239:
! 240: /* we have to initialize NSS if not initialized already */
! 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:
! 262: static 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:
! 270: static int MD5_Init(MD5_CTX *pctx)
! 271: {
! 272: return nss_hash_init(pctx, SEC_OID_MD5);
! 273: }
! 274:
! 275: static 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:
! 282: static void MD5_Final(unsigned char digest[16], MD5_CTX *pctx)
! 283: {
! 284: nss_hash_final(pctx, digest, 16);
! 285: }
! 286:
! 287: static int SHA1_Init(SHA_CTX *pctx)
! 288: {
! 289: return nss_hash_init(pctx, SEC_OID_SHA1);
! 290: }
! 291:
! 292: static 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:
! 299: static void SHA1_Final(unsigned char digest[20], SHA_CTX *pctx)
! 300: {
! 301: nss_hash_final(pctx, digest, 20);
! 302: }
! 303:
! 304: static int SHA256_Init(SHA256_CTX *pctx)
! 305: {
! 306: return nss_hash_init(pctx, SEC_OID_SHA256);
! 307: }
! 308:
! 309: static 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:
! 316: static void SHA256_Final(unsigned char digest[32], SHA256_CTX *pctx)
! 317: {
! 318: nss_hash_final(pctx, digest, 32);
! 319: }
! 320:
! 321: #elif defined(USE_WIN32_CRYPTO)
! 322:
! 323: static 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:
! 337: static int MD5_Init(MD5_CTX *ctx)
! 338: {
! 339: if(CryptAcquireContext(&ctx->hCryptProv, NULL, NULL, PROV_RSA_FULL,
! 340: CRYPT_VERIFYCONTEXT | CRYPT_SILENT)) {
! 341: CryptCreateHash(ctx->hCryptProv, CALG_MD5, 0, 0, &ctx->hHash);
! 342: }
! 343: return 1;
! 344: }
! 345:
! 346: static 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:
! 353: static void MD5_Final(unsigned char digest[16], MD5_CTX *ctx)
! 354: {
! 355: win32_crypto_final(ctx, digest, 16);
! 356: }
! 357:
! 358: static int SHA1_Init(SHA_CTX *ctx)
! 359: {
! 360: if(CryptAcquireContext(&ctx->hCryptProv, NULL, NULL, PROV_RSA_FULL,
! 361: CRYPT_VERIFYCONTEXT | CRYPT_SILENT)) {
! 362: CryptCreateHash(ctx->hCryptProv, CALG_SHA1, 0, 0, &ctx->hHash);
! 363: }
! 364: return 1;
! 365: }
! 366:
! 367: static 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:
! 374: static void SHA1_Final(unsigned char digest[20], SHA_CTX *ctx)
! 375: {
! 376: win32_crypto_final(ctx, digest, 20);
! 377: }
! 378:
! 379: static int SHA256_Init(SHA256_CTX *ctx)
! 380: {
! 381: if(CryptAcquireContext(&ctx->hCryptProv, NULL, NULL, PROV_RSA_AES,
! 382: CRYPT_VERIFYCONTEXT | CRYPT_SILENT)) {
! 383: CryptCreateHash(ctx->hCryptProv, CALG_SHA_256, 0, 0, &ctx->hHash);
! 384: }
! 385: return 1;
! 386: }
! 387:
! 388: static 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:
! 395: static 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:
! 402: const digest_params MD5_DIGEST_PARAMS[] = {
! 403: {
! 404: CURLX_FUNCTION_CAST(digest_init_func, MD5_Init),
! 405: CURLX_FUNCTION_CAST(digest_update_func, MD5_Update),
! 406: CURLX_FUNCTION_CAST(digest_final_func, MD5_Final),
! 407: sizeof(MD5_CTX),
! 408: 16
! 409: }
! 410: };
! 411:
! 412: const digest_params SHA1_DIGEST_PARAMS[] = {
! 413: {
! 414: CURLX_FUNCTION_CAST(digest_init_func, SHA1_Init),
! 415: CURLX_FUNCTION_CAST(digest_update_func, SHA1_Update),
! 416: CURLX_FUNCTION_CAST(digest_final_func, SHA1_Final),
! 417: sizeof(SHA_CTX),
! 418: 20
! 419: }
! 420: };
! 421:
! 422: const digest_params SHA256_DIGEST_PARAMS[] = {
! 423: {
! 424: CURLX_FUNCTION_CAST(digest_init_func, SHA256_Init),
! 425: CURLX_FUNCTION_CAST(digest_update_func, SHA256_Update),
! 426: CURLX_FUNCTION_CAST(digest_final_func, SHA256_Final),
! 427: sizeof(SHA256_CTX),
! 428: 32
! 429: }
! 430: };
! 431:
! 432: static const metalink_digest_def SHA256_DIGEST_DEF[] = {
! 433: {"sha-256", SHA256_DIGEST_PARAMS}
! 434: };
! 435:
! 436: static const metalink_digest_def SHA1_DIGEST_DEF[] = {
! 437: {"sha-1", SHA1_DIGEST_PARAMS}
! 438: };
! 439:
! 440: static 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: */
! 451: static 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:
! 460: static digest_context *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->digest_hashctx);
! 481: free(ctxt);
! 482: return NULL;
! 483: }
! 484:
! 485: return ctxt;
! 486: }
! 487:
! 488: static int digest_update(digest_context *context,
! 489: const unsigned char *data,
! 490: unsigned int len)
! 491: {
! 492: (*context->digest_hash->digest_update)(context->digest_hashctx, data, len);
! 493:
! 494: return 0;
! 495: }
! 496:
! 497: static int digest_final(digest_context *context, unsigned char *result)
! 498: {
! 499: if(result)
! 500: (*context->digest_hash->digest_final)(result, context->digest_hashctx);
! 501:
! 502: free(context->digest_hashctx);
! 503: free(context);
! 504:
! 505: return 0;
! 506: }
! 507:
! 508: static unsigned char hex_to_uint(const char *s)
! 509: {
! 510: char buf[3];
! 511: unsigned long val;
! 512: buf[0] = s[0];
! 513: buf[1] = s[1];
! 514: buf[2] = 0;
! 515: val = strtoul(buf, NULL, 16);
! 516: return (unsigned char)(val&0xff);
! 517: }
! 518:
! 519: /*
! 520: * Check checksum of file denoted by filename. The expected hash value
! 521: * is given in hex_hash which is hex-encoded string.
! 522: *
! 523: * This function returns 1 if it succeeds or one of the following
! 524: * integers:
! 525: *
! 526: * 0:
! 527: * Checksum didn't match.
! 528: * -1:
! 529: * Could not open file; or could not read data from file.
! 530: * -2:
! 531: * Hash algorithm not available.
! 532: */
! 533: static int check_hash(const char *filename,
! 534: const metalink_digest_def *digest_def,
! 535: const unsigned char *digest, FILE *error)
! 536: {
! 537: unsigned char *result;
! 538: digest_context *dctx;
! 539: int check_ok, flags, fd;
! 540:
! 541: flags = O_RDONLY;
! 542: #ifdef O_BINARY
! 543: /* O_BINARY is required in order to avoid binary EOF in text mode */
! 544: flags |= O_BINARY;
! 545: #endif
! 546:
! 547: fd = open(filename, flags);
! 548: if(fd == -1) {
! 549: fprintf(error, "Metalink: validating (%s) [%s] FAILED (%s)\n", filename,
! 550: digest_def->hash_name, strerror(errno));
! 551: return -1;
! 552: }
! 553:
! 554: dctx = digest_init(digest_def->dparams);
! 555: if(!dctx) {
! 556: fprintf(error, "Metalink: validating (%s) [%s] FAILED (%s)\n", filename,
! 557: digest_def->hash_name, "failed to initialize hash algorithm");
! 558: close(fd);
! 559: return -2;
! 560: }
! 561:
! 562: result = malloc(digest_def->dparams->digest_resultlen);
! 563: if(!result) {
! 564: close(fd);
! 565: digest_final(dctx, NULL);
! 566: return -1;
! 567: }
! 568: while(1) {
! 569: unsigned char buf[4096];
! 570: ssize_t len = read(fd, buf, sizeof(buf));
! 571: if(len == 0) {
! 572: break;
! 573: }
! 574: else if(len == -1) {
! 575: fprintf(error, "Metalink: validating (%s) [%s] FAILED (%s)\n", filename,
! 576: digest_def->hash_name, strerror(errno));
! 577: digest_final(dctx, result);
! 578: close(fd);
! 579: return -1;
! 580: }
! 581: digest_update(dctx, buf, (unsigned int)len);
! 582: }
! 583: digest_final(dctx, result);
! 584: check_ok = memcmp(result, digest,
! 585: digest_def->dparams->digest_resultlen) == 0;
! 586: /* sha*sum style verdict output */
! 587: if(check_ok)
! 588: fprintf(error, "Metalink: validating (%s) [%s] OK\n", filename,
! 589: digest_def->hash_name);
! 590: else
! 591: fprintf(error, "Metalink: validating (%s) [%s] FAILED (digest mismatch)\n",
! 592: filename, digest_def->hash_name);
! 593:
! 594: free(result);
! 595: close(fd);
! 596: return check_ok;
! 597: }
! 598:
! 599: int metalink_check_hash(struct GlobalConfig *config,
! 600: metalinkfile *mlfile,
! 601: const char *filename)
! 602: {
! 603: int rv;
! 604: fprintf(config->errors, "Metalink: validating (%s)...\n", filename);
! 605: if(mlfile->checksum == NULL) {
! 606: fprintf(config->errors,
! 607: "Metalink: validating (%s) FAILED (digest missing)\n", filename);
! 608: return -2;
! 609: }
! 610: rv = check_hash(filename, mlfile->checksum->digest_def,
! 611: mlfile->checksum->digest, config->errors);
! 612: return rv;
! 613: }
! 614:
! 615: static metalink_checksum *
! 616: checksum_from_hex_digest(const metalink_digest_def *digest_def,
! 617: const char *hex_digest)
! 618: {
! 619: metalink_checksum *chksum;
! 620: unsigned char *digest;
! 621: size_t i;
! 622: size_t len = strlen(hex_digest);
! 623: digest = malloc(len/2);
! 624: if(!digest)
! 625: return 0;
! 626:
! 627: for(i = 0; i < len; i += 2) {
! 628: digest[i/2] = hex_to_uint(hex_digest + i);
! 629: }
! 630: chksum = malloc(sizeof(metalink_checksum));
! 631: if(chksum) {
! 632: chksum->digest_def = digest_def;
! 633: chksum->digest = digest;
! 634: }
! 635: else
! 636: free(digest);
! 637: return chksum;
! 638: }
! 639:
! 640: static metalink_resource *new_metalink_resource(const char *url)
! 641: {
! 642: metalink_resource *res;
! 643: res = malloc(sizeof(metalink_resource));
! 644: if(res) {
! 645: res->next = NULL;
! 646: res->url = strdup(url);
! 647: if(!res->url) {
! 648: free(res);
! 649: return NULL;
! 650: }
! 651: }
! 652: return res;
! 653: }
! 654:
! 655: /* Returns nonzero if hex_digest is properly formatted; that is each
! 656: letter is in [0-9A-Za-z] and the length of the string equals to the
! 657: result length of digest * 2. */
! 658: static int check_hex_digest(const char *hex_digest,
! 659: const metalink_digest_def *digest_def)
! 660: {
! 661: size_t i;
! 662: for(i = 0; hex_digest[i]; ++i) {
! 663: char c = hex_digest[i];
! 664: if(!(('0' <= c && c <= '9') || ('a' <= c && c <= 'z') ||
! 665: ('A' <= c && c <= 'Z'))) {
! 666: return 0;
! 667: }
! 668: }
! 669: return digest_def->dparams->digest_resultlen * 2 == i;
! 670: }
! 671:
! 672: static metalinkfile *new_metalinkfile(metalink_file_t *fileinfo)
! 673: {
! 674: metalinkfile *f;
! 675: f = (metalinkfile*)malloc(sizeof(metalinkfile));
! 676: if(!f)
! 677: return NULL;
! 678:
! 679: f->next = NULL;
! 680: f->filename = strdup(fileinfo->name);
! 681: if(!f->filename) {
! 682: free(f);
! 683: return NULL;
! 684: }
! 685: f->checksum = NULL;
! 686: f->resource = NULL;
! 687: if(fileinfo->checksums) {
! 688: const metalink_digest_alias *digest_alias;
! 689: for(digest_alias = digest_aliases; digest_alias->alias_name;
! 690: ++digest_alias) {
! 691: metalink_checksum_t **p;
! 692: for(p = fileinfo->checksums; *p; ++p) {
! 693: if(curl_strequal(digest_alias->alias_name, (*p)->type) &&
! 694: check_hex_digest((*p)->hash, digest_alias->digest_def)) {
! 695: f->checksum =
! 696: checksum_from_hex_digest(digest_alias->digest_def,
! 697: (*p)->hash);
! 698: break;
! 699: }
! 700: }
! 701: if(f->checksum) {
! 702: break;
! 703: }
! 704: }
! 705: }
! 706: if(fileinfo->resources) {
! 707: metalink_resource_t **p;
! 708: metalink_resource root, *tail;
! 709: root.next = NULL;
! 710: tail = &root;
! 711: for(p = fileinfo->resources; *p; ++p) {
! 712: metalink_resource *res;
! 713: /* Filter by type if it is non-NULL. In Metalink v3, type
! 714: includes the type of the resource. In curl, we are only
! 715: interested in HTTP, HTTPS and FTP. In addition to them,
! 716: Metalink v3 file may contain bittorrent type URL, which
! 717: points to the BitTorrent metainfo file. We ignore it here.
! 718: In Metalink v4, type was deprecated and all
! 719: fileinfo->resources point to the target file. BitTorrent
! 720: metainfo file URL may be appeared in fileinfo->metaurls.
! 721: */
! 722: if((*p)->type == NULL ||
! 723: curl_strequal((*p)->type, "http") ||
! 724: curl_strequal((*p)->type, "https") ||
! 725: curl_strequal((*p)->type, "ftp") ||
! 726: curl_strequal((*p)->type, "ftps")) {
! 727: res = new_metalink_resource((*p)->url);
! 728: if(res) {
! 729: tail->next = res;
! 730: tail = res;
! 731: }
! 732: else {
! 733: tail = root.next;
! 734:
! 735: /* clean up the linked list */
! 736: while(tail) {
! 737: res = tail->next;
! 738: free(tail->url);
! 739: free(tail);
! 740: tail = res;
! 741: }
! 742: free(f->filename);
! 743: free(f);
! 744: return NULL;
! 745: }
! 746: }
! 747: }
! 748: f->resource = root.next;
! 749: }
! 750: return f;
! 751: }
! 752:
! 753: int parse_metalink(struct OperationConfig *config, struct OutStruct *outs,
! 754: const char *metalink_url)
! 755: {
! 756: metalink_error_t r;
! 757: metalink_t* metalink;
! 758: metalink_file_t **files;
! 759: bool warnings = FALSE;
! 760:
! 761: /* metlaink_parse_final deletes outs->metalink_parser */
! 762: r = metalink_parse_final(outs->metalink_parser, NULL, 0, &metalink);
! 763: outs->metalink_parser = NULL;
! 764: if(r != 0) {
! 765: return -1;
! 766: }
! 767: if(metalink->files == NULL) {
! 768: fprintf(config->global->errors, "Metalink: parsing (%s) WARNING "
! 769: "(missing or invalid file name)\n",
! 770: metalink_url);
! 771: metalink_delete(metalink);
! 772: return -1;
! 773: }
! 774: for(files = metalink->files; *files; ++files) {
! 775: struct getout *url;
! 776: /* Skip an entry which has no resource. */
! 777: if(!(*files)->resources) {
! 778: fprintf(config->global->errors, "Metalink: parsing (%s) WARNING "
! 779: "(missing or invalid resource)\n",
! 780: metalink_url);
! 781: continue;
! 782: }
! 783: if(config->url_get ||
! 784: ((config->url_get = config->url_list) != NULL)) {
! 785: /* there's a node here, if it already is filled-in continue to
! 786: find an "empty" node */
! 787: while(config->url_get && (config->url_get->flags & GETOUT_URL))
! 788: config->url_get = config->url_get->next;
! 789: }
! 790:
! 791: /* now there might or might not be an available node to fill in! */
! 792:
! 793: if(config->url_get)
! 794: /* existing node */
! 795: url = config->url_get;
! 796: else
! 797: /* there was no free node, create one! */
! 798: url = new_getout(config);
! 799:
! 800: if(url) {
! 801: metalinkfile *mlfile = new_metalinkfile(*files);
! 802: if(!mlfile)
! 803: break;
! 804:
! 805: if(!mlfile->checksum) {
! 806: warnings = TRUE;
! 807: fprintf(config->global->errors,
! 808: "Metalink: parsing (%s) WARNING (digest missing)\n",
! 809: metalink_url);
! 810: }
! 811: /* Set name as url */
! 812: GetStr(&url->url, mlfile->filename);
! 813:
! 814: /* set flag metalink here */
! 815: url->flags |= GETOUT_URL | GETOUT_METALINK;
! 816:
! 817: if(config->metalinkfile_list) {
! 818: config->metalinkfile_last->next = mlfile;
! 819: config->metalinkfile_last = mlfile;
! 820: }
! 821: else {
! 822: config->metalinkfile_list = config->metalinkfile_last = mlfile;
! 823: }
! 824: }
! 825: }
! 826: metalink_delete(metalink);
! 827: return (warnings) ? -2 : 0;
! 828: }
! 829:
! 830: size_t metalink_write_cb(void *buffer, size_t sz, size_t nmemb,
! 831: void *userdata)
! 832: {
! 833: struct per_transfer *per = userdata;
! 834: struct OutStruct *outs = &per->outs;
! 835: struct OperationConfig *config = per->config;
! 836: int rv;
! 837:
! 838: /*
! 839: * Once that libcurl has called back tool_write_cb() the returned value
! 840: * is checked against the amount that was intended to be written, if
! 841: * it does not match then it fails with CURLE_WRITE_ERROR. So at this
! 842: * point returning a value different from sz*nmemb indicates failure.
! 843: */
! 844: const size_t failure = (sz && nmemb) ? 0 : 1;
! 845:
! 846: if(!config)
! 847: return failure;
! 848:
! 849: rv = metalink_parse_update(outs->metalink_parser, buffer, sz * nmemb);
! 850: if(rv == 0)
! 851: return sz * nmemb;
! 852: else {
! 853: fprintf(config->global->errors, "Metalink: parsing FAILED\n");
! 854: return failure;
! 855: }
! 856: }
! 857:
! 858: /*
! 859: * Returns nonzero if content_type includes mediatype.
! 860: */
! 861: static int check_content_type(const char *content_type, const char *media_type)
! 862: {
! 863: const char *ptr = content_type;
! 864: size_t media_type_len = strlen(media_type);
! 865: for(; *ptr && (*ptr == ' ' || *ptr == '\t'); ++ptr);
! 866: if(!*ptr) {
! 867: return 0;
! 868: }
! 869: return curl_strnequal(ptr, media_type, media_type_len) &&
! 870: (*(ptr + media_type_len) == '\0' || *(ptr + media_type_len) == ' ' ||
! 871: *(ptr + media_type_len) == '\t' || *(ptr + media_type_len) == ';');
! 872: }
! 873:
! 874: int check_metalink_content_type(const char *content_type)
! 875: {
! 876: return check_content_type(content_type, "application/metalink+xml");
! 877: }
! 878:
! 879: int count_next_metalink_resource(metalinkfile *mlfile)
! 880: {
! 881: int count = 0;
! 882: metalink_resource *res;
! 883: for(res = mlfile->resource; res; res = res->next, ++count);
! 884: return count;
! 885: }
! 886:
! 887: static void delete_metalink_checksum(metalink_checksum *chksum)
! 888: {
! 889: if(chksum == NULL) {
! 890: return;
! 891: }
! 892: Curl_safefree(chksum->digest);
! 893: Curl_safefree(chksum);
! 894: }
! 895:
! 896: static void delete_metalink_resource(metalink_resource *res)
! 897: {
! 898: if(res == NULL) {
! 899: return;
! 900: }
! 901: Curl_safefree(res->url);
! 902: Curl_safefree(res);
! 903: }
! 904:
! 905: void delete_metalinkfile(metalinkfile *mlfile)
! 906: {
! 907: metalink_resource *res;
! 908: if(mlfile == NULL) {
! 909: return;
! 910: }
! 911: Curl_safefree(mlfile->filename);
! 912: delete_metalink_checksum(mlfile->checksum);
! 913: for(res = mlfile->resource; res;) {
! 914: metalink_resource *next;
! 915: next = res->next;
! 916: delete_metalink_resource(res);
! 917: res = next;
! 918: }
! 919: Curl_safefree(mlfile);
! 920: }
! 921:
! 922: void clean_metalink(struct OperationConfig *config)
! 923: {
! 924: if(config) {
! 925: while(config->metalinkfile_list) {
! 926: metalinkfile *mlfile = config->metalinkfile_list;
! 927: config->metalinkfile_list = config->metalinkfile_list->next;
! 928: delete_metalinkfile(mlfile);
! 929: }
! 930: config->metalinkfile_last = 0;
! 931: }
! 932: }
! 933:
! 934: void metalink_cleanup(void)
! 935: {
! 936: #ifdef HAVE_NSS_CONTEXT
! 937: if(nss_context) {
! 938: NSS_ShutdownContext(nss_context);
! 939: nss_context = NULL;
! 940: }
! 941: #endif
! 942: }
! 943:
! 944: #endif /* USE_METALINK */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>