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