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