be5fc26c46d8a395bd5fc54ba7305c55384947bd
[platform/upstream/curl.git] / src / tool_metalink.c
1 /***************************************************************************
2  *                                  _   _ ____  _
3  *  Project                     ___| | | |  _ \| |
4  *                             / __| | | | |_) | |
5  *                            | (__| |_| |  _ <| |___
6  *                             \___|\___/|_| \_\_____|
7  *
8  * Copyright (C) 1998 - 2012, 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_SSLEAY
33 #  ifdef USE_OPENSSL
34 #    include <openssl/md5.h>
35 #    include <openssl/sha.h>
36 #  else
37 #    include <md5.h>
38 #    include <sha.h>
39 #  endif
40 #elif defined(USE_GNUTLS_NETTLE)
41 #  include <nettle/md5.h>
42 #  include <nettle/sha.h>
43 #  define MD5_CTX    struct md5_ctx
44 #  define SHA_CTX    struct sha1_ctx
45 #  define SHA256_CTX struct sha256_ctx
46 #elif defined(USE_GNUTLS)
47 #  include <gcrypt.h>
48 #  define MD5_CTX    gcry_md_hd_t
49 #  define SHA_CTX    gcry_md_hd_t
50 #  define SHA256_CTX gcry_md_hd_t
51 #elif defined(USE_NSS)
52 #  include <nss.h>
53 #  include <pk11pub.h>
54 #  define MD5_CTX    void *
55 #  define SHA_CTX    void *
56 #  define SHA256_CTX void *
57 #  ifdef HAVE_NSS_INITCONTEXT
58      static NSSInitContext *nss_context;
59 #  endif
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 #ifdef HAVE_NSS_INITCONTEXT
244   if(!NSS_IsInitialized() && !nss_context) {
245     static NSSInitParameters params;
246     params.length = sizeof params;
247     nss_context = NSS_InitContext("", "", "", "", &params, NSS_INIT_READONLY
248         | NSS_INIT_NOCERTDB   | NSS_INIT_NOMODDB       | NSS_INIT_FORCEOPEN
249         | NSS_INIT_NOROOTINIT | NSS_INIT_OPTIMIZESPACE | NSS_INIT_PK11RELOAD);
250   }
251 #endif
252
253   ctx = PK11_CreateDigestContext(hash_alg);
254   if(!ctx)
255     return /* failure */ 0;
256
257   if(PK11_DigestBegin(ctx) != SECSuccess) {
258     PK11_DestroyContext(ctx, PR_TRUE);
259     return /* failure */ 0;
260   }
261
262   *pctx = ctx;
263   return /* success */ 1;
264 }
265
266 static void nss_hash_final(void **pctx, unsigned char *out, unsigned int len)
267 {
268   PK11Context *ctx = *pctx;
269   unsigned int outlen;
270   PK11_DigestFinal(ctx, out, &outlen, len);
271   PK11_DestroyContext(ctx, PR_TRUE);
272 }
273
274 static int MD5_Init(MD5_CTX *pctx)
275 {
276   return nss_hash_init(pctx, SEC_OID_MD5);
277 }
278
279 static void MD5_Update(MD5_CTX *pctx,
280                        const unsigned char *input,
281                        unsigned int input_len)
282 {
283   PK11_DigestOp(*pctx, input, input_len);
284 }
285
286 static void MD5_Final(unsigned char digest[16], MD5_CTX *pctx)
287 {
288   nss_hash_final(pctx, digest, 16);
289 }
290
291 static int SHA1_Init(SHA_CTX *pctx)
292 {
293   return nss_hash_init(pctx, SEC_OID_SHA1);
294 }
295
296 static void SHA1_Update(SHA_CTX *pctx,
297                         const unsigned char *input,
298                         unsigned int input_len)
299 {
300   PK11_DigestOp(*pctx, input, input_len);
301 }
302
303 static void SHA1_Final(unsigned char digest[20], SHA_CTX *pctx)
304 {
305   nss_hash_final(pctx, digest, 20);
306 }
307
308 static int SHA256_Init(SHA256_CTX *pctx)
309 {
310   return nss_hash_init(pctx, SEC_OID_SHA256);
311 }
312
313 static void SHA256_Update(SHA256_CTX *pctx,
314                           const unsigned char *input,
315                           unsigned int input_len)
316 {
317   PK11_DigestOp(*pctx, input, input_len);
318 }
319
320 static void SHA256_Final(unsigned char digest[32], SHA256_CTX *pctx)
321 {
322   nss_hash_final(pctx, digest, 32);
323 }
324
325 #elif defined(_WIN32) && !defined(USE_SSLEAY)
326
327 static void win32_crypto_final(struct win32_crypto_hash *ctx,
328                                unsigned char *digest,
329                                unsigned int digestLen)
330 {
331   unsigned long length;
332   CryptGetHashParam(ctx->hHash, HP_HASHVAL, NULL, &length, 0);
333   if(length == digestLen)
334     CryptGetHashParam(ctx->hHash, HP_HASHVAL, digest, &length, 0);
335   if(ctx->hHash)
336     CryptDestroyHash(ctx->hHash);
337   if(ctx->hCryptProv)
338     CryptReleaseContext(ctx->hCryptProv, 0);
339 }
340
341 static int MD5_Init(MD5_CTX *ctx)
342 {
343   if(CryptAcquireContext(&ctx->hCryptProv, NULL, NULL,
344                          PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) {
345     CryptCreateHash(ctx->hCryptProv, CALG_MD5, 0, 0, &ctx->hHash);
346   }
347   return 1;
348 }
349
350 static void MD5_Update(MD5_CTX *ctx,
351                        const unsigned char *input,
352                        unsigned int inputLen)
353 {
354   CryptHashData(ctx->hHash, (unsigned char *)input, inputLen, 0);
355 }
356
357 static void MD5_Final(unsigned char digest[16], MD5_CTX *ctx)
358 {
359   win32_crypto_final(ctx, digest, 16);
360 }
361
362 static int SHA1_Init(SHA_CTX *ctx)
363 {
364   if(CryptAcquireContext(&ctx->hCryptProv, NULL, NULL,
365                          PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) {
366     CryptCreateHash(ctx->hCryptProv, CALG_SHA1, 0, 0, &ctx->hHash);
367   }
368   return 1;
369 }
370
371 static void SHA1_Update(SHA_CTX *ctx,
372                         const unsigned char *input,
373                         unsigned int inputLen)
374 {
375   CryptHashData(ctx->hHash, (unsigned char *)input, inputLen, 0);
376 }
377
378 static void SHA1_Final(unsigned char digest[20], SHA_CTX *ctx)
379 {
380   win32_crypto_final(ctx, digest, 20);
381 }
382
383 static int SHA256_Init(SHA256_CTX *ctx)
384 {
385   if(CryptAcquireContext(&ctx->hCryptProv, NULL, NULL,
386                          PROV_RSA_AES, CRYPT_VERIFYCONTEXT)) {
387     CryptCreateHash(ctx->hCryptProv, CALG_SHA_256, 0, 0, &ctx->hHash);
388   }
389   return 1;
390 }
391
392 static void SHA256_Update(SHA256_CTX *ctx,
393                           const unsigned char *input,
394                           unsigned int inputLen)
395 {
396   CryptHashData(ctx->hHash, (unsigned char *)input, inputLen, 0);
397 }
398
399 static void SHA256_Final(unsigned char digest[32], SHA256_CTX *ctx)
400 {
401   win32_crypto_final(ctx, digest, 32);
402 }
403
404 #endif /* CRYPTO LIBS */
405
406 const digest_params MD5_DIGEST_PARAMS[] = {
407   {
408     (Curl_digest_init_func) MD5_Init,
409     (Curl_digest_update_func) MD5_Update,
410     (Curl_digest_final_func) MD5_Final,
411     sizeof(MD5_CTX),
412     16
413   }
414 };
415
416 const digest_params SHA1_DIGEST_PARAMS[] = {
417   {
418     (Curl_digest_init_func) SHA1_Init,
419     (Curl_digest_update_func) SHA1_Update,
420     (Curl_digest_final_func) SHA1_Final,
421     sizeof(SHA_CTX),
422     20
423   }
424 };
425
426 const digest_params SHA256_DIGEST_PARAMS[] = {
427   {
428     (Curl_digest_init_func) SHA256_Init,
429     (Curl_digest_update_func) SHA256_Update,
430     (Curl_digest_final_func) SHA256_Final,
431     sizeof(SHA256_CTX),
432     32
433   }
434 };
435
436 static const metalink_digest_def SHA256_DIGEST_DEF[] = {
437   {"sha-256", SHA256_DIGEST_PARAMS}
438 };
439
440 static const metalink_digest_def SHA1_DIGEST_DEF[] = {
441   {"sha-1", SHA1_DIGEST_PARAMS}
442 };
443
444 static const metalink_digest_def MD5_DIGEST_DEF[] = {
445   {"md5", MD5_DIGEST_PARAMS}
446 };
447
448 /*
449  * The alias of supported hash functions in the order by preference
450  * (basically stronger hash comes first). We included "sha-256" and
451  * "sha256". The former is the name defined in the IANA registry named
452  * "Hash Function Textual Names". The latter is widely (and
453  * historically) used in Metalink version 3.
454  */
455 static const metalink_digest_alias digest_aliases[] = {
456   {"sha-256", SHA256_DIGEST_DEF},
457   {"sha256", SHA256_DIGEST_DEF},
458   {"sha-1", SHA1_DIGEST_DEF},
459   {"sha1", SHA1_DIGEST_DEF},
460   {"md5", MD5_DIGEST_DEF},
461   {NULL, NULL}
462 };
463
464 digest_context *Curl_digest_init(const digest_params *dparams)
465 {
466   digest_context *ctxt;
467
468   /* Create digest context */
469   ctxt = malloc(sizeof *ctxt);
470
471   if(!ctxt)
472     return ctxt;
473
474   ctxt->digest_hashctx = malloc(dparams->digest_ctxtsize);
475
476   if(!ctxt->digest_hashctx) {
477     free(ctxt);
478     return NULL;
479   }
480
481   ctxt->digest_hash = dparams;
482
483   if(dparams->digest_init(ctxt->digest_hashctx) != 1) {
484     free(ctxt);
485     return NULL;
486   }
487
488   return ctxt;
489 }
490
491 int Curl_digest_update(digest_context *context,
492                        const unsigned char *data,
493                        unsigned int len)
494 {
495   (*context->digest_hash->digest_update)(context->digest_hashctx, data, len);
496
497   return 0;
498 }
499
500 int Curl_digest_final(digest_context *context, unsigned char *result)
501 {
502   (*context->digest_hash->digest_final)(result, context->digest_hashctx);
503
504   free(context->digest_hashctx);
505   free(context);
506
507   return 0;
508 }
509
510 static unsigned char hex_to_uint(const char *s)
511 {
512   int v[2];
513   int i;
514   for(i = 0; i < 2; ++i) {
515     v[i] = Curl_raw_toupper(s[i]);
516     if('0' <= v[i] && v[i] <= '9') {
517       v[i] -= '0';
518     }
519     else if('A' <= v[i] && v[i] <= 'Z') {
520       v[i] -= 'A'-10;
521     }
522   }
523   return (unsigned char)((v[0] << 4) | v[1]);
524 }
525
526 /*
527  * Check checksum of file denoted by filename. The expected hash value
528  * is given in hex_hash which is hex-encoded string.
529  *
530  * This function returns 1 if it succeeds or one of the following
531  * integers:
532  *
533  * 0:
534  *   Checksum didn't match.
535  * -1:
536  *   Could not open file; or could not read data from file.
537  * -2:
538  *   Hash algorithm not available.
539  */
540 static int check_hash(const char *filename,
541                       const metalink_digest_def *digest_def,
542                       const unsigned char *digest, FILE *error)
543 {
544   unsigned char *result;
545   digest_context *dctx;
546   int check_ok, flags, fd;
547
548   flags = O_RDONLY;
549 #ifdef O_BINARY
550   /* O_BINARY is required in order to avoid binary EOF in text mode */
551   flags |= O_BINARY;
552 #endif
553
554   fd = open(filename, flags);
555   if(fd == -1) {
556     fprintf(error, "Metalink: validating (%s) [%s] FAILED (%s)\n", filename,
557             digest_def->hash_name, strerror(errno));
558     return -1;
559   }
560
561   dctx = Curl_digest_init(digest_def->dparams);
562   if(!dctx) {
563     fprintf(error, "Metalink: validating (%s) [%s] FAILED (%s)\n", filename,
564             digest_def->hash_name, "failed to initialize hash algorithm");
565     close(fd);
566     return -2;
567   }
568
569   result = malloc(digest_def->dparams->digest_resultlen);
570   while(1) {
571     unsigned char buf[4096];
572     ssize_t len = read(fd, buf, sizeof(buf));
573     if(len == 0) {
574       break;
575     }
576     else if(len == -1) {
577       fprintf(error, "Metalink: validating (%s) [%s] FAILED (%s)\n", filename,
578               digest_def->hash_name, strerror(errno));
579       Curl_digest_final(dctx, result);
580       close(fd);
581       return -1;
582     }
583     Curl_digest_update(dctx, buf, (unsigned int)len);
584   }
585   Curl_digest_final(dctx, result);
586   check_ok = memcmp(result, digest,
587                     digest_def->dparams->digest_resultlen) == 0;
588   /* sha*sum style verdict output */
589   if(check_ok)
590     fprintf(error, "Metalink: validating (%s) [%s] OK\n", filename,
591             digest_def->hash_name);
592   else
593     fprintf(error, "Metalink: validating (%s) [%s] FAILED (digest mismatch)\n",
594             filename, digest_def->hash_name);
595
596   free(result);
597   close(fd);
598   return check_ok;
599 }
600
601 int metalink_check_hash(struct Configurable *config,
602                         metalinkfile *mlfile,
603                         const char *filename)
604 {
605   int rv;
606   fprintf(config->errors, "Metalink: validating (%s)...\n", filename);
607   if(mlfile->checksum == NULL) {
608     fprintf(config->errors,
609             "Metalink: validating (%s) FAILED (digest missing)\n",
610             filename);
611     return -2;
612   }
613   rv = check_hash(filename, mlfile->checksum->digest_def,
614                   mlfile->checksum->digest, config->errors);
615   return rv;
616 }
617
618 static metalink_checksum *new_metalink_checksum_from_hex_digest
619 (const metalink_digest_def *digest_def, const char *hex_digest)
620 {
621   metalink_checksum *chksum;
622   unsigned char *digest;
623   size_t i;
624   size_t len = strlen(hex_digest);
625   digest = malloc(len/2);
626   for(i = 0; i < len; i += 2) {
627     digest[i/2] = hex_to_uint(hex_digest+i);
628   }
629   chksum = malloc(sizeof(metalink_checksum));
630   chksum->digest_def = digest_def;
631   chksum->digest = digest;
632   return chksum;
633 }
634
635 static metalink_resource *new_metalink_resource(const char *url)
636 {
637   metalink_resource *res;
638   res = malloc(sizeof(metalink_resource));
639   res->next = NULL;
640   res->url = strdup(url);
641   return res;
642 }
643
644 /* Returns nonzero if hex_digest is properly formatted; that is each
645    letter is in [0-9A-Za-z] and the length of the string equals to the
646    result length of digest * 2. */
647 static int check_hex_digest(const char *hex_digest,
648                             const metalink_digest_def *digest_def)
649 {
650   size_t i;
651   for(i = 0; hex_digest[i]; ++i) {
652     char c = hex_digest[i];
653     if(!(('0' <= c && c <= '9') || ('a' <= c && c <= 'z') ||
654          ('A' <= c && c <= 'Z'))) {
655       return 0;
656     }
657   }
658   return digest_def->dparams->digest_resultlen * 2 == i;
659 }
660
661 static metalinkfile *new_metalinkfile(metalink_file_t *fileinfo)
662 {
663   metalinkfile *f;
664   f = (metalinkfile*)malloc(sizeof(metalinkfile));
665   f->next = NULL;
666   f->filename = strdup(fileinfo->name);
667   f->checksum = NULL;
668   f->resource = NULL;
669   if(fileinfo->checksums) {
670     const metalink_digest_alias *digest_alias;
671     for(digest_alias = digest_aliases; digest_alias->alias_name;
672         ++digest_alias) {
673       metalink_checksum_t **p;
674       for(p = fileinfo->checksums; *p; ++p) {
675         if(Curl_raw_equal(digest_alias->alias_name, (*p)->type) &&
676            check_hex_digest((*p)->hash, digest_alias->digest_def)) {
677           f->checksum =
678             new_metalink_checksum_from_hex_digest(digest_alias->digest_def,
679                                                   (*p)->hash);
680           break;
681         }
682       }
683       if(f->checksum) {
684         break;
685       }
686     }
687   }
688   if(fileinfo->resources) {
689     metalink_resource_t **p;
690     metalink_resource root, *tail;
691     root.next = NULL;
692     tail = &root;
693     for(p = fileinfo->resources; *p; ++p) {
694       metalink_resource *res;
695       /* Filter by type if it is non-NULL. In Metalink v3, type
696          includes the type of the resource. In curl, we are only
697          interested in HTTP, HTTPS and FTP. In addition to them,
698          Metalink v3 file may contain bittorrent type URL, which
699          points to the BitTorrent metainfo file. We ignore it here.
700          In Metalink v4, type was deprecated and all
701          fileinfo->resources point to the target file. BitTorrent
702          metainfo file URL may be appeared in fileinfo->metaurls.
703       */
704       if((*p)->type == NULL ||
705          Curl_raw_equal((*p)->type, "http") ||
706          Curl_raw_equal((*p)->type, "https") ||
707          Curl_raw_equal((*p)->type, "ftp") ||
708          Curl_raw_equal((*p)->type, "ftps")) {
709         res = new_metalink_resource((*p)->url);
710         tail->next = res;
711         tail = res;
712       }
713     }
714     f->resource = root.next;
715   }
716   return f;
717 }
718
719 int parse_metalink(struct Configurable *config, struct OutStruct *outs,
720                    const char *metalink_url)
721 {
722   metalink_error_t r;
723   metalink_t* metalink;
724   metalink_file_t **files;
725   bool warnings = FALSE;
726
727   /* metlaink_parse_final deletes outs->metalink_parser */
728   r = metalink_parse_final(outs->metalink_parser, NULL, 0, &metalink);
729   outs->metalink_parser = NULL;
730   if(r != 0) {
731     return -1;
732   }
733   if(metalink->files == NULL) {
734     fprintf(config->errors, "Metalink: parsing (%s) WARNING "
735             "(missing or invalid file name)\n",
736             metalink_url);
737     metalink_delete(metalink);
738     return -1;
739   }
740   for(files = metalink->files; *files; ++files) {
741     struct getout *url;
742     /* Skip an entry which has no resource. */
743     if(!(*files)->resources) {
744       fprintf(config->errors, "Metalink: parsing (%s) WARNING "
745               "(missing or invalid resource)\n",
746               metalink_url, (*files)->name);
747       continue;
748     }
749     if(config->url_get ||
750        ((config->url_get = config->url_list) != NULL)) {
751       /* there's a node here, if it already is filled-in continue to
752          find an "empty" node */
753       while(config->url_get && (config->url_get->flags & GETOUT_URL))
754         config->url_get = config->url_get->next;
755     }
756
757     /* now there might or might not be an available node to fill in! */
758
759     if(config->url_get)
760       /* existing node */
761       url = config->url_get;
762     else
763       /* there was no free node, create one! */
764       url = new_getout(config);
765
766     if(url) {
767       metalinkfile *mlfile;
768       mlfile = new_metalinkfile(*files);
769       if(!mlfile->checksum) {
770         warnings = TRUE;
771         fprintf(config->errors, "Metalink: parsing (%s) WARNING "
772                 "(digest missing)\n",
773                 metalink_url);
774       }
775       /* Set name as url */
776       GetStr(&url->url, mlfile->filename);
777
778       /* set flag metalink here */
779       url->flags |= GETOUT_URL | GETOUT_METALINK;
780
781       if(config->metalinkfile_list) {
782         config->metalinkfile_last->next = mlfile;
783         config->metalinkfile_last = mlfile;
784       }
785       else {
786         config->metalinkfile_list = config->metalinkfile_last = mlfile;
787       }
788     }
789   }
790   metalink_delete(metalink);
791   return (warnings) ? -2 : 0;
792 }
793
794 size_t metalink_write_cb(void *buffer, size_t sz, size_t nmemb,
795                          void *userdata)
796 {
797   struct OutStruct *outs = userdata;
798   struct Configurable *config = outs->config;
799   int rv;
800
801   /*
802    * Once that libcurl has called back tool_write_cb() the returned value
803    * is checked against the amount that was intended to be written, if
804    * it does not match then it fails with CURLE_WRITE_ERROR. So at this
805    * point returning a value different from sz*nmemb indicates failure.
806    */
807   const size_t failure = (sz * nmemb) ? 0 : 1;
808
809   if(!config)
810     return failure;
811
812   rv = metalink_parse_update(outs->metalink_parser, buffer, sz *nmemb);
813   if(rv == 0)
814     return sz * nmemb;
815   else {
816     fprintf(config->errors, "Metalink: parsing FAILED\n");
817     return failure;
818   }
819 }
820
821 /*
822  * Returns nonzero if content_type includes mediatype.
823  */
824 static int check_content_type(const char *content_type, const char *media_type)
825 {
826   const char *ptr = content_type;
827   size_t media_type_len = strlen(media_type);
828   for(; *ptr && (*ptr == ' ' || *ptr == '\t'); ++ptr);
829   if(!*ptr) {
830     return 0;
831   }
832   return Curl_raw_nequal(ptr, media_type, media_type_len) &&
833     (*(ptr+media_type_len) == '\0' || *(ptr+media_type_len) == ' ' ||
834      *(ptr+media_type_len) == '\t' || *(ptr+media_type_len) == ';');
835 }
836
837 int check_metalink_content_type(const char *content_type)
838 {
839   return check_content_type(content_type, "application/metalink+xml");
840 }
841
842 int count_next_metalink_resource(metalinkfile *mlfile)
843 {
844   int count = 0;
845   metalink_resource *res;
846   for(res = mlfile->resource; res; res = res->next, ++count);
847   return count;
848 }
849
850 static void delete_metalink_checksum(metalink_checksum *chksum)
851 {
852   if(chksum == NULL) {
853     return;
854   }
855   Curl_safefree(chksum->digest);
856   Curl_safefree(chksum);
857 }
858
859 static void delete_metalink_resource(metalink_resource *res)
860 {
861   if(res == NULL) {
862     return;
863   }
864   Curl_safefree(res->url);
865   Curl_safefree(res);
866 }
867
868 static void delete_metalinkfile(metalinkfile *mlfile)
869 {
870   metalink_resource *res;
871   if(mlfile == NULL) {
872     return;
873   }
874   Curl_safefree(mlfile->filename);
875   delete_metalink_checksum(mlfile->checksum);
876   for(res = mlfile->resource; res;) {
877     metalink_resource *next;
878     next = res->next;
879     delete_metalink_resource(res);
880     res = next;
881   }
882   Curl_safefree(mlfile);
883 }
884
885 void clean_metalink(struct Configurable *config)
886 {
887   while(config->metalinkfile_list) {
888     metalinkfile *mlfile = config->metalinkfile_list;
889     config->metalinkfile_list = config->metalinkfile_list->next;
890     delete_metalinkfile(mlfile);
891   }
892   config->metalinkfile_last = 0;
893 }
894
895 void metalink_cleanup(void)
896 {
897 #if defined(USE_NSS) && defined(HAVE_NSS_INITCONTEXT)
898   if(nss_context) {
899     NSS_ShutdownContext(nss_context);
900     nss_context = NULL;
901   }
902 #endif
903 }
904
905 #endif /* USE_METALINK */