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