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