00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include "tool_setup.h"
00023
00024 #ifdef USE_METALINK
00025
00026 #include <sys/stat.h>
00027 #include <stdlib.h>
00028
00029 #ifdef HAVE_FCNTL_H
00030 # include <fcntl.h>
00031 #endif
00032
00033 #ifdef USE_OPENSSL
00034 # include <openssl/md5.h>
00035 # include <openssl/sha.h>
00036 #elif defined(USE_GNUTLS_NETTLE)
00037 # include <nettle/md5.h>
00038 # include <nettle/sha.h>
00039 # define MD5_CTX struct md5_ctx
00040 # define SHA_CTX struct sha1_ctx
00041 # define SHA256_CTX struct sha256_ctx
00042 #elif defined(USE_GNUTLS)
00043 # include <gcrypt.h>
00044 # define MD5_CTX gcry_md_hd_t
00045 # define SHA_CTX gcry_md_hd_t
00046 # define SHA256_CTX gcry_md_hd_t
00047 #elif defined(USE_NSS)
00048 # include <nss.h>
00049 # include <pk11pub.h>
00050 # define MD5_CTX void *
00051 # define SHA_CTX void *
00052 # define SHA256_CTX void *
00053 static NSSInitContext *nss_context;
00054 #elif defined(USE_POLARSSL)
00055 # include <polarssl/md5.h>
00056 # include <polarssl/sha1.h>
00057 # include <polarssl/sha256.h>
00058 # define MD5_CTX md5_context
00059 # define SHA_CTX sha1_context
00060 # define SHA256_CTX sha256_context
00061 #elif (defined(__MAC_OS_X_VERSION_MAX_ALLOWED) && \
00062 (__MAC_OS_X_VERSION_MAX_ALLOWED >= 1040)) || \
00063 (defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && \
00064 (__IPHONE_OS_VERSION_MAX_ALLOWED >= 20000))
00065
00066
00067
00068
00069
00070
00071 # define COMMON_DIGEST_FOR_OPENSSL
00072 # include <CommonCrypto/CommonDigest.h>
00073 #elif defined(_WIN32)
00074
00075
00076 # include <wincrypt.h>
00077
00078 struct win32_crypto_hash {
00079 HCRYPTPROV hCryptProv;
00080 HCRYPTHASH hHash;
00081 };
00082
00083 # ifndef ALG_SID_SHA_256
00084 # define ALG_SID_SHA_256 12
00085 # endif
00086 # ifndef CALG_SHA_256
00087 # define CALG_SHA_256 (ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_SHA_256)
00088 # endif
00089 # define MD5_CTX struct win32_crypto_hash
00090 # define SHA_CTX struct win32_crypto_hash
00091 # define SHA256_CTX struct win32_crypto_hash
00092 #else
00093 # error "Can't compile METALINK support without a crypto library."
00094 #endif
00095
00096 #define ENABLE_CURLX_PRINTF
00097
00098 #include "curlx.h"
00099
00100 #include "tool_getparam.h"
00101 #include "tool_paramhlp.h"
00102 #include "tool_cfgable.h"
00103 #include "tool_metalink.h"
00104 #include "tool_msgs.h"
00105
00106 #include "memdebug.h"
00107
00108
00109 #define GetStr(str,val) do { \
00110 if(*(str)) { \
00111 free(*(str)); \
00112 *(str) = NULL; \
00113 } \
00114 if((val)) \
00115 *(str) = strdup((val)); \
00116 if(!(val)) \
00117 return PARAM_NO_MEM; \
00118 } WHILE_FALSE
00119
00120 #ifdef USE_GNUTLS_NETTLE
00121
00122 static int MD5_Init(MD5_CTX *ctx)
00123 {
00124 md5_init(ctx);
00125 return 1;
00126 }
00127
00128 static void MD5_Update(MD5_CTX *ctx,
00129 const unsigned char *input,
00130 unsigned int inputLen)
00131 {
00132 md5_update(ctx, inputLen, input);
00133 }
00134
00135 static void MD5_Final(unsigned char digest[16], MD5_CTX *ctx)
00136 {
00137 md5_digest(ctx, 16, digest);
00138 }
00139
00140 static int SHA1_Init(SHA_CTX *ctx)
00141 {
00142 sha1_init(ctx);
00143 return 1;
00144 }
00145
00146 static void SHA1_Update(SHA_CTX *ctx,
00147 const unsigned char *input,
00148 unsigned int inputLen)
00149 {
00150 sha1_update(ctx, inputLen, input);
00151 }
00152
00153 static void SHA1_Final(unsigned char digest[20], SHA_CTX *ctx)
00154 {
00155 sha1_digest(ctx, 20, digest);
00156 }
00157
00158 static int SHA256_Init(SHA256_CTX *ctx)
00159 {
00160 sha256_init(ctx);
00161 return 1;
00162 }
00163
00164 static void SHA256_Update(SHA256_CTX *ctx,
00165 const unsigned char *input,
00166 unsigned int inputLen)
00167 {
00168 sha256_update(ctx, inputLen, input);
00169 }
00170
00171 static void SHA256_Final(unsigned char digest[32], SHA256_CTX *ctx)
00172 {
00173 sha256_digest(ctx, 32, digest);
00174 }
00175
00176 #elif defined(USE_GNUTLS)
00177
00178 static int MD5_Init(MD5_CTX *ctx)
00179 {
00180 gcry_md_open(ctx, GCRY_MD_MD5, 0);
00181 return 1;
00182 }
00183
00184 static void MD5_Update(MD5_CTX *ctx,
00185 const unsigned char *input,
00186 unsigned int inputLen)
00187 {
00188 gcry_md_write(*ctx, input, inputLen);
00189 }
00190
00191 static void MD5_Final(unsigned char digest[16], MD5_CTX *ctx)
00192 {
00193 memcpy(digest, gcry_md_read(*ctx, 0), 16);
00194 gcry_md_close(*ctx);
00195 }
00196
00197 static int SHA1_Init(SHA_CTX *ctx)
00198 {
00199 gcry_md_open(ctx, GCRY_MD_SHA1, 0);
00200 return 1;
00201 }
00202
00203 static void SHA1_Update(SHA_CTX *ctx,
00204 const unsigned char *input,
00205 unsigned int inputLen)
00206 {
00207 gcry_md_write(*ctx, input, inputLen);
00208 }
00209
00210 static void SHA1_Final(unsigned char digest[20], SHA_CTX *ctx)
00211 {
00212 memcpy(digest, gcry_md_read(*ctx, 0), 20);
00213 gcry_md_close(*ctx);
00214 }
00215
00216 static int SHA256_Init(SHA256_CTX *ctx)
00217 {
00218 gcry_md_open(ctx, GCRY_MD_SHA256, 0);
00219 return 1;
00220 }
00221
00222 static void SHA256_Update(SHA256_CTX *ctx,
00223 const unsigned char *input,
00224 unsigned int inputLen)
00225 {
00226 gcry_md_write(*ctx, input, inputLen);
00227 }
00228
00229 static void SHA256_Final(unsigned char digest[32], SHA256_CTX *ctx)
00230 {
00231 memcpy(digest, gcry_md_read(*ctx, 0), 32);
00232 gcry_md_close(*ctx);
00233 }
00234
00235 #elif defined(USE_NSS)
00236
00237 static int nss_hash_init(void **pctx, SECOidTag hash_alg)
00238 {
00239 PK11Context *ctx;
00240
00241
00242 if(!NSS_IsInitialized() && !nss_context) {
00243 static NSSInitParameters params;
00244 params.length = sizeof params;
00245 nss_context = NSS_InitContext("", "", "", "", ¶ms, NSS_INIT_READONLY
00246 | NSS_INIT_NOCERTDB | NSS_INIT_NOMODDB | NSS_INIT_FORCEOPEN
00247 | NSS_INIT_NOROOTINIT | NSS_INIT_OPTIMIZESPACE | NSS_INIT_PK11RELOAD);
00248 }
00249
00250 ctx = PK11_CreateDigestContext(hash_alg);
00251 if(!ctx)
00252 return 0;
00253
00254 if(PK11_DigestBegin(ctx) != SECSuccess) {
00255 PK11_DestroyContext(ctx, PR_TRUE);
00256 return 0;
00257 }
00258
00259 *pctx = ctx;
00260 return 1;
00261 }
00262
00263 static void nss_hash_final(void **pctx, unsigned char *out, unsigned int len)
00264 {
00265 PK11Context *ctx = *pctx;
00266 unsigned int outlen;
00267 PK11_DigestFinal(ctx, out, &outlen, len);
00268 PK11_DestroyContext(ctx, PR_TRUE);
00269 }
00270
00271 static int MD5_Init(MD5_CTX *pctx)
00272 {
00273 return nss_hash_init(pctx, SEC_OID_MD5);
00274 }
00275
00276 static void MD5_Update(MD5_CTX *pctx,
00277 const unsigned char *input,
00278 unsigned int input_len)
00279 {
00280 PK11_DigestOp(*pctx, input, input_len);
00281 }
00282
00283 static void MD5_Final(unsigned char digest[16], MD5_CTX *pctx)
00284 {
00285 nss_hash_final(pctx, digest, 16);
00286 }
00287
00288 static int SHA1_Init(SHA_CTX *pctx)
00289 {
00290 return nss_hash_init(pctx, SEC_OID_SHA1);
00291 }
00292
00293 static void SHA1_Update(SHA_CTX *pctx,
00294 const unsigned char *input,
00295 unsigned int input_len)
00296 {
00297 PK11_DigestOp(*pctx, input, input_len);
00298 }
00299
00300 static void SHA1_Final(unsigned char digest[20], SHA_CTX *pctx)
00301 {
00302 nss_hash_final(pctx, digest, 20);
00303 }
00304
00305 static int SHA256_Init(SHA256_CTX *pctx)
00306 {
00307 return nss_hash_init(pctx, SEC_OID_SHA256);
00308 }
00309
00310 static void SHA256_Update(SHA256_CTX *pctx,
00311 const unsigned char *input,
00312 unsigned int input_len)
00313 {
00314 PK11_DigestOp(*pctx, input, input_len);
00315 }
00316
00317 static void SHA256_Final(unsigned char digest[32], SHA256_CTX *pctx)
00318 {
00319 nss_hash_final(pctx, digest, 32);
00320 }
00321
00322 #elif defined(USE_POLARSSL)
00323
00324 static int MD5_Init(MD5_CTX *ctx)
00325 {
00326 md5_starts(ctx);
00327 return 1;
00328 }
00329
00330 static void MD5_Update(MD5_CTX *ctx,
00331 const unsigned char *input,
00332 unsigned int inputLen)
00333 {
00334 md5_update(ctx, input, inputLen);
00335 }
00336
00337 static void MD5_Final(unsigned char digest[16], MD5_CTX *ctx)
00338 {
00339 md5_finish(ctx, digest);
00340 }
00341
00342 static int SHA1_Init(SHA_CTX *ctx)
00343 {
00344 sha1_starts(ctx);
00345 return 1;
00346 }
00347
00348 static void SHA1_Update(SHA_CTX *ctx,
00349 const unsigned char *input,
00350 unsigned int inputLen)
00351 {
00352 sha1_update(ctx, input, inputLen);
00353 }
00354
00355 static void SHA1_Final(unsigned char digest[20], SHA_CTX *ctx)
00356 {
00357 sha1_finish(ctx, digest);
00358 }
00359
00360 static int SHA256_Init(SHA256_CTX *ctx)
00361 {
00362 sha256_starts(ctx, 0);
00363 return 1;
00364 }
00365
00366 static void SHA256_Update(SHA256_CTX *ctx,
00367 const unsigned char *input,
00368 unsigned int inputLen)
00369 {
00370 sha256_update(ctx, input, inputLen);
00371 }
00372
00373 static void SHA256_Final(unsigned char digest[32], SHA256_CTX *ctx)
00374 {
00375 sha256_finish(ctx, digest);
00376 }
00377
00378 #elif defined(_WIN32) && !defined(USE_OPENSSL)
00379
00380 static void win32_crypto_final(struct win32_crypto_hash *ctx,
00381 unsigned char *digest,
00382 unsigned int digestLen)
00383 {
00384 unsigned long length;
00385 CryptGetHashParam(ctx->hHash, HP_HASHVAL, NULL, &length, 0);
00386 if(length == digestLen)
00387 CryptGetHashParam(ctx->hHash, HP_HASHVAL, digest, &length, 0);
00388 if(ctx->hHash)
00389 CryptDestroyHash(ctx->hHash);
00390 if(ctx->hCryptProv)
00391 CryptReleaseContext(ctx->hCryptProv, 0);
00392 }
00393
00394 static int MD5_Init(MD5_CTX *ctx)
00395 {
00396 if(CryptAcquireContext(&ctx->hCryptProv, NULL, NULL,
00397 PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) {
00398 CryptCreateHash(ctx->hCryptProv, CALG_MD5, 0, 0, &ctx->hHash);
00399 }
00400 return 1;
00401 }
00402
00403 static void MD5_Update(MD5_CTX *ctx,
00404 const unsigned char *input,
00405 unsigned int inputLen)
00406 {
00407 CryptHashData(ctx->hHash, (unsigned char *)input, inputLen, 0);
00408 }
00409
00410 static void MD5_Final(unsigned char digest[16], MD5_CTX *ctx)
00411 {
00412 win32_crypto_final(ctx, digest, 16);
00413 }
00414
00415 static int SHA1_Init(SHA_CTX *ctx)
00416 {
00417 if(CryptAcquireContext(&ctx->hCryptProv, NULL, NULL,
00418 PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) {
00419 CryptCreateHash(ctx->hCryptProv, CALG_SHA1, 0, 0, &ctx->hHash);
00420 }
00421 return 1;
00422 }
00423
00424 static void SHA1_Update(SHA_CTX *ctx,
00425 const unsigned char *input,
00426 unsigned int inputLen)
00427 {
00428 CryptHashData(ctx->hHash, (unsigned char *)input, inputLen, 0);
00429 }
00430
00431 static void SHA1_Final(unsigned char digest[20], SHA_CTX *ctx)
00432 {
00433 win32_crypto_final(ctx, digest, 20);
00434 }
00435
00436 static int SHA256_Init(SHA256_CTX *ctx)
00437 {
00438 if(CryptAcquireContext(&ctx->hCryptProv, NULL, NULL,
00439 PROV_RSA_AES, CRYPT_VERIFYCONTEXT)) {
00440 CryptCreateHash(ctx->hCryptProv, CALG_SHA_256, 0, 0, &ctx->hHash);
00441 }
00442 return 1;
00443 }
00444
00445 static void SHA256_Update(SHA256_CTX *ctx,
00446 const unsigned char *input,
00447 unsigned int inputLen)
00448 {
00449 CryptHashData(ctx->hHash, (unsigned char *)input, inputLen, 0);
00450 }
00451
00452 static void SHA256_Final(unsigned char digest[32], SHA256_CTX *ctx)
00453 {
00454 win32_crypto_final(ctx, digest, 32);
00455 }
00456
00457 #endif
00458
00459 const digest_params MD5_DIGEST_PARAMS[] = {
00460 {
00461 (Curl_digest_init_func) MD5_Init,
00462 (Curl_digest_update_func) MD5_Update,
00463 (Curl_digest_final_func) MD5_Final,
00464 sizeof(MD5_CTX),
00465 16
00466 }
00467 };
00468
00469 const digest_params SHA1_DIGEST_PARAMS[] = {
00470 {
00471 (Curl_digest_init_func) SHA1_Init,
00472 (Curl_digest_update_func) SHA1_Update,
00473 (Curl_digest_final_func) SHA1_Final,
00474 sizeof(SHA_CTX),
00475 20
00476 }
00477 };
00478
00479 const digest_params SHA256_DIGEST_PARAMS[] = {
00480 {
00481 (Curl_digest_init_func) SHA256_Init,
00482 (Curl_digest_update_func) SHA256_Update,
00483 (Curl_digest_final_func) SHA256_Final,
00484 sizeof(SHA256_CTX),
00485 32
00486 }
00487 };
00488
00489 static const metalink_digest_def SHA256_DIGEST_DEF[] = {
00490 {"sha-256", SHA256_DIGEST_PARAMS}
00491 };
00492
00493 static const metalink_digest_def SHA1_DIGEST_DEF[] = {
00494 {"sha-1", SHA1_DIGEST_PARAMS}
00495 };
00496
00497 static const metalink_digest_def MD5_DIGEST_DEF[] = {
00498 {"md5", MD5_DIGEST_PARAMS}
00499 };
00500
00501
00502
00503
00504
00505
00506
00507
00508 static const metalink_digest_alias digest_aliases[] = {
00509 {"sha-256", SHA256_DIGEST_DEF},
00510 {"sha256", SHA256_DIGEST_DEF},
00511 {"sha-1", SHA1_DIGEST_DEF},
00512 {"sha1", SHA1_DIGEST_DEF},
00513 {"md5", MD5_DIGEST_DEF},
00514 {NULL, NULL}
00515 };
00516
00517 digest_context *Curl_digest_init(const digest_params *dparams)
00518 {
00519 digest_context *ctxt;
00520
00521
00522 ctxt = malloc(sizeof *ctxt);
00523
00524 if(!ctxt)
00525 return ctxt;
00526
00527 ctxt->digest_hashctx = malloc(dparams->digest_ctxtsize);
00528
00529 if(!ctxt->digest_hashctx) {
00530 free(ctxt);
00531 return NULL;
00532 }
00533
00534 ctxt->digest_hash = dparams;
00535
00536 if(dparams->digest_init(ctxt->digest_hashctx) != 1) {
00537 free(ctxt);
00538 return NULL;
00539 }
00540
00541 return ctxt;
00542 }
00543
00544 int Curl_digest_update(digest_context *context,
00545 const unsigned char *data,
00546 unsigned int len)
00547 {
00548 (*context->digest_hash->digest_update)(context->digest_hashctx, data, len);
00549
00550 return 0;
00551 }
00552
00553 int Curl_digest_final(digest_context *context, unsigned char *result)
00554 {
00555 (*context->digest_hash->digest_final)(result, context->digest_hashctx);
00556
00557 free(context->digest_hashctx);
00558 free(context);
00559
00560 return 0;
00561 }
00562
00563 static unsigned char hex_to_uint(const char *s)
00564 {
00565 char buf[3];
00566 unsigned long val;
00567 buf[0] = s[0];
00568 buf[1] = s[1];
00569 buf[2] = 0;
00570 val = strtoul(buf, NULL, 16);
00571 return (unsigned char)(val&0xff);
00572 }
00573
00574
00575
00576
00577
00578
00579
00580
00581
00582
00583
00584
00585
00586
00587
00588 static int check_hash(const char *filename,
00589 const metalink_digest_def *digest_def,
00590 const unsigned char *digest, FILE *error)
00591 {
00592 unsigned char *result;
00593 digest_context *dctx;
00594 int check_ok, flags, fd;
00595
00596 flags = O_RDONLY;
00597 #ifdef O_BINARY
00598
00599 flags |= O_BINARY;
00600 #endif
00601
00602 fd = open(filename, flags);
00603 if(fd == -1) {
00604 fprintf(error, "Metalink: validating (%s) [%s] FAILED (%s)\n", filename,
00605 digest_def->hash_name, strerror(errno));
00606 return -1;
00607 }
00608
00609 dctx = Curl_digest_init(digest_def->dparams);
00610 if(!dctx) {
00611 fprintf(error, "Metalink: validating (%s) [%s] FAILED (%s)\n", filename,
00612 digest_def->hash_name, "failed to initialize hash algorithm");
00613 close(fd);
00614 return -2;
00615 }
00616
00617 result = malloc(digest_def->dparams->digest_resultlen);
00618 if(!result) {
00619 close(fd);
00620 return -1;
00621 }
00622 while(1) {
00623 unsigned char buf[4096];
00624 ssize_t len = read(fd, buf, sizeof(buf));
00625 if(len == 0) {
00626 break;
00627 }
00628 else if(len == -1) {
00629 fprintf(error, "Metalink: validating (%s) [%s] FAILED (%s)\n", filename,
00630 digest_def->hash_name, strerror(errno));
00631 Curl_digest_final(dctx, result);
00632 close(fd);
00633 return -1;
00634 }
00635 Curl_digest_update(dctx, buf, (unsigned int)len);
00636 }
00637 Curl_digest_final(dctx, result);
00638 check_ok = memcmp(result, digest,
00639 digest_def->dparams->digest_resultlen) == 0;
00640
00641 if(check_ok)
00642 fprintf(error, "Metalink: validating (%s) [%s] OK\n", filename,
00643 digest_def->hash_name);
00644 else
00645 fprintf(error, "Metalink: validating (%s) [%s] FAILED (digest mismatch)\n",
00646 filename, digest_def->hash_name);
00647
00648 free(result);
00649 close(fd);
00650 return check_ok;
00651 }
00652
00653 int metalink_check_hash(struct GlobalConfig *config,
00654 metalinkfile *mlfile,
00655 const char *filename)
00656 {
00657 int rv;
00658 fprintf(config->errors, "Metalink: validating (%s)...\n", filename);
00659 if(mlfile->checksum == NULL) {
00660 fprintf(config->errors,
00661 "Metalink: validating (%s) FAILED (digest missing)\n", filename);
00662 return -2;
00663 }
00664 rv = check_hash(filename, mlfile->checksum->digest_def,
00665 mlfile->checksum->digest, config->errors);
00666 return rv;
00667 }
00668
00669 static metalink_checksum *new_metalink_checksum_from_hex_digest
00670 (const metalink_digest_def *digest_def, const char *hex_digest)
00671 {
00672 metalink_checksum *chksum;
00673 unsigned char *digest;
00674 size_t i;
00675 size_t len = strlen(hex_digest);
00676 digest = malloc(len/2);
00677 if(!digest)
00678 return 0;
00679
00680 for(i = 0; i < len; i += 2) {
00681 digest[i/2] = hex_to_uint(hex_digest+i);
00682 }
00683 chksum = malloc(sizeof(metalink_checksum));
00684 if(chksum) {
00685 chksum->digest_def = digest_def;
00686 chksum->digest = digest;
00687 }
00688 return chksum;
00689 }
00690
00691 static metalink_resource *new_metalink_resource(const char *url)
00692 {
00693 metalink_resource *res;
00694 res = malloc(sizeof(metalink_resource));
00695 if(res) {
00696 res->next = NULL;
00697 res->url = strdup(url);
00698 if(!res->url) {
00699 free(res);
00700 return NULL;
00701 }
00702 }
00703 return res;
00704 }
00705
00706
00707
00708
00709 static int check_hex_digest(const char *hex_digest,
00710 const metalink_digest_def *digest_def)
00711 {
00712 size_t i;
00713 for(i = 0; hex_digest[i]; ++i) {
00714 char c = hex_digest[i];
00715 if(!(('0' <= c && c <= '9') || ('a' <= c && c <= 'z') ||
00716 ('A' <= c && c <= 'Z'))) {
00717 return 0;
00718 }
00719 }
00720 return digest_def->dparams->digest_resultlen * 2 == i;
00721 }
00722
00723 static metalinkfile *new_metalinkfile(metalink_file_t *fileinfo)
00724 {
00725 metalinkfile *f;
00726 f = (metalinkfile*)malloc(sizeof(metalinkfile));
00727 if(!f)
00728 return NULL;
00729
00730 f->next = NULL;
00731 f->filename = strdup(fileinfo->name);
00732 if(!f->filename) {
00733 free(f);
00734 return NULL;
00735 }
00736 f->checksum = NULL;
00737 f->resource = NULL;
00738 if(fileinfo->checksums) {
00739 const metalink_digest_alias *digest_alias;
00740 for(digest_alias = digest_aliases; digest_alias->alias_name;
00741 ++digest_alias) {
00742 metalink_checksum_t **p;
00743 for(p = fileinfo->checksums; *p; ++p) {
00744 if(curl_strequal(digest_alias->alias_name, (*p)->type) &&
00745 check_hex_digest((*p)->hash, digest_alias->digest_def)) {
00746 f->checksum =
00747 new_metalink_checksum_from_hex_digest(digest_alias->digest_def,
00748 (*p)->hash);
00749 break;
00750 }
00751 }
00752 if(f->checksum) {
00753 break;
00754 }
00755 }
00756 }
00757 if(fileinfo->resources) {
00758 metalink_resource_t **p;
00759 metalink_resource root, *tail;
00760 root.next = NULL;
00761 tail = &root;
00762 for(p = fileinfo->resources; *p; ++p) {
00763 metalink_resource *res;
00764
00765
00766
00767
00768
00769
00770
00771
00772
00773 if((*p)->type == NULL ||
00774 curl_strequal((*p)->type, "http") ||
00775 curl_strequal((*p)->type, "https") ||
00776 curl_strequal((*p)->type, "ftp") ||
00777 curl_strequal((*p)->type, "ftps")) {
00778 res = new_metalink_resource((*p)->url);
00779 tail->next = res;
00780 tail = res;
00781 }
00782 }
00783 f->resource = root.next;
00784 }
00785 return f;
00786 }
00787
00788 int parse_metalink(struct OperationConfig *config, struct OutStruct *outs,
00789 const char *metalink_url)
00790 {
00791 metalink_error_t r;
00792 metalink_t* metalink;
00793 metalink_file_t **files;
00794 bool warnings = FALSE;
00795
00796
00797 r = metalink_parse_final(outs->metalink_parser, NULL, 0, &metalink);
00798 outs->metalink_parser = NULL;
00799 if(r != 0) {
00800 return -1;
00801 }
00802 if(metalink->files == NULL) {
00803 fprintf(config->global->errors, "Metalink: parsing (%s) WARNING "
00804 "(missing or invalid file name)\n",
00805 metalink_url);
00806 metalink_delete(metalink);
00807 return -1;
00808 }
00809 for(files = metalink->files; *files; ++files) {
00810 struct getout *url;
00811
00812 if(!(*files)->resources) {
00813 fprintf(config->global->errors, "Metalink: parsing (%s) WARNING "
00814 "(missing or invalid resource)\n",
00815 metalink_url, (*files)->name);
00816 continue;
00817 }
00818 if(config->url_get ||
00819 ((config->url_get = config->url_list) != NULL)) {
00820
00821
00822 while(config->url_get && (config->url_get->flags & GETOUT_URL))
00823 config->url_get = config->url_get->next;
00824 }
00825
00826
00827
00828 if(config->url_get)
00829
00830 url = config->url_get;
00831 else
00832
00833 url = new_getout(config);
00834
00835 if(url) {
00836 metalinkfile *mlfile = new_metalinkfile(*files);
00837 if(!mlfile)
00838 break;
00839
00840 if(!mlfile->checksum) {
00841 warnings = TRUE;
00842 fprintf(config->global->errors,
00843 "Metalink: parsing (%s) WARNING (digest missing)\n",
00844 metalink_url);
00845 }
00846
00847 GetStr(&url->url, mlfile->filename);
00848
00849
00850 url->flags |= GETOUT_URL | GETOUT_METALINK;
00851
00852 if(config->metalinkfile_list) {
00853 config->metalinkfile_last->next = mlfile;
00854 config->metalinkfile_last = mlfile;
00855 }
00856 else {
00857 config->metalinkfile_list = config->metalinkfile_last = mlfile;
00858 }
00859 }
00860 }
00861 metalink_delete(metalink);
00862 return (warnings) ? -2 : 0;
00863 }
00864
00865 size_t metalink_write_cb(void *buffer, size_t sz, size_t nmemb,
00866 void *userdata)
00867 {
00868 struct OutStruct *outs = userdata;
00869 struct OperationConfig *config = outs->config;
00870 int rv;
00871
00872
00873
00874
00875
00876
00877
00878 const size_t failure = (sz * nmemb) ? 0 : 1;
00879
00880 if(!config)
00881 return failure;
00882
00883 rv = metalink_parse_update(outs->metalink_parser, buffer, sz *nmemb);
00884 if(rv == 0)
00885 return sz * nmemb;
00886 else {
00887 fprintf(config->global->errors, "Metalink: parsing FAILED\n");
00888 return failure;
00889 }
00890 }
00891
00892
00893
00894
00895 static int check_content_type(const char *content_type, const char *media_type)
00896 {
00897 const char *ptr = content_type;
00898 size_t media_type_len = strlen(media_type);
00899 for(; *ptr && (*ptr == ' ' || *ptr == '\t'); ++ptr);
00900 if(!*ptr) {
00901 return 0;
00902 }
00903 return curl_strnequal(ptr, media_type, media_type_len) &&
00904 (*(ptr+media_type_len) == '\0' || *(ptr+media_type_len) == ' ' ||
00905 *(ptr+media_type_len) == '\t' || *(ptr+media_type_len) == ';');
00906 }
00907
00908 int check_metalink_content_type(const char *content_type)
00909 {
00910 return check_content_type(content_type, "application/metalink+xml");
00911 }
00912
00913 int count_next_metalink_resource(metalinkfile *mlfile)
00914 {
00915 int count = 0;
00916 metalink_resource *res;
00917 for(res = mlfile->resource; res; res = res->next, ++count);
00918 return count;
00919 }
00920
00921 static void delete_metalink_checksum(metalink_checksum *chksum)
00922 {
00923 if(chksum == NULL) {
00924 return;
00925 }
00926 Curl_safefree(chksum->digest);
00927 Curl_safefree(chksum);
00928 }
00929
00930 static void delete_metalink_resource(metalink_resource *res)
00931 {
00932 if(res == NULL) {
00933 return;
00934 }
00935 Curl_safefree(res->url);
00936 Curl_safefree(res);
00937 }
00938
00939 static void delete_metalinkfile(metalinkfile *mlfile)
00940 {
00941 metalink_resource *res;
00942 if(mlfile == NULL) {
00943 return;
00944 }
00945 Curl_safefree(mlfile->filename);
00946 delete_metalink_checksum(mlfile->checksum);
00947 for(res = mlfile->resource; res;) {
00948 metalink_resource *next;
00949 next = res->next;
00950 delete_metalink_resource(res);
00951 res = next;
00952 }
00953 Curl_safefree(mlfile);
00954 }
00955
00956 void clean_metalink(struct OperationConfig *config)
00957 {
00958 while(config->metalinkfile_list) {
00959 metalinkfile *mlfile = config->metalinkfile_list;
00960 config->metalinkfile_list = config->metalinkfile_list->next;
00961 delete_metalinkfile(mlfile);
00962 }
00963 config->metalinkfile_last = 0;
00964 }
00965
00966 void metalink_cleanup(void)
00967 {
00968 #ifdef USE_NSS
00969 if(nss_context) {
00970 NSS_ShutdownContext(nss_context);
00971 nss_context = NULL;
00972 }
00973 #endif
00974 }
00975
00976 #endif