tool: Moved --stderr to the global config
[platform/upstream/curl.git] / src / tool_metalink.c
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 */
75 struct 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
121 static int MD5_Init(MD5_CTX *ctx)
122 {
123   md5_init(ctx);
124   return 1;
125 }
126
127 static void MD5_Update(MD5_CTX *ctx,
128                        const unsigned char *input,
129                        unsigned int inputLen)
130 {
131   md5_update(ctx, inputLen, input);
132 }
133
134 static void MD5_Final(unsigned char digest[16], MD5_CTX *ctx)
135 {
136   md5_digest(ctx, 16, digest);
137 }
138
139 static int SHA1_Init(SHA_CTX *ctx)
140 {
141   sha1_init(ctx);
142   return 1;
143 }
144
145 static void SHA1_Update(SHA_CTX *ctx,
146                         const unsigned char *input,
147                         unsigned int inputLen)
148 {
149   sha1_update(ctx, inputLen, input);
150 }
151
152 static void SHA1_Final(unsigned char digest[20], SHA_CTX *ctx)
153 {
154   sha1_digest(ctx, 20, digest);
155 }
156
157 static int SHA256_Init(SHA256_CTX *ctx)
158 {
159   sha256_init(ctx);
160   return 1;
161 }
162
163 static void SHA256_Update(SHA256_CTX *ctx,
164                           const unsigned char *input,
165                           unsigned int inputLen)
166 {
167   sha256_update(ctx, inputLen, input);
168 }
169
170 static 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
177 static int MD5_Init(MD5_CTX *ctx)
178 {
179   gcry_md_open(ctx, GCRY_MD_MD5, 0);
180   return 1;
181 }
182
183 static 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
190 static 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
196 static int SHA1_Init(SHA_CTX *ctx)
197 {
198   gcry_md_open(ctx, GCRY_MD_SHA1, 0);
199   return 1;
200 }
201
202 static 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
209 static 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
215 static int SHA256_Init(SHA256_CTX *ctx)
216 {
217   gcry_md_open(ctx, GCRY_MD_SHA256, 0);
218   return 1;
219 }
220
221 static 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
228 static 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
236 static 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
262 static 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
270 static int MD5_Init(MD5_CTX *pctx)
271 {
272   return nss_hash_init(pctx, SEC_OID_MD5);
273 }
274
275 static 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
282 static void MD5_Final(unsigned char digest[16], MD5_CTX *pctx)
283 {
284   nss_hash_final(pctx, digest, 16);
285 }
286
287 static int SHA1_Init(SHA_CTX *pctx)
288 {
289   return nss_hash_init(pctx, SEC_OID_SHA1);
290 }
291
292 static 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
299 static void SHA1_Final(unsigned char digest[20], SHA_CTX *pctx)
300 {
301   nss_hash_final(pctx, digest, 20);
302 }
303
304 static int SHA256_Init(SHA256_CTX *pctx)
305 {
306   return nss_hash_init(pctx, SEC_OID_SHA256);
307 }
308
309 static 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
316 static 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
323 static 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
337 static 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
346 static 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
353 static void MD5_Final(unsigned char digest[16], MD5_CTX *ctx)
354 {
355   win32_crypto_final(ctx, digest, 16);
356 }
357
358 static 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
367 static 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
374 static void SHA1_Final(unsigned char digest[20], SHA_CTX *ctx)
375 {
376   win32_crypto_final(ctx, digest, 20);
377 }
378
379 static 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
388 static 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
395 static 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
402 const 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
412 const 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
422 const 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
432 static const metalink_digest_def SHA256_DIGEST_DEF[] = {
433   {"sha-256", SHA256_DIGEST_PARAMS}
434 };
435
436 static const metalink_digest_def SHA1_DIGEST_DEF[] = {
437   {"sha-1", SHA1_DIGEST_PARAMS}
438 };
439
440 static 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  */
451 static 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
460 digest_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
487 int 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
496 int 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
506 static 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  */
536 static 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
597 int 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
613 static 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
630 static 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. */
642 static 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
656 static 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
714 int 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
789 size_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  */
819 static 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
832 int check_metalink_content_type(const char *content_type)
833 {
834   return check_content_type(content_type, "application/metalink+xml");
835 }
836
837 int 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
845 static 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
854 static 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
863 static 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
880 void 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
890 void 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 */